From a49e513bc2e772905da1a2c3a7e56ce96abb8a11 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 26 Jun 2014 13:04:11 -0400 Subject: get more exact hls segment times --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 54 ++++++---------------- 1 file changed, 14 insertions(+), 40 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 5ee119e13..1087c905c 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -1,5 +1,3 @@ -using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.IO; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; @@ -11,7 +9,6 @@ using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; @@ -27,11 +24,6 @@ namespace MediaBrowser.MediaEncoding.Encoder /// private readonly ILogger _logger; - /// - /// The _app paths - /// - private readonly IApplicationPaths _appPaths; - /// /// Gets the json serializer. /// @@ -53,23 +45,17 @@ namespace MediaBrowser.MediaEncoding.Encoder /// 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) + public MediaEncoder(ILogger logger, IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, string version) { _logger = logger; - _appPaths = appPaths; _jsonSerializer = jsonSerializer; Version = version; - _fileSystem = fileSystem; FFProbePath = ffProbePath; FFMpegPath = ffMpegPath; } @@ -263,30 +249,6 @@ namespace MediaBrowser.MediaEncoding.Encoder ((Process)sender).Dispose(); } - private const int FastSeekOffsetSeconds = 1; - - 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; - } - public Task ExtractAudioImage(string path, CancellationToken cancellationToken) { return ExtractImage(new[] { path }, MediaProtocol.File, true, null, null, cancellationToken); @@ -368,7 +330,7 @@ namespace MediaBrowser.MediaEncoding.Encoder if (offset.HasValue) { - args = string.Format("-ss {0} ", Convert.ToInt32(offset.Value.TotalSeconds)).ToString(UsCulture) + args; + args = string.Format("-ss {0} ", GetTimeParameter(offset.Value)) + args; } var process = new Process @@ -463,5 +425,17 @@ namespace MediaBrowser.MediaEncoding.Encoder _videoImageResourcePool.Dispose(); } } + + public string GetTimeParameter(long ticks) + { + var time = TimeSpan.FromTicks(ticks); + + return GetTimeParameter(time); + } + + public string GetTimeParameter(TimeSpan time) + { + return time.ToString(@"hh\:mm\:ss\.fff", UsCulture); + } } } -- cgit v1.2.3 From 933443c2b948d43e4ec41d7f8c11fd6ab3a0ab7e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 29 Jun 2014 13:35:05 -0400 Subject: added modular configuration --- MediaBrowser.Api/ConfigurationService.cs | 38 ++++++++- MediaBrowser.Api/Dlna/DlnaServerService.cs | 9 +- MediaBrowser.Api/MediaBrowser.Api.csproj | 1 + .../BaseApplicationHost.cs | 1 + .../Configuration/BaseConfigurationManager.cs | 91 ++++++++++++++++++-- .../Configuration/ConfigurationUpdateEventArgs.cs | 18 ++++ .../Configuration/IConfigurationFactory.cs | 17 ++++ .../Configuration/IConfigurationManager.cs | 43 +++++++++- MediaBrowser.Common/MediaBrowser.Common.csproj | 2 + MediaBrowser.Common/Net/MimeTypes.cs | 5 ++ .../Chapters/IChapterManager.cs | 7 ++ .../MediaEncoding/IMediaEncoder.cs | 21 +++++ MediaBrowser.Dlna/ConfigurationExtension.cs | 29 +++++++ .../ContentDirectory/ContentDirectory.cs | 6 +- MediaBrowser.Dlna/Main/DlnaEntryPoint.cs | 22 +++-- MediaBrowser.Dlna/MediaBrowser.Dlna.csproj | 1 + MediaBrowser.Dlna/PlayTo/PlayToManager.cs | 6 +- MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs | 6 +- MediaBrowser.Dlna/Service/BaseControlHandler.cs | 2 +- MediaBrowser.Dlna/Ssdp/SsdpHandler.cs | 30 ++++--- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 99 ++++++++++++++++++++-- .../Subtitles/SubtitleEncoder.cs | 11 ++- .../MediaBrowser.Model.Portable.csproj | 9 ++ .../MediaBrowser.Model.net35.csproj | 9 ++ MediaBrowser.Model/Configuration/ChannelOptions.cs | 18 ++++ MediaBrowser.Model/Configuration/ChapterOptions.cs | 27 ++++++ .../Configuration/ServerConfiguration.cs | 61 ++----------- .../Configuration/SubtitlePlaybackMode.cs | 10 +++ .../Configuration/UserConfiguration.cs | 8 -- MediaBrowser.Model/MediaBrowser.Model.csproj | 3 + MediaBrowser.Providers/Chapters/ChapterManager.cs | 32 ++++++- .../MediaInfo/FFProbeVideoInfo.cs | 6 +- .../MediaEncoder/EncodingManager.cs | 14 +-- MediaBrowser.ServerApplication/ApplicationHost.cs | 27 +++++- 34 files changed, 563 insertions(+), 126 deletions(-) create mode 100644 MediaBrowser.Common/Configuration/ConfigurationUpdateEventArgs.cs create mode 100644 MediaBrowser.Common/Configuration/IConfigurationFactory.cs create mode 100644 MediaBrowser.Dlna/ConfigurationExtension.cs create mode 100644 MediaBrowser.Model/Configuration/ChannelOptions.cs create mode 100644 MediaBrowser.Model/Configuration/ChapterOptions.cs create mode 100644 MediaBrowser.Model/Configuration/SubtitlePlaybackMode.cs (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.Api/ConfigurationService.cs b/MediaBrowser.Api/ConfigurationService.cs index b3191cd4b..39fcc50d8 100644 --- a/MediaBrowser.Api/ConfigurationService.cs +++ b/MediaBrowser.Api/ConfigurationService.cs @@ -8,8 +8,11 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Serialization; using ServiceStack; +using ServiceStack.Text.Controller; +using ServiceStack.Web; using System; using System.Collections.Generic; +using System.IO; using System.Linq; namespace MediaBrowser.Api @@ -23,6 +26,13 @@ namespace MediaBrowser.Api } + [Route("/System/Configuration/{Key}", "GET", Summary = "Gets a named configuration")] + public class GetNamedConfiguration + { + [ApiMember(Name = "Key", Description = "Key", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public string Key { get; set; } + } + /// /// Class UpdateConfiguration /// @@ -31,6 +41,15 @@ namespace MediaBrowser.Api { } + [Route("/System/Configuration/{Key}", "POST", Summary = "Updates named configuration")] + public class UpdateNamedConfiguration : IReturnVoid, IRequiresRequestStream + { + [ApiMember(Name = "Key", Description = "Key", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public string Key { get; set; } + + public Stream RequestStream { get; set; } + } + [Route("/System/Configuration/MetadataOptions/Default", "GET", Summary = "Gets a default MetadataOptions object")] public class GetDefaultMetadataOptions : IReturn { @@ -88,6 +107,13 @@ namespace MediaBrowser.Api return ToOptimizedResultUsingCache(cacheKey, dateModified, null, () => _configurationManager.Configuration); } + public object Get(GetNamedConfiguration request) + { + var result = _configurationManager.GetConfiguration(request.Key); + + return ToOptimizedResult(result); + } + /// /// Posts the specified configuraiton. /// @@ -95,7 +121,6 @@ namespace MediaBrowser.Api public void Post(UpdateConfiguration request) { // Silly, but we need to serialize and deserialize or the XmlSerializer will write the xml with an element name of UpdateConfiguration - var json = _jsonSerializer.SerializeToString(request); var config = _jsonSerializer.DeserializeFromString(json); @@ -103,6 +128,17 @@ namespace MediaBrowser.Api _configurationManager.ReplaceConfiguration(config); } + public void Post(UpdateNamedConfiguration request) + { + var pathInfo = PathInfo.Parse(Request.PathInfo); + var key = pathInfo.GetArgumentValue(2); + + var configurationType = _configurationManager.GetConfigurationType(key); + var configuration = _jsonSerializer.DeserializeFromStream(request.RequestStream, configurationType); + + _configurationManager.SaveConfiguration(key, configuration); + } + public object Get(GetDefaultMetadataOptions request) { return ToOptimizedSerializedResultUsingCache(new MetadataOptions()); diff --git a/MediaBrowser.Api/Dlna/DlnaServerService.cs b/MediaBrowser.Api/Dlna/DlnaServerService.cs index 28de8ee17..82bd394f0 100644 --- a/MediaBrowser.Api/Dlna/DlnaServerService.cs +++ b/MediaBrowser.Api/Dlna/DlnaServerService.cs @@ -1,4 +1,6 @@ -using MediaBrowser.Controller.Dlna; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Dlna; +using MediaBrowser.Model.Configuration; using ServiceStack; using ServiceStack.Text.Controller; using ServiceStack.Web; @@ -76,11 +78,14 @@ namespace MediaBrowser.Api.Dlna private readonly IContentDirectory _contentDirectory; private readonly IConnectionManager _connectionManager; - public DlnaServerService(IDlnaManager dlnaManager, IContentDirectory contentDirectory, IConnectionManager connectionManager) + private readonly IConfigurationManager _config; + + public DlnaServerService(IDlnaManager dlnaManager, IContentDirectory contentDirectory, IConnectionManager connectionManager, IConfigurationManager config) { _dlnaManager = dlnaManager; _contentDirectory = contentDirectory; _connectionManager = connectionManager; + _config = config; } public object Get(GetDescriptionXml request) diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index 1e9ff9199..3f1d9fe67 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -101,6 +101,7 @@ + diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs index 7bd0ca748..ebd6c6b59 100644 --- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs +++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs @@ -342,6 +342,7 @@ namespace MediaBrowser.Common.Implementations /// protected virtual void FindParts() { + ConfigurationManager.AddParts(GetExports()); Plugins = GetExports(); } diff --git a/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs b/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs index 8c4840ea7..60abc14f1 100644 --- a/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs +++ b/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs @@ -1,10 +1,13 @@ -using System.IO; -using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Events; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; using System.Threading; namespace MediaBrowser.Common.Implementations.Configuration @@ -25,6 +28,11 @@ namespace MediaBrowser.Common.Implementations.Configuration /// public event EventHandler ConfigurationUpdated; + /// + /// Occurs when [named configuration updated]. + /// + public event EventHandler NamedConfigurationUpdated; + /// /// Gets the logger. /// @@ -74,6 +82,9 @@ namespace MediaBrowser.Common.Implementations.Configuration } } + private ConfigurationStore[] _configurationStores = {}; + private IConfigurationFactory[] _configurationFactories; + /// /// Initializes a new instance of the class. /// @@ -89,10 +100,14 @@ namespace MediaBrowser.Common.Implementations.Configuration UpdateCachePath(); } - /// - /// The _save lock - /// - private readonly object _configurationSaveLock = new object(); + public void AddParts(IEnumerable factories) + { + _configurationFactories = factories.ToArray(); + + _configurationStores = _configurationFactories + .SelectMany(i => i.GetConfigurations()) + .ToArray(); + } /// /// Saves the configuration. @@ -103,7 +118,7 @@ namespace MediaBrowser.Common.Implementations.Configuration Directory.CreateDirectory(Path.GetDirectoryName(path)); - lock (_configurationSaveLock) + lock (_configurationSyncLock) { XmlSerializer.SerializeToFile(CommonConfiguration, path); } @@ -144,8 +159,8 @@ namespace MediaBrowser.Common.Implementations.Configuration /// private void UpdateCachePath() { - ((BaseApplicationPaths)CommonApplicationPaths).CachePath = string.IsNullOrEmpty(CommonConfiguration.CachePath) ? - null : + ((BaseApplicationPaths)CommonApplicationPaths).CachePath = string.IsNullOrEmpty(CommonConfiguration.CachePath) ? + null : CommonConfiguration.CachePath; } @@ -168,5 +183,63 @@ namespace MediaBrowser.Common.Implementations.Configuration } } } + + private readonly ConcurrentDictionary _configurations = new ConcurrentDictionary(); + + private string GetConfigurationFile(string key) + { + return Path.Combine(CommonApplicationPaths.ConfigurationDirectoryPath, key.ToLower() + ".xml"); + } + + public object GetConfiguration(string key) + { + return _configurations.GetOrAdd(key, k => + { + var file = GetConfigurationFile(key); + + var configurationType = _configurationStores + .First(i => string.Equals(i.Key, key, StringComparison.OrdinalIgnoreCase)) + .ConfigurationType; + + lock (_configurationSyncLock) + { + return ConfigurationHelper.GetXmlConfiguration(configurationType, file, XmlSerializer); + } + }); + } + + public void SaveConfiguration(string key, object configuration) + { + var configurationType = GetConfigurationType(key); + + if (configuration.GetType() != configurationType) + { + throw new ArgumentException("Expected configuration type is " + configurationType.Name); + } + + _configurations.AddOrUpdate(key, configuration, (k, v) => configuration); + + var path = GetConfigurationFile(key); + Directory.CreateDirectory(Path.GetDirectoryName(path)); + + lock (_configurationSyncLock) + { + XmlSerializer.SerializeToFile(configuration, path); + } + + EventHelper.FireEventIfNotNull(NamedConfigurationUpdated, this, new ConfigurationUpdateEventArgs + { + Key = key, + NewConfiguration = configuration + + }, Logger); + } + + public Type GetConfigurationType(string key) + { + return _configurationStores + .First(i => string.Equals(i.Key, key, StringComparison.OrdinalIgnoreCase)) + .ConfigurationType; + } } } diff --git a/MediaBrowser.Common/Configuration/ConfigurationUpdateEventArgs.cs b/MediaBrowser.Common/Configuration/ConfigurationUpdateEventArgs.cs new file mode 100644 index 000000000..310e2aa63 --- /dev/null +++ b/MediaBrowser.Common/Configuration/ConfigurationUpdateEventArgs.cs @@ -0,0 +1,18 @@ +using System; + +namespace MediaBrowser.Common.Configuration +{ + public class ConfigurationUpdateEventArgs : EventArgs + { + /// + /// Gets or sets the key. + /// + /// The key. + public string Key { get; set; } + /// + /// Gets or sets the new configuration. + /// + /// The new configuration. + public object NewConfiguration { get; set; } + } +} diff --git a/MediaBrowser.Common/Configuration/IConfigurationFactory.cs b/MediaBrowser.Common/Configuration/IConfigurationFactory.cs new file mode 100644 index 000000000..d418d0a42 --- /dev/null +++ b/MediaBrowser.Common/Configuration/IConfigurationFactory.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; + +namespace MediaBrowser.Common.Configuration +{ + public interface IConfigurationFactory + { + IEnumerable GetConfigurations(); + } + + public class ConfigurationStore + { + public string Key { get; set; } + + public Type ConfigurationType { get; set; } + } +} diff --git a/MediaBrowser.Common/Configuration/IConfigurationManager.cs b/MediaBrowser.Common/Configuration/IConfigurationManager.cs index 0d0759b66..25698d972 100644 --- a/MediaBrowser.Common/Configuration/IConfigurationManager.cs +++ b/MediaBrowser.Common/Configuration/IConfigurationManager.cs @@ -1,5 +1,6 @@ using MediaBrowser.Model.Configuration; using System; +using System.Collections.Generic; namespace MediaBrowser.Common.Configuration { @@ -9,7 +10,12 @@ namespace MediaBrowser.Common.Configuration /// Occurs when [configuration updated]. /// event EventHandler ConfigurationUpdated; - + + /// + /// Occurs when [named configuration updated]. + /// + event EventHandler NamedConfigurationUpdated; + /// /// Gets or sets the application paths. /// @@ -32,5 +38,40 @@ namespace MediaBrowser.Common.Configuration /// /// The new configuration. void ReplaceConfiguration(BaseApplicationConfiguration newConfiguration); + + /// + /// Gets the configuration. + /// + /// The key. + /// System.Object. + object GetConfiguration(string key); + + /// + /// Gets the type of the configuration. + /// + /// The key. + /// Type. + Type GetConfigurationType(string key); + + /// + /// Saves the configuration. + /// + /// The key. + /// The configuration. + void SaveConfiguration(string key, object configuration); + + /// + /// Adds the parts. + /// + /// The factories. + void AddParts(IEnumerable factories); + } + + public static class ConfigurationManagerExtensions + { + public static T GetConfiguration(this IConfigurationManager manager, string key) + { + return (T)manager.GetConfiguration(key); + } } } diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 2e7db5c35..9d5984317 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -55,7 +55,9 @@ Properties\SharedVersion.cs + + diff --git a/MediaBrowser.Common/Net/MimeTypes.cs b/MediaBrowser.Common/Net/MimeTypes.cs index d85a2fd1e..0cc4fc6b4 100644 --- a/MediaBrowser.Common/Net/MimeTypes.cs +++ b/MediaBrowser.Common/Net/MimeTypes.cs @@ -228,6 +228,11 @@ namespace MediaBrowser.Common.Net return "text/vtt"; } + if (ext.Equals(".bif", StringComparison.OrdinalIgnoreCase)) + { + return "application/octet-stream"; + } + throw new ArgumentException("Argument not supported: " + path); } } diff --git a/MediaBrowser.Controller/Chapters/IChapterManager.cs b/MediaBrowser.Controller/Chapters/IChapterManager.cs index b8f29d1ce..676ef9c56 100644 --- a/MediaBrowser.Controller/Chapters/IChapterManager.cs +++ b/MediaBrowser.Controller/Chapters/IChapterManager.cs @@ -3,6 +3,7 @@ using MediaBrowser.Model.Chapters; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; namespace MediaBrowser.Controller.Chapters @@ -70,5 +71,11 @@ namespace MediaBrowser.Controller.Chapters /// /// IEnumerable{ChapterProviderInfo}. IEnumerable GetProviders(); + + /// + /// Gets the configuration. + /// + /// ChapterOptions. + ChapterOptions GetConfiguration(); } } diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 9468fd987..38c2c83c4 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -43,6 +43,27 @@ namespace MediaBrowser.Controller.MediaEncoding /// Task{Stream}. Task ExtractVideoImage(string[] inputFiles, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken); + /// + /// Extracts the video images on interval. + /// + /// The input files. + /// The protocol. + /// The threed format. + /// The interval. + /// The target directory. + /// The filename prefix. + /// The maximum width. + /// The cancellation token. + /// Task. + Task ExtractVideoImagesOnInterval(string[] inputFiles, + MediaProtocol protocol, + Video3DFormat? threedFormat, + TimeSpan interval, + string targetDirectory, + string filenamePrefix, + int? maxWidth, + CancellationToken cancellationToken); + /// /// Gets the media info. /// diff --git a/MediaBrowser.Dlna/ConfigurationExtension.cs b/MediaBrowser.Dlna/ConfigurationExtension.cs new file mode 100644 index 000000000..821e21ccf --- /dev/null +++ b/MediaBrowser.Dlna/ConfigurationExtension.cs @@ -0,0 +1,29 @@ +using MediaBrowser.Common.Configuration; +using MediaBrowser.Model.Configuration; +using System.Collections.Generic; + +namespace MediaBrowser.Dlna +{ + public static class ConfigurationExtension + { + public static DlnaOptions GetDlnaConfiguration(this IConfigurationManager manager) + { + return manager.GetConfiguration("dlna"); + } + } + + public class DlnaConfigurationFactory : IConfigurationFactory + { + public IEnumerable GetConfigurations() + { + return new List + { + new ConfigurationStore + { + Key = "dlna", + ConfigurationType = typeof (DlnaOptions) + } + }; + } + } +} diff --git a/MediaBrowser.Dlna/ContentDirectory/ContentDirectory.cs b/MediaBrowser.Dlna/ContentDirectory/ContentDirectory.cs index bb65f422c..f594b4471 100644 --- a/MediaBrowser.Dlna/ContentDirectory/ContentDirectory.cs +++ b/MediaBrowser.Dlna/ContentDirectory/ContentDirectory.cs @@ -89,9 +89,11 @@ namespace MediaBrowser.Dlna.ContentDirectory } } - if (!string.IsNullOrEmpty(_config.Configuration.DlnaOptions.DefaultUserId)) + var userId = _config.GetDlnaConfiguration().DefaultUserId; + + if (!string.IsNullOrEmpty(userId)) { - var user = _userManager.GetUserById(new Guid(_config.Configuration.DlnaOptions.DefaultUserId)); + var user = _userManager.GetUserById(new Guid(userId)); if (user != null) { diff --git a/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs b/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs index 048525588..5f2c1c49a 100644 --- a/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs +++ b/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; @@ -58,34 +59,39 @@ namespace MediaBrowser.Dlna.Main StartSsdpHandler(); ReloadComponents(); - _config.ConfigurationUpdated += ConfigurationUpdated; + _config.NamedConfigurationUpdated += _config_NamedConfigurationUpdated; } - void ConfigurationUpdated(object sender, EventArgs e) + void _config_NamedConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e) { - ReloadComponents(); + if (string.Equals(e.Key, "dlna", StringComparison.OrdinalIgnoreCase)) + { + ReloadComponents(); + } } private void ReloadComponents() { var isServerStarted = _dlnaServerStarted; - if (_config.Configuration.DlnaOptions.EnableServer && !isServerStarted) + var options = _config.GetDlnaConfiguration(); + + if (options.EnableServer && !isServerStarted) { StartDlnaServer(); } - else if (!_config.Configuration.DlnaOptions.EnableServer && isServerStarted) + else if (!options.EnableServer && isServerStarted) { DisposeDlnaServer(); } var isPlayToStarted = _manager != null; - if (_config.Configuration.DlnaOptions.EnablePlayTo && !isPlayToStarted) + if (options.EnablePlayTo && !isPlayToStarted) { StartPlayToManager(); } - else if (!_config.Configuration.DlnaOptions.EnablePlayTo && isPlayToStarted) + else if (!options.EnablePlayTo && isPlayToStarted) { DisposePlayToManager(); } diff --git a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj index 10da21e52..1d51fc60f 100644 --- a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj +++ b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj @@ -51,6 +51,7 @@ Properties\SharedVersion.cs + diff --git a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs index 095c6a893..1f8c33ee7 100644 --- a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs +++ b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs @@ -181,7 +181,7 @@ namespace MediaBrowser.Dlna.PlayTo return; } - if (_config.Configuration.DlnaOptions.EnableDebugLogging) + if (_config.GetDlnaConfiguration().EnableDebugLogging) { var headerTexts = args.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)); var headerText = string.Join(",", headerTexts.ToArray()); @@ -220,7 +220,7 @@ namespace MediaBrowser.Dlna.PlayTo { _ssdpHandler.SendRendererSearchMessage(new IPEndPoint(localIp, 1900)); - var delay = _config.Configuration.DlnaOptions.ClientDiscoveryIntervalSeconds * 1000; + var delay = _config.GetDlnaConfiguration().ClientDiscoveryIntervalSeconds * 1000; await Task.Delay(delay, _tokenSource.Token).ConfigureAwait(false); } @@ -250,7 +250,7 @@ namespace MediaBrowser.Dlna.PlayTo { socket.SendTo(request, new IPEndPoint(IPAddress.Parse("239.255.255.250"), 1900)); - var delay = _config.Configuration.DlnaOptions.ClientDiscoveryIntervalSeconds * 1000; + var delay = _config.GetDlnaConfiguration().ClientDiscoveryIntervalSeconds * 1000; await Task.Delay(delay).ConfigureAwait(false); } diff --git a/MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs b/MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs index 22d4797a3..ccc7d46e6 100644 --- a/MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs +++ b/MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs @@ -58,7 +58,7 @@ namespace MediaBrowser.Dlna.PlayTo { Url = url, UserAgent = USERAGENT, - LogRequest = _config.Configuration.DlnaOptions.EnableDebugLogging, + LogRequest = _config.GetDlnaConfiguration().EnableDebugLogging, LogErrorResponseBody = true }; @@ -76,7 +76,7 @@ namespace MediaBrowser.Dlna.PlayTo { Url = url, UserAgent = USERAGENT, - LogRequest = _config.Configuration.DlnaOptions.EnableDebugLogging, + LogRequest = _config.GetDlnaConfiguration().EnableDebugLogging, LogErrorResponseBody = true }; @@ -103,7 +103,7 @@ namespace MediaBrowser.Dlna.PlayTo { Url = url, UserAgent = USERAGENT, - LogRequest = _config.Configuration.DlnaOptions.EnableDebugLogging, + LogRequest = _config.GetDlnaConfiguration().EnableDebugLogging, LogErrorResponseBody = true }; diff --git a/MediaBrowser.Dlna/Service/BaseControlHandler.cs b/MediaBrowser.Dlna/Service/BaseControlHandler.cs index 9f7e87088..c2af1f5a1 100644 --- a/MediaBrowser.Dlna/Service/BaseControlHandler.cs +++ b/MediaBrowser.Dlna/Service/BaseControlHandler.cs @@ -28,7 +28,7 @@ namespace MediaBrowser.Dlna.Service { try { - if (Config.Configuration.DlnaOptions.EnableDebugLogging) + if (Config.GetDlnaConfiguration().EnableDebugLogging) { LogRequest(request); } diff --git a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs index 0fc7c579b..0455dd674 100644 --- a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs +++ b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs @@ -1,4 +1,4 @@ -using System.Text; +using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Events; using MediaBrowser.Controller.Configuration; using MediaBrowser.Dlna.Server; @@ -9,6 +9,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; +using System.Text; using System.Threading; namespace MediaBrowser.Dlna.Ssdp @@ -42,12 +43,15 @@ namespace MediaBrowser.Dlna.Ssdp _config = config; _serverSignature = serverSignature; - _config.ConfigurationUpdated += _config_ConfigurationUpdated; + _config.NamedConfigurationUpdated += _config_ConfigurationUpdated; } - void _config_ConfigurationUpdated(object sender, EventArgs e) + void _config_ConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e) { - ReloadAliveNotifier(); + if (string.Equals(e.Key, "dlna", StringComparison.OrdinalIgnoreCase)) + { + ReloadAliveNotifier(); + } } public event EventHandler MessageReceived; @@ -142,7 +146,7 @@ namespace MediaBrowser.Dlna.Ssdp private void RespondToSearch(IPEndPoint endpoint, string deviceType) { - if (_config.Configuration.DlnaOptions.EnableDebugLogging) + if (_config.GetDlnaConfiguration().EnableDebugLogging) { _logger.Debug("RespondToSearch"); } @@ -166,7 +170,7 @@ namespace MediaBrowser.Dlna.Ssdp SendDatagram(header, values, endpoint, null); - if (_config.Configuration.DlnaOptions.EnableDebugLogging) + if (_config.GetDlnaConfiguration().EnableDebugLogging) { _logger.Debug("{1} - Responded to a {0} request to {2}", d.Type, endpoint, d.Address.ToString()); } @@ -255,14 +259,14 @@ namespace MediaBrowser.Dlna.Ssdp var received = (byte[])result.AsyncState; - if (_config.Configuration.DlnaOptions.EnableDebugLogging) + if (_config.GetDlnaConfiguration().EnableDebugLogging) { _logger.Debug(Encoding.ASCII.GetString(received)); } var args = SsdpHelper.ParseSsdpResponse(received, (IPEndPoint)endpoint); - if (_config.Configuration.DlnaOptions.EnableDebugLogging) + if (_config.GetDlnaConfiguration().EnableDebugLogging) { var headerTexts = args.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)); var headerText = string.Join(",", headerTexts.ToArray()); @@ -285,7 +289,7 @@ namespace MediaBrowser.Dlna.Ssdp public void Dispose() { - _config.ConfigurationUpdated -= _config_ConfigurationUpdated; + _config.NamedConfigurationUpdated -= _config_ConfigurationUpdated; _isDisposed = true; while (_messageQueue.Count != 0) @@ -337,7 +341,7 @@ namespace MediaBrowser.Dlna.Ssdp private void NotifyAll() { - if (_config.Configuration.DlnaOptions.EnableDebugLogging) + if (_config.GetDlnaConfiguration().EnableDebugLogging) { _logger.Debug("Sending alive notifications"); } @@ -362,7 +366,7 @@ namespace MediaBrowser.Dlna.Ssdp values["NT"] = dev.Type; values["USN"] = dev.USN; - if (_config.Configuration.DlnaOptions.EnableDebugLogging) + if (_config.GetDlnaConfiguration().EnableDebugLogging) { _logger.Debug("{0} said {1}", dev.USN, type); } @@ -406,13 +410,13 @@ namespace MediaBrowser.Dlna.Ssdp private int _aliveNotifierIntervalMs; private void ReloadAliveNotifier() { - if (!_config.Configuration.DlnaOptions.BlastAliveMessages) + if (!_config.GetDlnaConfiguration().BlastAliveMessages) { DisposeNotificationTimer(); return; } - var intervalMs = _config.Configuration.DlnaOptions.BlastAliveMessageIntervalSeconds * 1000; + var intervalMs = _config.GetDlnaConfiguration().BlastAliveMessageIntervalSeconds * 1000; if (_notificationTimer == null || _aliveNotifierIntervalMs != intervalMs) { diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 1087c905c..ce761ff9c 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -152,7 +152,7 @@ namespace MediaBrowser.MediaEncoding.Encoder RedirectStandardError = true, FileName = FFProbePath, Arguments = string.Format(args, - probeSizeArgument, inputPath).Trim(), + probeSizeArgument, inputPath).Trim(), WindowStyle = ProcessWindowStyle.Hidden, ErrorDialog = false @@ -186,8 +186,7 @@ namespace MediaBrowser.MediaEncoding.Encoder { process.BeginErrorReadLine(); - result = - _jsonSerializer.DeserializeFromStream(process.StandardOutput.BaseStream); + result = _jsonSerializer.DeserializeFromStream(process.StandardOutput.BaseStream); } catch { @@ -292,7 +291,6 @@ namespace MediaBrowser.MediaEncoding.Encoder // 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) { @@ -344,7 +342,8 @@ namespace MediaBrowser.MediaEncoding.Encoder WindowStyle = ProcessWindowStyle.Hidden, ErrorDialog = false, RedirectStandardOutput = true, - RedirectStandardError = true + RedirectStandardError = true, + RedirectStandardInput = true } }; @@ -370,7 +369,7 @@ namespace MediaBrowser.MediaEncoding.Encoder { _logger.Info("Killing ffmpeg process"); - process.Kill(); + process.StandardInput.WriteLine("q"); process.WaitForExit(1000); } @@ -437,5 +436,93 @@ namespace MediaBrowser.MediaEncoding.Encoder { return time.ToString(@"hh\:mm\:ss\.fff", UsCulture); } + + public async Task ExtractVideoImagesOnInterval(string[] inputFiles, + MediaProtocol protocol, + Video3DFormat? threedFormat, + TimeSpan interval, + string targetDirectory, + string filenamePrefix, + int? maxWidth, + CancellationToken cancellationToken) + { + var resourcePool = _videoImageResourcePool; + + var inputArgument = GetInputArgument(inputFiles, protocol); + + var vf = "fps=fps=1/" + interval.TotalSeconds.ToString(UsCulture); + + if (maxWidth.HasValue) + { + var maxWidthParam = maxWidth.Value.ToString(UsCulture); + + vf += string.Format(",scale=min(iw\\,{0}):trunc(ow/dar/2)*2", maxWidthParam); + } + + Directory.CreateDirectory(targetDirectory); + var outputPath = Path.Combine(targetDirectory, filenamePrefix + "%05d.jpg"); + + var args = string.Format("-i {0} -threads 0 -v quiet -vf \"{2}\" -f image2 \"{1}\"", inputArgument, outputPath, vf); + + var probeSize = GetProbeSizeArgument(new[] { inputArgument }, protocol); + + if (!string.IsNullOrEmpty(probeSize)) + { + args = probeSize + " " + args; + } + + var process = new Process + { + StartInfo = new ProcessStartInfo + { + CreateNoWindow = true, + UseShellExecute = false, + FileName = FFMpegPath, + Arguments = args, + WindowStyle = ProcessWindowStyle.Hidden, + ErrorDialog = false, + RedirectStandardInput = true + } + }; + + _logger.Info(process.StartInfo.FileName + " " + process.StartInfo.Arguments); + + await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); + + process.Start(); + + var ranToCompletion = process.WaitForExit(120000); + + if (!ranToCompletion) + { + try + { + _logger.Info("Killing ffmpeg process"); + + process.StandardInput.WriteLine("q"); + + 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) + { + var msg = string.Format("ffmpeg image extraction failed for {0}", inputArgument); + + _logger.Error(msg); + + throw new ApplicationException(msg); + } + } } } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 154541316..ab9cd546a 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -342,12 +342,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles { RedirectStandardOutput = false, RedirectStandardError = true, + RedirectStandardInput = true, CreateNoWindow = true, UseShellExecute = false, FileName = _mediaEncoder.EncoderPath, - Arguments = - string.Format("{0} -i \"{1}\" -c:s ass \"{2}\"", encodingParam, inputPath, outputPath), + Arguments = string.Format("{0} -i \"{1}\" -c:s ass \"{2}\"", encodingParam, inputPath, outputPath), WindowStyle = ProcessWindowStyle.Hidden, ErrorDialog = false @@ -385,8 +385,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { _logger.Info("Killing ffmpeg subtitle conversion process"); - process.Kill(); - + process.StandardInput.WriteLine("q"); process.WaitForExit(1000); await logTask.ConfigureAwait(false); @@ -520,6 +519,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles RedirectStandardOutput = false, RedirectStandardError = true, + RedirectStandardInput = true, FileName = _mediaEncoder.EncoderPath, Arguments = processArgs, @@ -559,8 +559,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { _logger.Info("Killing ffmpeg subtitle extraction process"); - process.Kill(); - + process.StandardInput.WriteLine("q"); process.WaitForExit(1000); } catch (Exception ex) diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index ee6f05cc1..3c34652c3 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -104,6 +104,12 @@ Configuration\BaseApplicationConfiguration.cs + + Configuration\ChannelOptions.cs + + + Configuration\ChapterOptions.cs + Configuration\DlnaOptions.cs @@ -152,6 +158,9 @@ Configuration\SubtitleOptions.cs + + Configuration\SubtitlePlaybackMode.cs + Configuration\TvFileOrganizationOptions.cs diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index a2fa1aa94..9e3df382e 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -91,6 +91,12 @@ Configuration\BaseApplicationConfiguration.cs + + Configuration\ChannelOptions.cs + + + Configuration\ChapterOptions.cs + Configuration\DlnaOptions.cs @@ -139,6 +145,9 @@ Configuration\SubtitleOptions.cs + + Configuration\SubtitlePlaybackMode.cs + Configuration\TvFileOrganizationOptions.cs diff --git a/MediaBrowser.Model/Configuration/ChannelOptions.cs b/MediaBrowser.Model/Configuration/ChannelOptions.cs new file mode 100644 index 000000000..f0fc4d47c --- /dev/null +++ b/MediaBrowser.Model/Configuration/ChannelOptions.cs @@ -0,0 +1,18 @@ +namespace MediaBrowser.Model.Configuration +{ + public class ChannelOptions + { + public int? PreferredStreamingWidth { get; set; } + + public string DownloadPath { get; set; } + public int? MaxDownloadAge { get; set; } + + public string[] DownloadingChannels { get; set; } + + public ChannelOptions() + { + DownloadingChannels = new string[] { }; + MaxDownloadAge = 30; + } + } +} \ No newline at end of file diff --git a/MediaBrowser.Model/Configuration/ChapterOptions.cs b/MediaBrowser.Model/Configuration/ChapterOptions.cs new file mode 100644 index 000000000..8a059a0a4 --- /dev/null +++ b/MediaBrowser.Model/Configuration/ChapterOptions.cs @@ -0,0 +1,27 @@ +namespace MediaBrowser.Model.Configuration +{ + public class ChapterOptions + { + public bool EnableMovieChapterImageExtraction { get; set; } + public bool EnableEpisodeChapterImageExtraction { get; set; } + public bool EnableOtherVideoChapterImageExtraction { get; set; } + + public bool DownloadMovieChapters { get; set; } + public bool DownloadEpisodeChapters { get; set; } + + public string[] FetcherOrder { get; set; } + public string[] DisabledFetchers { get; set; } + + public ChapterOptions() + { + EnableMovieChapterImageExtraction = true; + EnableEpisodeChapterImageExtraction = false; + EnableOtherVideoChapterImageExtraction = false; + + DownloadMovieChapters = true; + + DisabledFetchers = new string[] { }; + FetcherOrder = new string[] { }; + } + } +} \ No newline at end of file diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 0d728ec75..3d5e0a9c9 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -211,6 +211,7 @@ namespace MediaBrowser.Model.Configuration public string UICulture { get; set; } + [Obsolete] public DlnaOptions DlnaOptions { get; set; } public double DownMixAudioBoost { get; set; } @@ -223,6 +224,8 @@ namespace MediaBrowser.Model.Configuration public string[] ManualLoginClients { get; set; } public ChannelOptions ChannelOptions { get; set; } + + [Obsolete] public ChapterOptions ChapterOptions { get; set; } /// @@ -268,73 +271,27 @@ namespace MediaBrowser.Model.Configuration SeasonZeroDisplayName = "Specials"; - LiveTvOptions = new LiveTvOptions(); - - TvFileOrganizationOptions = new TvFileOrganizationOptions(); - EnableRealtimeMonitor = true; - List options = new List + UICulture = "en-us"; + + MetadataOptions = new List { new MetadataOptions(1, 1280) {ItemType = "Book"}, new MetadataOptions(1, 1280) {ItemType = "MusicAlbum"}, new MetadataOptions(1, 1280) {ItemType = "MusicArtist"}, new MetadataOptions(0, 1280) {ItemType = "Season"} - }; - - MetadataOptions = options.ToArray(); - DlnaOptions = new DlnaOptions(); - - UICulture = "en-us"; + }.ToArray(); NotificationOptions = new NotificationOptions(); SubtitleOptions = new SubtitleOptions(); ChannelOptions = new ChannelOptions(); - ChapterOptions = new ChapterOptions(); - } - } - - public class ChannelOptions - { - public int? PreferredStreamingWidth { get; set; } - public string DownloadPath { get; set; } - public int? MaxDownloadAge { get; set; } - - public string[] DownloadingChannels { get; set; } - - public ChannelOptions() - { - DownloadingChannels = new string[] { }; - MaxDownloadAge = 30; - } - } - - public class ChapterOptions - { - public bool EnableMovieChapterImageExtraction { get; set; } - public bool EnableEpisodeChapterImageExtraction { get; set; } - public bool EnableOtherVideoChapterImageExtraction { get; set; } - - public bool DownloadMovieChapters { get; set; } - public bool DownloadEpisodeChapters { get; set; } - - public string[] FetcherOrder { get; set; } - public string[] DisabledFetchers { get; set; } - - public ChapterOptions() - { - EnableMovieChapterImageExtraction = true; - EnableEpisodeChapterImageExtraction = false; - EnableOtherVideoChapterImageExtraction = false; - - DownloadMovieChapters = true; - - DisabledFetchers = new string[] { }; - FetcherOrder = new string[] { }; + LiveTvOptions = new LiveTvOptions(); + TvFileOrganizationOptions = new TvFileOrganizationOptions(); } } } diff --git a/MediaBrowser.Model/Configuration/SubtitlePlaybackMode.cs b/MediaBrowser.Model/Configuration/SubtitlePlaybackMode.cs new file mode 100644 index 000000000..e6a3c3091 --- /dev/null +++ b/MediaBrowser.Model/Configuration/SubtitlePlaybackMode.cs @@ -0,0 +1,10 @@ +namespace MediaBrowser.Model.Configuration +{ + public enum SubtitlePlaybackMode + { + Default = 0, + Always = 1, + OnlyForced = 2, + None = 3 + } +} \ No newline at end of file diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs index 885172bed..94a41bdda 100644 --- a/MediaBrowser.Model/Configuration/UserConfiguration.cs +++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs @@ -91,12 +91,4 @@ namespace MediaBrowser.Model.Configuration ExcludeFoldersFromGrouping = new string[] { }; } } - - public enum SubtitlePlaybackMode - { - Default = 0, - Always = 1, - OnlyForced = 2, - None = 3 - } } diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 9efa63283..5d753f9c2 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -73,6 +73,9 @@ + + + diff --git a/MediaBrowser.Providers/Chapters/ChapterManager.cs b/MediaBrowser.Providers/Chapters/ChapterManager.cs index 5f8664bec..6e2cd77eb 100644 --- a/MediaBrowser.Providers/Chapters/ChapterManager.cs +++ b/MediaBrowser.Providers/Chapters/ChapterManager.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Chapters; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; @@ -8,6 +9,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Chapters; +using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using System; @@ -192,8 +194,10 @@ namespace MediaBrowser.Providers.Chapters if (!includeDisabledProviders) { + var options = GetConfiguration(); + providers = providers - .Where(i => !_config.Configuration.ChapterOptions.DisabledFetchers.Contains(i.Name)) + .Where(i => !options.DisabledFetchers.Contains(i.Name)) .ToArray(); } @@ -224,8 +228,10 @@ namespace MediaBrowser.Providers.Chapters private int GetConfiguredOrder(IChapterProvider provider) { + var options = GetConfiguration(); + // See if there's a user-defined order - var index = Array.IndexOf(_config.Configuration.ChapterOptions.FetcherOrder, provider.Name); + var index = Array.IndexOf(options.FetcherOrder, provider.Name); if (index != -1) { @@ -257,5 +263,25 @@ namespace MediaBrowser.Providers.Chapters { return _itemRepo.SaveChapters(new Guid(itemId), chapters, cancellationToken); } + + public ChapterOptions GetConfiguration() + { + return _config.GetConfiguration("chapters"); + } + } + + public class ChapterConfigurationStore : IConfigurationFactory + { + public IEnumerable GetConfigurations() + { + return new List + { + new ConfigurationStore + { + Key = "chapters", + ConfigurationType = typeof (ChapterOptions) + } + }; + } } } diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index 65faae327..92b4616e7 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -492,9 +492,11 @@ namespace MediaBrowser.Providers.MediaInfo private async Task> DownloadChapters(Video video, List currentChapters, CancellationToken cancellationToken) { - if ((_config.Configuration.ChapterOptions.DownloadEpisodeChapters && + var options = _chapterManager.GetConfiguration(); + + if ((options.DownloadEpisodeChapters && video is Episode) || - (_config.Configuration.ChapterOptions.DownloadMovieChapters && + (options.DownloadMovieChapters && video is Movie)) { var results = await _chapterManager.Search(video, cancellationToken).ConfigureAwait(false); diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs b/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs index 056a526f6..d35282e55 100644 --- a/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs +++ b/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs @@ -1,12 +1,15 @@ -using MediaBrowser.Common.IO; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.IO; using MediaBrowser.Controller.Chapters; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.MediaInfo; using System; using System.Collections.Generic; using System.Globalization; @@ -14,7 +17,6 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.Server.Implementations.MediaEncoder { @@ -61,23 +63,25 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder return false; } + var options = _chapterManager.GetConfiguration(); + if (video is Movie) { - if (!_config.Configuration.ChapterOptions.EnableMovieChapterImageExtraction) + if (!options.EnableMovieChapterImageExtraction) { return false; } } else if (video is Episode) { - if (!_config.Configuration.ChapterOptions.EnableEpisodeChapterImageExtraction) + if (!options.EnableEpisodeChapterImageExtraction) { return false; } } else { - if (!_config.Configuration.ChapterOptions.EnableOtherVideoChapterImageExtraction) + if (!options.EnableOtherVideoChapterImageExtraction) { return false; } diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index d03c5fe3d..8007e0506 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -41,6 +41,7 @@ using MediaBrowser.Dlna.Main; using MediaBrowser.MediaEncoding.BdInfo; using MediaBrowser.MediaEncoding.Encoder; using MediaBrowser.MediaEncoding.Subtitles; +using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.System; @@ -273,11 +274,35 @@ namespace MediaBrowser.ServerApplication public override Task Init(IProgress progress) { - DeleteDeprecatedModules(); + PerformVersionMigration(); return base.Init(progress); } + private void PerformVersionMigration() + { + DeleteDeprecatedModules(); + + MigrateModularConfigurations(); + } + + private void MigrateModularConfigurations() + { + if (ServerConfigurationManager.Configuration.DlnaOptions != null) + { + ServerConfigurationManager.SaveConfiguration("dlna", ServerConfigurationManager.Configuration.DlnaOptions); + ServerConfigurationManager.Configuration.DlnaOptions = null; + ServerConfigurationManager.SaveConfiguration(); + } + + if (ServerConfigurationManager.Configuration.ChapterOptions != null) + { + ServerConfigurationManager.SaveConfiguration("chapters", ServerConfigurationManager.Configuration.ChapterOptions); + ServerConfigurationManager.Configuration.ChapterOptions = null; + ServerConfigurationManager.SaveConfiguration(); + } + } + private void DeleteDeprecatedModules() { try -- cgit v1.2.3 From ca66390e2445c94c769d19d601c88fe2f79f901a Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 21 Aug 2014 22:24:38 -0400 Subject: 3.0.5346.38509 --- MediaBrowser.Api/ConfigurationService.cs | 33 +- MediaBrowser.Api/Library/LibraryService.cs | 2 +- MediaBrowser.Api/PlaylistService.cs | 15 +- .../Playlists/IPlaylistManager.cs | 3 +- MediaBrowser.Controller/Playlists/Playlist.cs | 22 +- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 16 - .../MediaBrowser.MediaEncoding.csproj | 3 +- MediaBrowser.MediaEncoding/Subtitles/AssParser.cs | 71 ++++ MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs | 400 ++++++++++++++++++--- .../Subtitles/SubtitleEncoder.cs | 7 +- MediaBrowser.Model/ApiClient/IApiClient.cs | 3 +- MediaBrowser.Model/Dto/BaseItemDto.cs | 8 +- .../Dto/DtoService.cs | 1 + .../Playlists/PlaylistManager.cs | 24 +- .../MediaEncoding/Subtitles/SsaParserTests.cs | 2 +- 15 files changed, 514 insertions(+), 96 deletions(-) create mode 100644 MediaBrowser.MediaEncoding/Subtitles/AssParser.cs (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.Api/ConfigurationService.cs b/MediaBrowser.Api/ConfigurationService.cs index 1e7f9d8b0..7b6e5ed19 100644 --- a/MediaBrowser.Api/ConfigurationService.cs +++ b/MediaBrowser.Api/ConfigurationService.cs @@ -141,22 +141,29 @@ namespace MediaBrowser.Api private string AutoDetectMetadataService() { - var paths = _libraryManager.GetDefaultVirtualFolders() - .SelectMany(i => i.Locations) - .Distinct(StringComparer.OrdinalIgnoreCase) - .Select(i => new DirectoryInfo(i)) - .ToList(); - - if (paths.SelectMany(i => i.EnumerateFiles("*.xml", SearchOption.AllDirectories)) - .Any()) + try { - return XbmcMetadata; + var paths = _libraryManager.GetDefaultVirtualFolders() + .SelectMany(i => i.Locations) + .Distinct(StringComparer.OrdinalIgnoreCase) + .Select(i => new DirectoryInfo(i)) + .ToList(); + + if (paths.SelectMany(i => i.EnumerateFiles("*.xml", SearchOption.AllDirectories)) + .Any()) + { + return XbmcMetadata; + } + + if (paths.SelectMany(i => i.EnumerateFiles("*.xml", SearchOption.AllDirectories)) + .Any(i => string.Equals(i.Name, "series.xml", StringComparison.OrdinalIgnoreCase) || string.Equals(i.Name, "movie.xml", StringComparison.OrdinalIgnoreCase))) + { + return MediaBrowserMetadata; + } } - - if (paths.SelectMany(i => i.EnumerateFiles("*.xml", SearchOption.AllDirectories)) - .Any(i => string.Equals(i.Name, "series.xml", StringComparison.OrdinalIgnoreCase) || string.Equals(i.Name, "movie.xml", StringComparison.OrdinalIgnoreCase))) + catch (Exception) { - return MediaBrowserMetadata; + } return XbmcMetadata; diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 10a3117a1..34b930a6a 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -286,7 +286,7 @@ namespace MediaBrowser.Api.Library public void Post(PostUpdatedSeries request) { - + Task.Run(() => _libraryManager.ValidateMediaLibrary(new Progress(), CancellationToken.None)); } public object Get(GetFile request) diff --git a/MediaBrowser.Api/PlaylistService.cs b/MediaBrowser.Api/PlaylistService.cs index 5cba348a5..5f4ced12e 100644 --- a/MediaBrowser.Api/PlaylistService.cs +++ b/MediaBrowser.Api/PlaylistService.cs @@ -36,6 +36,13 @@ namespace MediaBrowser.Api [ApiMember(Name = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] public string Id { get; set; } + + /// + /// Gets or sets the user id. + /// + /// The user id. + [ApiMember(Name = "UserId", Description = "User Id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string UserId { get; set; } } [Route("/Playlists/{Id}/Items", "DELETE", Summary = "Removes items from a playlist")] @@ -58,8 +65,8 @@ namespace MediaBrowser.Api /// Gets or sets the user id. /// /// The user id. - [ApiMember(Name = "UserId", Description = "User Id", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")] - public Guid? UserId { get; set; } + [ApiMember(Name = "UserId", Description = "User Id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string UserId { get; set; } /// /// Skips over a given number of items within the results. Use for paging. @@ -115,7 +122,7 @@ namespace MediaBrowser.Api public void Post(AddToPlaylist request) { - var task = _playlistManager.AddToPlaylist(request.Id, request.Ids.Split(',')); + var task = _playlistManager.AddToPlaylist(request.Id, request.Ids.Split(','), request.UserId); Task.WaitAll(task); } @@ -130,7 +137,7 @@ namespace MediaBrowser.Api public object Get(GetPlaylistItems request) { var playlist = (Playlist)_libraryManager.GetItemById(request.Id); - var user = request.UserId.HasValue ? _userManager.GetUserById(request.UserId.Value) : null; + var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(new Guid(request.UserId)) : null; var items = playlist.GetManageableItems().ToArray(); diff --git a/MediaBrowser.Controller/Playlists/IPlaylistManager.cs b/MediaBrowser.Controller/Playlists/IPlaylistManager.cs index c67a8a3d5..cbe0b97a4 100644 --- a/MediaBrowser.Controller/Playlists/IPlaylistManager.cs +++ b/MediaBrowser.Controller/Playlists/IPlaylistManager.cs @@ -26,8 +26,9 @@ namespace MediaBrowser.Controller.Playlists /// /// The playlist identifier. /// The item ids. + /// The user identifier. /// Task. - Task AddToPlaylist(string playlistId, IEnumerable itemIds); + Task AddToPlaylist(string playlistId, IEnumerable itemIds, string userId); /// /// Removes from playlist. diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index 84fcbb91a..2659a7c13 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -49,7 +49,7 @@ namespace MediaBrowser.Controller.Playlists } return inputItems.SelectMany(i => GetPlaylistItems(i, user)) - .Where(m => string.Equals(m.MediaType, playlistMediaType, StringComparison.OrdinalIgnoreCase)); + .Where(m => string.Equals(m.MediaType, playlistMediaType, StringComparison.OrdinalIgnoreCase)); } private static IEnumerable GetPlaylistItems(BaseItem i, User user) @@ -57,25 +57,31 @@ namespace MediaBrowser.Controller.Playlists var musicGenre = i as MusicGenre; if (musicGenre != null) { - var songs = user.RootFolder - .GetRecursiveChildren(user) + var items = user == null + ? LibraryManager.RootFolder.GetRecursiveChildren() + : user.RootFolder.GetRecursiveChildren(user, true); + + var songs = items .OfType /// The playlist identifier. /// The item ids. + /// The user identifier. /// Task. - Task AddToPlaylist(string playlistId, IEnumerable itemIds); + Task AddToPlaylist(string playlistId, IEnumerable itemIds, string userId); /// /// Removes from playlist. diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index d3e61792f..0dfd27a72 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -1,12 +1,12 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Library; +using MediaBrowser.Model.Providers; using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Runtime.Serialization; -using MediaBrowser.Model.Providers; namespace MediaBrowser.Model.Dto { @@ -227,6 +227,12 @@ namespace MediaBrowser.Model.Dto /// The production year. public int? ProductionYear { get; set; } + /// + /// Gets or sets the recursive unplayed item count. + /// + /// The recursive unplayed item count. + public int? RecursiveUnplayedItemCount { get; set; } + /// /// Gets or sets the season count. /// diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index 2010b495c..2c683991c 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -1366,6 +1366,7 @@ namespace MediaBrowser.Server.Implementations.Dto dto.RecursiveItemCount = recursiveItemCount; dto.UserData.UnplayedItemCount = unplayed; + dto.RecursiveUnplayedItemCount = unplayed; if (recursiveItemCount > 0) { diff --git a/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs b/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs index 07c937389..ee2114aa4 100644 --- a/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs +++ b/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs @@ -82,7 +82,7 @@ namespace MediaBrowser.Server.Implementations.Playlists if (folder != null) { options.MediaType = folder.GetRecursiveChildren() - .Where(i => !i.IsFolder) + .Where(i => !i.IsFolder && i.SupportsAddingToPlaylist) .Select(i => i.MediaType) .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i)); } @@ -100,6 +100,8 @@ namespace MediaBrowser.Server.Implementations.Playlists throw new ArgumentException("A playlist media type is required."); } + var user = _userManager.GetUserById(new Guid(options.UserId)); + var path = Path.Combine(parentFolder.Path, folderName); path = GetTargetPath(path); @@ -126,7 +128,7 @@ namespace MediaBrowser.Server.Implementations.Playlists if (options.ItemIdList.Count > 0) { - await AddToPlaylist(playlist.Id.ToString("N"), options.ItemIdList); + await AddToPlaylistInternal(playlist.Id.ToString("N"), options.ItemIdList, user); } return new PlaylistCreationResult @@ -151,14 +153,21 @@ namespace MediaBrowser.Server.Implementations.Playlists return path; } - private IEnumerable GetPlaylistItems(IEnumerable itemIds, string playlistMediaType) + private IEnumerable GetPlaylistItems(IEnumerable itemIds, string playlistMediaType, User user) { var items = itemIds.Select(i => _libraryManager.GetItemById(i)).Where(i => i != null); - return Playlist.GetPlaylistItems(playlistMediaType, items, null); + return Playlist.GetPlaylistItems(playlistMediaType, items, user); } - public async Task AddToPlaylist(string playlistId, IEnumerable itemIds) + public Task AddToPlaylist(string playlistId, IEnumerable itemIds, string userId) + { + var user = string.IsNullOrWhiteSpace(userId) ? null : _userManager.GetUserById(new Guid(userId)); + + return AddToPlaylistInternal(playlistId, itemIds, user); + } + + private async Task AddToPlaylistInternal(string playlistId, IEnumerable itemIds, User user) { var playlist = _libraryManager.GetItemById(playlistId) as Playlist; @@ -170,7 +179,9 @@ namespace MediaBrowser.Server.Implementations.Playlists var list = new List(); var itemList = new List(); - var items = GetPlaylistItems(itemIds, playlist.MediaType).ToList(); + var items = GetPlaylistItems(itemIds, playlist.MediaType, user) + .Where(i => i.SupportsAddingToPlaylist) + .ToList(); foreach (var item in items) { @@ -183,7 +194,6 @@ namespace MediaBrowser.Server.Implementations.Playlists await playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); await playlist.RefreshMetadata(new MetadataRefreshOptions { - ForceSave = true }, CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Tests/MediaEncoding/Subtitles/SsaParserTests.cs b/MediaBrowser.Tests/MediaEncoding/Subtitles/SsaParserTests.cs index 3c278ae41..d869146fd 100644 --- a/MediaBrowser.Tests/MediaEncoding/Subtitles/SsaParserTests.cs +++ b/MediaBrowser.Tests/MediaEncoding/Subtitles/SsaParserTests.cs @@ -39,7 +39,7 @@ namespace MediaBrowser.Tests.MediaEncoding.Subtitles { } }; - var sut = new SsaParser(); + var sut = new AssParser(); var stream = File.OpenRead(@"MediaEncoding\Subtitles\TestSubtitles\data.ssa"); -- cgit v1.2.3