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') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 5ee119e133..1087c905c8 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') diff --git a/MediaBrowser.Api/ConfigurationService.cs b/MediaBrowser.Api/ConfigurationService.cs index b3191cd4b9..39fcc50d8f 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 28de8ee174..82bd394f0c 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 1e9ff9199e..3f1d9fe67d 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 7bd0ca7482..ebd6c6b59f 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 8c4840ea71..60abc14f1a 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 0000000000..310e2aa638 --- /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 0000000000..d418d0a423 --- /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 0d0759b666..25698d9729 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 2e7db5c351..9d59843171 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 d85a2fd1e0..0cc4fc6b4d 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 b8f29d1ceb..676ef9c561 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 9468fd9875..38c2c83c47 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 0000000000..821e21ccfb --- /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 bb65f422c5..f594b4471d 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 0485255881..5f2c1c49ae 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 10da21e52c..1d51fc60ff 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 095c6a893c..1f8c33ee7d 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 22d4797a3e..ccc7d46e6e 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 9f7e87088a..c2af1f5a12 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 0fc7c579b5..0455dd674d 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 1087c905c8..ce761ff9c1 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 154541316d..ab9cd546aa 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 ee6f05cc1c..3c34652c32 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 a2fa1aa949..9e3df382ef 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 0000000000..f0fc4d47c4 --- /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 0000000000..8a059a0a4a --- /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 0d728ec75e..3d5e0a9c92 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 0000000000..e6a3c3091e --- /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 885172bed7..94a41bdda0 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 9efa63283d..5d753f9c29 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 5f8664bec3..6e2cd77eb3 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 65faae3274..92b4616e71 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 056a526f6c..d35282e55c 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 d03c5fe3dc..8007e05062 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 9b8c0d68ce3e816c86a66702a7f5036760a42413 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 9 Jul 2014 10:39:04 -0400 Subject: update mono build --- .../BaseApplicationHost.cs | 3 ++- .../MediaBrowser.LocalMetadata.csproj | 3 +++ .../Properties/AssemblyInfo.cs | 4 +--- .../MediaBrowser.MediaEncoding.csproj | 3 +++ .../Properties/AssemblyInfo.cs | 4 +--- MediaBrowser.Mono.sln | 20 ++++++++++++++++++++ MediaBrowser.Mono.userprefs | 2 +- MediaBrowser.Providers/Manager/MetadataService.cs | 10 ++++++++++ MediaBrowser.Providers/TV/MovieDbSeasonProvider.cs | 2 +- MediaBrowser.Providers/TV/SeasonMetadataService.cs | 10 ++++++++++ .../MediaBrowser.Server.Mono.csproj | 8 ++++++++ MediaBrowser.Server.Mono/Program.cs | 4 ++-- MediaBrowser.ServerApplication/ApplicationHost.cs | 10 ++++++++-- .../MediaBrowser.XbmcMetadata.csproj | 3 +++ MediaBrowser.XbmcMetadata/Properties/AssemblyInfo.cs | 4 +--- 15 files changed, 74 insertions(+), 16 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs index ebd6c6b59f..178b840a87 100644 --- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs +++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs @@ -632,6 +632,7 @@ namespace MediaBrowser.Common.Implementations return parts; } + private Version _version; /// /// Gets the current application version /// @@ -640,7 +641,7 @@ namespace MediaBrowser.Common.Implementations { get { - return GetType().Assembly.GetName().Version; + return _version ?? (_version = GetType().Assembly.GetName().Version); } } diff --git a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj index 0d2c0b97f2..2cc7e989b4 100644 --- a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj +++ b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj @@ -39,6 +39,9 @@ + + Properties\SharedVersion.cs + diff --git a/MediaBrowser.LocalMetadata/Properties/AssemblyInfo.cs b/MediaBrowser.LocalMetadata/Properties/AssemblyInfo.cs index dd1c89579f..a26bfd954c 100644 --- a/MediaBrowser.LocalMetadata/Properties/AssemblyInfo.cs +++ b/MediaBrowser.LocalMetadata/Properties/AssemblyInfo.cs @@ -31,6 +31,4 @@ using System.Runtime.InteropServices; // // 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")] +// [assembly: AssemblyVersion("1.0.*")] \ No newline at end of file diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index d2c21639c6..f11c261e21 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -52,6 +52,9 @@ + + Properties\SharedVersion.cs + diff --git a/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs b/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs index 6616e46acc..6b456b98d3 100644 --- a/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs +++ b/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs @@ -31,6 +31,4 @@ using System.Runtime.InteropServices; // // 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")] +// [assembly: AssemblyVersion("1.0.*")] \ No newline at end of file diff --git a/MediaBrowser.Mono.sln b/MediaBrowser.Mono.sln index 9c23970468..daf06c0836 100644 --- a/MediaBrowser.Mono.sln +++ b/MediaBrowser.Mono.sln @@ -25,6 +25,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.MediaEncoding" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenSubtitlesHandler", "OpenSubtitlesHandler\OpenSubtitlesHandler.csproj", "{4A4402D4-E910-443B-B8FC-2C18286A2CA0}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.LocalMetadata", "MediaBrowser.LocalMetadata\MediaBrowser.LocalMetadata.csproj", "{7EF9F3E0-697D-42F3-A08F-19DEB5F84392}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.XbmcMetadata", "MediaBrowser.XbmcMetadata\MediaBrowser.XbmcMetadata.csproj", "{23499896-B135-4527-8574-C26E926EA99E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 @@ -57,6 +61,14 @@ Global {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|Any CPU.Build.0 = Release|Any CPU {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|x86.ActiveCfg = Release|Any CPU {17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}.Release|x86.Build.0 = Release|Any CPU + {23499896-B135-4527-8574-C26E926EA99E}.Debug|x86.ActiveCfg = Debug|Any CPU + {23499896-B135-4527-8574-C26E926EA99E}.Debug|x86.Build.0 = Debug|Any CPU + {23499896-B135-4527-8574-C26E926EA99E}.Release Mono|Any CPU.ActiveCfg = Release|Any CPU + {23499896-B135-4527-8574-C26E926EA99E}.Release Mono|Any CPU.Build.0 = Release|Any CPU + {23499896-B135-4527-8574-C26E926EA99E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {23499896-B135-4527-8574-C26E926EA99E}.Release|Any CPU.Build.0 = Release|Any CPU + {23499896-B135-4527-8574-C26E926EA99E}.Release|x86.ActiveCfg = Release|Any CPU + {23499896-B135-4527-8574-C26E926EA99E}.Release|x86.Build.0 = Release|Any CPU {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|x86.ActiveCfg = Debug|Any CPU {2E781478-814D-4A48-9D80-BFF206441A65}.Debug|x86.Build.0 = Debug|Any CPU {2E781478-814D-4A48-9D80-BFF206441A65}.Release Mono|Any CPU.ActiveCfg = Release Mono|Any CPU @@ -113,6 +125,14 @@ Global {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|Any CPU.Build.0 = Release|Any CPU {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|x86.ActiveCfg = Release|Any CPU {7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|x86.Build.0 = Release|Any CPU + {7EF9F3E0-697D-42F3-A08F-19DEB5F84392}.Debug|x86.ActiveCfg = Debug|Any CPU + {7EF9F3E0-697D-42F3-A08F-19DEB5F84392}.Debug|x86.Build.0 = Debug|Any CPU + {7EF9F3E0-697D-42F3-A08F-19DEB5F84392}.Release Mono|Any CPU.ActiveCfg = Release|Any CPU + {7EF9F3E0-697D-42F3-A08F-19DEB5F84392}.Release Mono|Any CPU.Build.0 = Release|Any CPU + {7EF9F3E0-697D-42F3-A08F-19DEB5F84392}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7EF9F3E0-697D-42F3-A08F-19DEB5F84392}.Release|Any CPU.Build.0 = Release|Any CPU + {7EF9F3E0-697D-42F3-A08F-19DEB5F84392}.Release|x86.ActiveCfg = Release|Any CPU + {7EF9F3E0-697D-42F3-A08F-19DEB5F84392}.Release|x86.Build.0 = Release|Any CPU {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|x86.ActiveCfg = Debug|Any CPU {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|x86.Build.0 = Debug|Any CPU {9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Release Mono|Any CPU.ActiveCfg = Release Mono|Any CPU diff --git a/MediaBrowser.Mono.userprefs b/MediaBrowser.Mono.userprefs index f115a532ed..bac7f95102 100644 --- a/MediaBrowser.Mono.userprefs +++ b/MediaBrowser.Mono.userprefs @@ -5,7 +5,7 @@ - + diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 91466c655e..335fb97699 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -470,9 +470,19 @@ namespace MediaBrowser.Providers.Manager } } + if (refreshResult.Successes > 0) + { + AfterRemoteRefresh(temp); + } + return refreshResult; } + protected virtual void AfterRemoteRefresh(TItemType item) + { + + } + private async Task CreateInitialLookupInfo(TItemType item, CancellationToken cancellationToken) { var info = item.GetLookupInfo(); diff --git a/MediaBrowser.Providers/TV/MovieDbSeasonProvider.cs b/MediaBrowser.Providers/TV/MovieDbSeasonProvider.cs index 6b2c067329..49b0d67f9f 100644 --- a/MediaBrowser.Providers/TV/MovieDbSeasonProvider.cs +++ b/MediaBrowser.Providers/TV/MovieDbSeasonProvider.cs @@ -60,7 +60,7 @@ namespace MediaBrowser.Providers.TV var seasonInfo = await GetSeasonInfo(seriesTmdbId, seasonNumber.Value, info.MetadataLanguage, cancellationToken) .ConfigureAwait(false); - result.Item.Name = seasonInfo.name; + result.Item.Name = info.Name; result.Item.Overview = seasonInfo.overview; result.Item.IndexNumber = seasonNumber; diff --git a/MediaBrowser.Providers/TV/SeasonMetadataService.cs b/MediaBrowser.Providers/TV/SeasonMetadataService.cs index 4c0149d2e7..5e7570ad15 100644 --- a/MediaBrowser.Providers/TV/SeasonMetadataService.cs +++ b/MediaBrowser.Providers/TV/SeasonMetadataService.cs @@ -28,5 +28,15 @@ namespace MediaBrowser.Providers.TV { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); } + + protected override void AfterRemoteRefresh(Season item) + { + base.AfterRemoteRefresh(item); + + if (item.IndexNumber.HasValue && item.IndexNumber.Value == 0) + { + item.Name = ServerConfigurationManager.Configuration.SeasonZeroDisplayName; + } + } } } diff --git a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj index e94c297eb9..b6c1ab98bd 100644 --- a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj +++ b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj @@ -128,6 +128,14 @@ {0BD82FA6-EB8A-4452-8AF5-74F9C3849451} MediaBrowser.MediaEncoding + + {7EF9F3E0-697D-42F3-A08F-19DEB5F84392} + MediaBrowser.LocalMetadata + + + {23499896-B135-4527-8574-C26E926EA99E} + MediaBrowser.XbmcMetadata + diff --git a/MediaBrowser.Server.Mono/Program.cs b/MediaBrowser.Server.Mono/Program.cs index b849c7a440..a3e645c8e8 100644 --- a/MediaBrowser.Server.Mono/Program.cs +++ b/MediaBrowser.Server.Mono/Program.cs @@ -42,7 +42,7 @@ namespace MediaBrowser.Server.Mono #endif // Allow this to be specified on the command line. - var customProgramDataPath = ParseCommandLine(); + var customProgramDataPath = ParseProgramDataPathFromCommandLine(); var appPaths = CreateApplicationPaths(applicationPath, customProgramDataPath); @@ -74,7 +74,7 @@ namespace MediaBrowser.Server.Mono } } - private static string ParseCommandLine() + private static string ParseProgramDataPathFromCommandLine() { var commandArgs = Environment.GetCommandLineArgs().ToList(); diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index ca04e580f3..688c07639c 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -1216,8 +1216,14 @@ namespace MediaBrowser.ServerApplication HasUpdateAvailable = versionObject != null && versionObject >= ApplicationVersion; - return versionObject != null ? new CheckForUpdateResult { AvailableVersion = versionObject.ToString(), IsUpdateAvailable = versionObject > ApplicationVersion, Package = version } : - new CheckForUpdateResult { AvailableVersion = ApplicationVersion.ToString(), IsUpdateAvailable = false }; + if (versionObject != null && versionObject >= ApplicationVersion) + { + Logger.Info("New application version is available: {0}", versionObject); + } + + return versionObject != null ? + new CheckForUpdateResult { AvailableVersion = versionObject.ToString(), IsUpdateAvailable = versionObject > ApplicationVersion, Package = version } : + new CheckForUpdateResult { AvailableVersion = ApplicationVersion.ToString(), IsUpdateAvailable = false }; } /// diff --git a/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj b/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj index 972595b94f..7116b4fd70 100644 --- a/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj +++ b/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj @@ -39,6 +39,9 @@ + + Properties\SharedVersion.cs + diff --git a/MediaBrowser.XbmcMetadata/Properties/AssemblyInfo.cs b/MediaBrowser.XbmcMetadata/Properties/AssemblyInfo.cs index 03829798e7..7df6e59678 100644 --- a/MediaBrowser.XbmcMetadata/Properties/AssemblyInfo.cs +++ b/MediaBrowser.XbmcMetadata/Properties/AssemblyInfo.cs @@ -31,6 +31,4 @@ using System.Runtime.InteropServices; // // 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")] +// [assembly: AssemblyVersion("1.0.*")] \ No newline at end of file -- cgit v1.2.3 From a118169a3ccf3361a5920794c7762dfcff1babd2 Mon Sep 17 00:00:00 2001 From: gsnerf Date: Wed, 6 Aug 2014 01:06:45 +0200 Subject: removed block of NuGet.targets for 'Release Mono' --- .../MediaBrowser.Common.Implementations.csproj | 3 ++- MediaBrowser.Controller/MediaBrowser.Controller.csproj | 3 ++- MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj | 5 +++-- MediaBrowser.Providers/MediaBrowser.Providers.csproj | 5 +++-- .../MediaBrowser.Server.Implementations.csproj | 3 ++- MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj | 3 ++- 6 files changed, 14 insertions(+), 8 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj index fe6da7e4fe..954d9bfe3c 100644 --- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj +++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj @@ -122,7 +122,8 @@ - + + if '$(ConfigurationName)' == 'Release' ( xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\" /y /d /r /i diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 3ecf5ef45c..610510109f 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -349,7 +349,8 @@ xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\" /y /d /r /i - + + + - \ No newline at end of file + diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 9a26101a1f..7657e6ca8a 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -205,7 +205,8 @@ - + + - \ No newline at end of file + diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 9dd16e7c38..f5837c4cab 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -481,7 +481,8 @@ - + + + if '$(ConfigurationName)' == 'Release' ( diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index fd41c7e9e9..661073c89e 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -116,7 +116,7 @@ - + if '$(ConfigurationName)' == 'Release' ( xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\" /y /d /r /i diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 6a9c4edbbe..5243e1a2ae 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -352,7 +352,6 @@ xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\" /y /d /r /i - - \ No newline at end of file + diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index fb04216784..76a1e52f5b 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -205,7 +205,6 @@ - - + \ No newline at end of file diff --git a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs new file mode 100644 index 0000000000..e5a7274282 --- /dev/null +++ b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading; + +namespace MediaBrowser.MediaEncoding.Subtitles +{ + public class AssParser : ISubtitleParser + { + private readonly CultureInfo _usCulture = new CultureInfo("en-US"); + + public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken) + { + var trackInfo = new SubtitleTrackInfo(); + var eventIndex = 1; + using (var reader = new StreamReader(stream)) + { + string line; + while (reader.ReadLine() != "[Events]") + {} + var headers = ParseFieldHeaders(reader.ReadLine()); + + while ((line = reader.ReadLine()) != null) + { + cancellationToken.ThrowIfCancellationRequested(); + + if (string.IsNullOrWhiteSpace(line)) + { + continue; + } + if(line.StartsWith("[")) + break; + if(string.IsNullOrEmpty(line)) + continue; + var subEvent = new SubtitleTrackEvent { Id = eventIndex.ToString(_usCulture) }; + eventIndex++; + var sections = line.Substring(10).Split(','); + + subEvent.StartPositionTicks = GetTicks(sections[headers["Start"]]); + subEvent.EndPositionTicks = GetTicks(sections[headers["End"]]); + subEvent.Text = string.Join(",", sections.Skip(headers["Text"])); + subEvent.Text = Regex.Replace(subEvent.Text, @"\{(\\[\w]+\(?([\w\d]+,?)+\)?)+\}", string.Empty, RegexOptions.IgnoreCase); + + trackInfo.TrackEvents.Add(subEvent); + } + } + return trackInfo; + } + + long GetTicks(string time) + { + TimeSpan span; + return TimeSpan.TryParseExact(time, @"h\:mm\:ss\.ff", _usCulture, out span) + ? span.Ticks: 0; + } + + private Dictionary ParseFieldHeaders(string line) { + var fields = line.Substring(8).Split(',').Select(x=>x.Trim()).ToList(); + + var result = new Dictionary { + {"Start", fields.IndexOf("Start")}, + {"End", fields.IndexOf("End")}, + {"Text", fields.IndexOf("Text")} + }; + return result; + } + } +} diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs index e21804f6cc..4b11d55ce0 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs @@ -1,71 +1,391 @@ using System; -using System.Collections.Generic; -using System.Globalization; using System.IO; -using System.Linq; -using System.Text.RegularExpressions; +using System.Text; using System.Threading; namespace MediaBrowser.MediaEncoding.Subtitles { + /// + /// Credit to https://github.com/SubtitleEdit/subtitleedit/blob/a299dc4407a31796364cc6ad83f0d3786194ba22/src/Logic/SubtitleFormats/SubStationAlpha.cs + /// public class SsaParser : ISubtitleParser { - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken) { var trackInfo = new SubtitleTrackInfo(); - var eventIndex = 1; + using (var reader = new StreamReader(stream)) { + bool eventsStarted = false; + + string[] format = "Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text".Split(','); + int indexLayer = 0; + int indexStart = 1; + int indexEnd = 2; + int indexStyle = 3; + int indexName = 4; + int indexEffect = 8; + int indexText = 9; + int lineNumber = 0; + + var header = new StringBuilder(); + string line; - while (reader.ReadLine() != "[Events]") - {} - var headers = ParseFieldHeaders(reader.ReadLine()); while ((line = reader.ReadLine()) != null) { cancellationToken.ThrowIfCancellationRequested(); - - if (string.IsNullOrWhiteSpace(line)) + + lineNumber++; + if (!eventsStarted) + header.AppendLine(line); + + if (line.Trim().ToLower() == "[events]") { - continue; + eventsStarted = true; } - if(line.StartsWith("[")) - break; - if(string.IsNullOrEmpty(line)) - continue; - var subEvent = new SubtitleTrackEvent { Id = eventIndex.ToString(_usCulture) }; - eventIndex++; - var sections = line.Substring(10).Split(','); - - subEvent.StartPositionTicks = GetTicks(sections[headers["Start"]]); - subEvent.EndPositionTicks = GetTicks(sections[headers["End"]]); - subEvent.Text = string.Join(",", sections.Skip(headers["Text"])); - subEvent.Text = Regex.Replace(subEvent.Text, @"\{(\\[\w]+\(?([\w\d]+,?)+\)?)+\}", string.Empty, RegexOptions.IgnoreCase); - - trackInfo.TrackEvents.Add(subEvent); - } + else if (!string.IsNullOrEmpty(line) && line.Trim().StartsWith(";")) + { + // skip comment lines + } + else if (eventsStarted && line.Trim().Length > 0) + { + string s = line.Trim().ToLower(); + if (s.StartsWith("format:")) + { + if (line.Length > 10) + { + format = line.ToLower().Substring(8).Split(','); + for (int i = 0; i < format.Length; i++) + { + if (format[i].Trim().ToLower() == "layer") + indexLayer = i; + else if (format[i].Trim().ToLower() == "start") + indexStart = i; + else if (format[i].Trim().ToLower() == "end") + indexEnd = i; + else if (format[i].Trim().ToLower() == "text") + indexText = i; + else if (format[i].Trim().ToLower() == "effect") + indexEffect = i; + else if (format[i].Trim().ToLower() == "style") + indexStyle = i; + } + } + } + else if (!string.IsNullOrEmpty(s)) + { + string text = string.Empty; + string start = string.Empty; + string end = string.Empty; + string style = string.Empty; + string layer = string.Empty; + string effect = string.Empty; + string name = string.Empty; + + string[] splittedLine; + + if (s.StartsWith("dialogue:")) + splittedLine = line.Substring(10).Split(','); + else + splittedLine = line.Split(','); + + for (int i = 0; i < splittedLine.Length; i++) + { + if (i == indexStart) + start = splittedLine[i].Trim(); + else if (i == indexEnd) + end = splittedLine[i].Trim(); + else if (i == indexLayer) + layer = splittedLine[i]; + else if (i == indexEffect) + effect = splittedLine[i]; + else if (i == indexText) + text = splittedLine[i]; + else if (i == indexStyle) + style = splittedLine[i]; + else if (i == indexName) + name = splittedLine[i]; + else if (i > indexText) + text += "," + splittedLine[i]; + } + + try + { + var p = new SubtitleTrackEvent(); + + p.StartPositionTicks = GetTimeCodeFromString(start); + p.EndPositionTicks = GetTimeCodeFromString(end); + p.Text = GetFormattedText(text); + + trackInfo.TrackEvents.Add(p); + } + catch + { + } + } + } + } + + //if (header.Length > 0) + //subtitle.Header = header.ToString(); + + //subtitle.Renumber(1); } return trackInfo; } - long GetTicks(string time) + private static long GetTimeCodeFromString(string time) + { + // h:mm:ss.cc + string[] timeCode = time.Split(':', '.'); + return new TimeSpan(0, int.Parse(timeCode[0]), + int.Parse(timeCode[1]), + int.Parse(timeCode[2]), + int.Parse(timeCode[3]) * 10).Ticks; + } + + public static string GetFormattedText(string text) + { + text = text.Replace("\\N", Environment.NewLine).Replace("\\n", Environment.NewLine); + bool italic = false; + + for (int i = 0; i < 10; i++) // just look ten times... + { + if (text.Contains(@"{\fn")) + { + int start = text.IndexOf(@"{\fn"); + int end = text.IndexOf('}', start); + if (end > 0 && !text.Substring(start).StartsWith("{\\fn}")) + { + string fontName = text.Substring(start + 4, end - (start + 4)); + string extraTags = string.Empty; + CheckAndAddSubTags(ref fontName, ref extraTags, out italic); + text = text.Remove(start, end - start + 1); + if (italic) + text = text.Insert(start, ""); + else + text = text.Insert(start, ""); + + int indexOfEndTag = text.IndexOf("{\\fn}", start); + if (indexOfEndTag > 0) + text = text.Remove(indexOfEndTag, "{\\fn}".Length).Insert(indexOfEndTag, ""); + else + text += ""; + } + } + + if (text.Contains(@"{\fs")) + { + int start = text.IndexOf(@"{\fs"); + int end = text.IndexOf('}', start); + if (end > 0 && !text.Substring(start).StartsWith("{\\fs}")) + { + string fontSize = text.Substring(start + 4, end - (start + 4)); + string extraTags = string.Empty; + CheckAndAddSubTags(ref fontSize, ref extraTags, out italic); + if (IsInteger(fontSize)) + { + text = text.Remove(start, end - start + 1); + if (italic) + text = text.Insert(start, ""); + else + text = text.Insert(start, ""); + + int indexOfEndTag = text.IndexOf("{\\fs}", start); + if (indexOfEndTag > 0) + text = text.Remove(indexOfEndTag, "{\\fs}".Length).Insert(indexOfEndTag, ""); + else + text += ""; + } + } + } + + if (text.Contains(@"{\c")) + { + int start = text.IndexOf(@"{\c"); + int end = text.IndexOf('}', start); + if (end > 0 && !text.Substring(start).StartsWith("{\\c}")) + { + string color = text.Substring(start + 4, end - (start + 4)); + string extraTags = string.Empty; + CheckAndAddSubTags(ref color, ref extraTags, out italic); + + color = color.Replace("&", string.Empty).TrimStart('H'); + color = color.PadLeft(6, '0'); + + // switch to rrggbb from bbggrr + color = "#" + color.Remove(color.Length - 6) + color.Substring(color.Length - 2, 2) + color.Substring(color.Length - 4, 2) + color.Substring(color.Length - 6, 2); + color = color.ToLower(); + + text = text.Remove(start, end - start + 1); + if (italic) + text = text.Insert(start, ""); + else + text = text.Insert(start, ""); + int indexOfEndTag = text.IndexOf("{\\c}", start); + if (indexOfEndTag > 0) + text = text.Remove(indexOfEndTag, "{\\c}".Length).Insert(indexOfEndTag, ""); + else + text += ""; + } + } + + if (text.Contains(@"{\1c")) // "1" specifices primary color + { + int start = text.IndexOf(@"{\1c"); + int end = text.IndexOf('}', start); + if (end > 0 && !text.Substring(start).StartsWith("{\\1c}")) + { + string color = text.Substring(start + 5, end - (start + 5)); + string extraTags = string.Empty; + CheckAndAddSubTags(ref color, ref extraTags, out italic); + + color = color.Replace("&", string.Empty).TrimStart('H'); + color = color.PadLeft(6, '0'); + + // switch to rrggbb from bbggrr + color = "#" + color.Remove(color.Length - 6) + color.Substring(color.Length - 2, 2) + color.Substring(color.Length - 4, 2) + color.Substring(color.Length - 6, 2); + color = color.ToLower(); + + text = text.Remove(start, end - start + 1); + if (italic) + text = text.Insert(start, ""); + else + text = text.Insert(start, ""); + text += ""; + } + } + + } + + text = text.Replace(@"{\i1}", ""); + text = text.Replace(@"{\i0}", ""); + text = text.Replace(@"{\i}", ""); + if (CountTagInText(text, "") > CountTagInText(text, "")) + text += ""; + + text = text.Replace(@"{\u1}", ""); + text = text.Replace(@"{\u0}", ""); + text = text.Replace(@"{\u}", ""); + if (CountTagInText(text, "") > CountTagInText(text, "")) + text += ""; + + text = text.Replace(@"{\b1}", ""); + text = text.Replace(@"{\b0}", ""); + text = text.Replace(@"{\b}", ""); + if (CountTagInText(text, "") > CountTagInText(text, "")) + text += ""; + + return text; + } + + private static bool IsInteger(string s) { - TimeSpan span; - return TimeSpan.TryParseExact(time, @"h\:mm\:ss\.ff", _usCulture, out span) - ? span.Ticks: 0; + int i; + if (int.TryParse(s, out i)) + return true; + return false; } - private Dictionary ParseFieldHeaders(string line) { - var fields = line.Substring(8).Split(',').Select(x=>x.Trim()).ToList(); + private static int CountTagInText(string text, string tag) + { + int count = 0; + int index = text.IndexOf(tag); + while (index >= 0) + { + count++; + if (index == text.Length) + return count; + index = text.IndexOf(tag, index + 1); + } + return count; + } + + private static void CheckAndAddSubTags(ref string tagName, ref string extraTags, out bool italic) + { + italic = false; + int indexOfSPlit = tagName.IndexOf(@"\"); + if (indexOfSPlit > 0) + { + string rest = tagName.Substring(indexOfSPlit).TrimStart('\\'); + tagName = tagName.Remove(indexOfSPlit); + + for (int i = 0; i < 10; i++) + { + if (rest.StartsWith("fs") && rest.Length > 2) + { + indexOfSPlit = rest.IndexOf(@"\"); + string fontSize = rest; + if (indexOfSPlit > 0) + { + fontSize = rest.Substring(0, indexOfSPlit); + rest = rest.Substring(indexOfSPlit).TrimStart('\\'); + } + else + { + rest = string.Empty; + } + extraTags += " size=\"" + fontSize.Substring(2) + "\""; + } + else if (rest.StartsWith("fn") && rest.Length > 2) + { + indexOfSPlit = rest.IndexOf(@"\"); + string fontName = rest; + if (indexOfSPlit > 0) + { + fontName = rest.Substring(0, indexOfSPlit); + rest = rest.Substring(indexOfSPlit).TrimStart('\\'); + } + else + { + rest = string.Empty; + } + extraTags += " face=\"" + fontName.Substring(2) + "\""; + } + else if (rest.StartsWith("c") && rest.Length > 2) + { + indexOfSPlit = rest.IndexOf(@"\"); + string fontColor = rest; + if (indexOfSPlit > 0) + { + fontColor = rest.Substring(0, indexOfSPlit); + rest = rest.Substring(indexOfSPlit).TrimStart('\\'); + } + else + { + rest = string.Empty; + } + + string color = fontColor.Substring(2); + color = color.Replace("&", string.Empty).TrimStart('H'); + color = color.PadLeft(6, '0'); + // switch to rrggbb from bbggrr + color = "#" + color.Remove(color.Length - 6) + color.Substring(color.Length - 2, 2) + color.Substring(color.Length - 4, 2) + color.Substring(color.Length - 6, 2); + color = color.ToLower(); - var result = new Dictionary { - {"Start", fields.IndexOf("Start")}, - {"End", fields.IndexOf("End")}, - {"Text", fields.IndexOf("Text")} - }; - return result; + extraTags += " color=\"" + color + "\""; + } + else if (rest.StartsWith("i1") && rest.Length > 1) + { + indexOfSPlit = rest.IndexOf(@"\"); + italic = true; + if (indexOfSPlit > 0) + { + rest = rest.Substring(indexOfSPlit).TrimStart('\\'); + } + else + { + rest = string.Empty; + } + } + else if (rest.Length > 0 && rest.Contains("\\")) + { + indexOfSPlit = rest.IndexOf(@"\"); + rest = rest.Substring(indexOfSPlit).TrimStart('\\'); + } + } + } } } } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 82e331dd87..c083cad4ee 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -239,11 +239,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles { return new SrtParser(); } - if (string.Equals(format, SubtitleFormat.SSA, StringComparison.OrdinalIgnoreCase) || - string.Equals(format, SubtitleFormat.ASS, StringComparison.OrdinalIgnoreCase)) + if (string.Equals(format, SubtitleFormat.SSA, StringComparison.OrdinalIgnoreCase)) { return new SsaParser(); } + if (string.Equals(format, SubtitleFormat.ASS, StringComparison.OrdinalIgnoreCase)) + { + return new AssParser(); + } if (throwIfMissing) { diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs index af37a2be0f..4ccafd5908 100644 --- a/MediaBrowser.Model/ApiClient/IApiClient.cs +++ b/MediaBrowser.Model/ApiClient/IApiClient.cs @@ -1271,8 +1271,9 @@ namespace MediaBrowser.Model.ApiClient /// /// 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 d3e61792fa..0dfd27a729 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 2010b495c8..2c683991ca 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 07c9373892..ee2114aa4d 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 3c278ae418..d869146fdc 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 From 21d88faa187f89854f2ab5f5146baea70b6bc118 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 22 Aug 2014 11:47:44 -0400 Subject: added json subtitle output --- MediaBrowser.Api/Subtitles/SubtitleService.cs | 6 ++++- MediaBrowser.Common/Net/MimeTypes.cs | 4 ++++ .../MediaBrowser.MediaEncoding.csproj | 1 + MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs | 27 ++++++++++++++++++++++ .../Subtitles/SubtitleEncoder.cs | 9 +++++++- .../Session/HttpSessionController.cs | 2 +- MediaBrowser.ServerApplication/ApplicationHost.cs | 2 +- 7 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.Api/Subtitles/SubtitleService.cs b/MediaBrowser.Api/Subtitles/SubtitleService.cs index dc5799239a..6e28823193 100644 --- a/MediaBrowser.Api/Subtitles/SubtitleService.cs +++ b/MediaBrowser.Api/Subtitles/SubtitleService.cs @@ -174,12 +174,16 @@ namespace MediaBrowser.Api.Subtitles } builder.AppendLine("#EXT-X-ENDLIST"); - + return ResultFactory.GetResult(builder.ToString(), Common.Net.MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary()); } public object Get(GetSubtitle request) { + if (string.Equals(request.Format, "js", StringComparison.OrdinalIgnoreCase)) + { + request.Format = "json"; + } if (string.IsNullOrEmpty(request.Format)) { var item = (Video)_libraryManager.GetItemById(new Guid(request.Id)); diff --git a/MediaBrowser.Common/Net/MimeTypes.cs b/MediaBrowser.Common/Net/MimeTypes.cs index ee3b7dad6e..bd9668d800 100644 --- a/MediaBrowser.Common/Net/MimeTypes.cs +++ b/MediaBrowser.Common/Net/MimeTypes.cs @@ -203,6 +203,10 @@ namespace MediaBrowser.Common.Net { return "application/x-javascript"; } + if (ext.Equals(".json", StringComparison.OrdinalIgnoreCase)) + { + return JsonMimeType; + } if (ext.Equals(".map", StringComparison.OrdinalIgnoreCase)) { return "application/x-javascript"; diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index 94e3575a10..9263a31875 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -61,6 +61,7 @@ + diff --git a/MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs new file mode 100644 index 0000000000..a4fc5d7952 --- /dev/null +++ b/MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs @@ -0,0 +1,27 @@ +using MediaBrowser.Model.Serialization; +using System.IO; +using System.Text; +using System.Threading; + +namespace MediaBrowser.MediaEncoding.Subtitles +{ + public class JsonWriter : ISubtitleWriter + { + private readonly IJsonSerializer _json; + + public JsonWriter(IJsonSerializer json) + { + _json = json; + } + + public void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken) + { + using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true)) + { + var json = _json.SerializeToString(info); + + writer.Write(json); + } + } + } +} diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index c083cad4ee..1e839c5a36 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -7,6 +7,7 @@ using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; +using MediaBrowser.Model.Serialization; using System; using System.Collections.Concurrent; using System.Diagnostics; @@ -26,14 +27,16 @@ namespace MediaBrowser.MediaEncoding.Subtitles private readonly IApplicationPaths _appPaths; private readonly IFileSystem _fileSystem; private readonly IMediaEncoder _mediaEncoder; + private readonly IJsonSerializer _json; - public SubtitleEncoder(ILibraryManager libraryManager, ILogger logger, IApplicationPaths appPaths, IFileSystem fileSystem, IMediaEncoder mediaEncoder) + public SubtitleEncoder(ILibraryManager libraryManager, ILogger logger, IApplicationPaths appPaths, IFileSystem fileSystem, IMediaEncoder mediaEncoder, IJsonSerializer json) { _libraryManager = libraryManager; _logger = logger; _appPaths = appPaths; _fileSystem = fileSystem; _mediaEncoder = mediaEncoder; + _json = json; } private string SubtitleCachePath @@ -263,6 +266,10 @@ namespace MediaBrowser.MediaEncoding.Subtitles throw new ArgumentNullException("format"); } + if (string.Equals(format, "json", StringComparison.OrdinalIgnoreCase)) + { + return new JsonWriter(_json); + } if (string.Equals(format, SubtitleFormat.SRT, StringComparison.OrdinalIgnoreCase)) { return new SrtWriter(); diff --git a/MediaBrowser.Server.Implementations/Session/HttpSessionController.cs b/MediaBrowser.Server.Implementations/Session/HttpSessionController.cs index 1be4eca23e..a719e8be27 100644 --- a/MediaBrowser.Server.Implementations/Session/HttpSessionController.cs +++ b/MediaBrowser.Server.Implementations/Session/HttpSessionController.cs @@ -54,7 +54,7 @@ namespace MediaBrowser.Server.Implementations.Session { get { - return (DateTime.UtcNow - Session.LastActivityDate).TotalMinutes <= 10; + return (DateTime.UtcNow - Session.LastActivityDate).TotalMinutes <= 20; } } diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index 35ee580b50..00cefdb22d 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -535,7 +535,7 @@ namespace MediaBrowser.ServerApplication RegisterSingleInstance(new SessionContext(UserManager, authContext, SessionManager)); RegisterSingleInstance(new AuthService(UserManager, SessionManager, authContext, ServerConfigurationManager)); - RegisterSingleInstance(new SubtitleEncoder(LibraryManager, LogManager.GetLogger("SubtitleEncoder"), ApplicationPaths, FileSystemManager, MediaEncoder)); + RegisterSingleInstance(new SubtitleEncoder(LibraryManager, LogManager.GetLogger("SubtitleEncoder"), ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer)); var displayPreferencesTask = Task.Run(async () => await ConfigureDisplayPreferencesRepositories().ConfigureAwait(false)); var itemsTask = Task.Run(async () => await ConfigureItemRepositories().ConfigureAwait(false)); -- cgit v1.2.3 From d92936187d2e0a4391dbca6ea182bdb180c3dece Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 24 Aug 2014 17:07:04 -0400 Subject: Extract subs to srt instead of ass --- .../Subtitles/SubtitleEncoder.cs | 32 ++++++++++++---------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 1e839c5a36..df22b5e1f7 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -194,15 +194,17 @@ namespace MediaBrowser.MediaEncoding.Subtitles MediaStream subtitleStream, CancellationToken cancellationToken) { + const string extractedFormat = "srt"; + if (!subtitleStream.IsExternal) { // Extract - var outputPath = GetSubtitleCachePath(mediaPath, subtitleStream.Index, ".ass"); + var outputPath = GetSubtitleCachePath(mediaPath, subtitleStream.Index, "." + extractedFormat); await ExtractTextSubtitle(inputFiles, protocol, subtitleStream.Index, false, outputPath, cancellationToken) .ConfigureAwait(false); - return new Tuple(outputPath, "ass"); + return new Tuple(outputPath, extractedFormat); } var currentFormat = (Path.GetExtension(subtitleStream.Path) ?? subtitleStream.Codec) @@ -211,12 +213,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles if (GetReader(currentFormat, false) == null) { // Convert - var outputPath = GetSubtitleCachePath(mediaPath, subtitleStream.Index, ".ass"); + var outputPath = GetSubtitleCachePath(mediaPath, subtitleStream.Index, "." + extractedFormat); - await ConvertTextSubtitleToAss(subtitleStream.Path, outputPath, subtitleStream.Language, cancellationToken) + await ConvertTextSubtitleToSrt(subtitleStream.Path, outputPath, subtitleStream.Language, cancellationToken) .ConfigureAwait(false); - return new Tuple(outputPath, "ass"); + return new Tuple(outputPath, extractedFormat); } return new Tuple(subtitleStream.Path, currentFormat); @@ -303,14 +305,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles } /// - /// Converts the text subtitle to ass. + /// Converts the text subtitle to SRT. /// /// The input path. /// The output path. /// The language. /// The cancellation token. /// Task. - public async Task ConvertTextSubtitleToAss(string inputPath, string outputPath, string language, + public async Task ConvertTextSubtitleToSrt(string inputPath, string outputPath, string language, CancellationToken cancellationToken) { var semaphore = GetLock(outputPath); @@ -321,7 +323,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { if (!File.Exists(outputPath)) { - await ConvertTextSubtitleToAssInternal(inputPath, outputPath, language).ConfigureAwait(false); + await ConvertTextSubtitleToSrtInternal(inputPath, outputPath, language).ConfigureAwait(false); } } finally @@ -331,17 +333,19 @@ namespace MediaBrowser.MediaEncoding.Subtitles } /// - /// Converts the text subtitle to ass. + /// Converts the text subtitle to SRT internal. /// /// The input path. /// The output path. /// The language. /// Task. - /// inputPath + /// + /// inputPath /// or - /// outputPath + /// outputPath + /// /// - private async Task ConvertTextSubtitleToAssInternal(string inputPath, string outputPath, string language) + private async Task ConvertTextSubtitleToSrtInternal(string inputPath, string outputPath, string language) { if (string.IsNullOrEmpty(inputPath)) { @@ -375,7 +379,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles 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 srt \"{2}\"", encodingParam, inputPath, outputPath), WindowStyle = ProcessWindowStyle.Hidden, ErrorDialog = false @@ -529,7 +533,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); - var processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s ass \"{2}\"", inputPath, + var processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s srt \"{2}\"", inputPath, subtitleStreamIndex, outputPath); if (copySubtitleStream) -- cgit v1.2.3 From 0cb3c396367812a51ecb79b976cbeae50b97ab7b Mon Sep 17 00:00:00 2001 From: Luis Miguel Almánzar Date: Sun, 24 Aug 2014 18:02:47 -0400 Subject: change newline value --- MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs | 2 +- MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs | 2 +- MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs | 2 +- MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs | 2 +- MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs index f94fae9e92..84cd1eb2d3 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs @@ -48,7 +48,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles } multiline.Add(line); } - subEvent.Text = string.Join(@"\N", multiline); + subEvent.Text = string.Join(@"\n", multiline); subEvent.Text = Regex.Replace(subEvent.Text, @"\{(\\[\w]+\(?([\w\d]+,?)+\)?)+\}", string.Empty, RegexOptions.IgnoreCase); subEvent.Text = Regex.Replace(subEvent.Text, "<", "<", RegexOptions.IgnoreCase); subEvent.Text = Regex.Replace(subEvent.Text, ">", ">", RegexOptions.IgnoreCase); diff --git a/MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs index d0d0819dd6..3e574f9315 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs @@ -25,7 +25,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles var text = trackEvent.Text; // TODO: Not sure how to handle these - text = Regex.Replace(text, @"\\N", " ", RegexOptions.IgnoreCase); + text = Regex.Replace(text, @"\\n", " ", RegexOptions.IgnoreCase); writer.WriteLine(text); writer.WriteLine(string.Empty); diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs index 4b11d55ce0..559a05bc8a 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs @@ -147,7 +147,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles public static string GetFormattedText(string text) { - text = text.Replace("\\N", Environment.NewLine).Replace("\\n", Environment.NewLine); + text = text.Replace("\\n", Environment.NewLine).Replace("\\n", Environment.NewLine); bool italic = false; for (int i = 0; i < 10; i++) // just look ten times... diff --git a/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs index a937175f01..955b36ecda 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs @@ -34,7 +34,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { var text = trackEvent.Text; - text = Regex.Replace(text, @"\\N", "
", RegexOptions.IgnoreCase); + text = Regex.Replace(text, @"\\n", "
", RegexOptions.IgnoreCase); writer.WriteLine("

{2}

", trackEvent.StartPositionTicks, diff --git a/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs index 09f45aa61d..228f0beb1e 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs @@ -23,7 +23,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles var text = trackEvent.Text; // TODO: Not sure how to handle these - text = Regex.Replace(text, @"\\N", " ", RegexOptions.IgnoreCase); + text = Regex.Replace(text, @"\\n", " ", RegexOptions.IgnoreCase); writer.WriteLine(text); writer.WriteLine(string.Empty); -- cgit v1.2.3 From 96f8132f6e1c316b2d9fcc06fddea80f89e2c645 Mon Sep 17 00:00:00 2001 From: faush01 Date: Fri, 29 Aug 2014 16:42:56 +1000 Subject: make sure start and end times are different --- MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs index 09f45aa61d..285eed1686 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs @@ -18,7 +18,16 @@ namespace MediaBrowser.MediaEncoding.Subtitles { cancellationToken.ThrowIfCancellationRequested(); - writer.WriteLine(@"{0:hh\:mm\:ss\.fff} --> {1:hh\:mm\:ss\.fff}", TimeSpan.FromTicks(trackEvent.StartPositionTicks), TimeSpan.FromTicks(trackEvent.EndPositionTicks)); + TimeSpan startTime = TimeSpan.FromTicks(trackEvent.StartPositionTicks); + TimeSpan endTime = TimeSpan.FromTicks(trackEvent.EndPositionTicks); + + // make sure the start and end times are different and seqential + if (endTime.TotalMilliseconds <= startTime.TotalMilliseconds) + { + endTime = startTime.Add(TimeSpan.FromMilliseconds(1)); + } + + writer.WriteLine(@"{0:hh\:mm\:ss\.fff} --> {1:hh\:mm\:ss\.fff}", startTime, endTime); var text = trackEvent.Text; -- cgit v1.2.3 From 33c6c37316b062b9afc1a4b3c8f97b658cb62a70 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 30 Aug 2014 10:26:29 -0400 Subject: Adjust transcoding throttling --- MediaBrowser.Api/AppThemeService.cs | 2 +- MediaBrowser.Api/BaseApiService.cs | 18 --- MediaBrowser.Api/Images/ImageService.cs | 25 ++-- MediaBrowser.Api/Playback/BaseStreamingService.cs | 16 ++- MediaBrowser.Api/Playback/Hls/VideoHlsService.cs | 9 -- .../Progressive/BaseProgressiveStreamingService.cs | 61 ++++++--- MediaBrowser.Controller/Entities/Audio/Audio.cs | 2 + .../Entities/Audio/MusicAlbum.cs | 1 + .../Entities/Audio/MusicArtist.cs | 4 +- .../Entities/Audio/MusicGenre.cs | 2 + MediaBrowser.Controller/Entities/BaseItem.cs | 2 + MediaBrowser.Controller/Entities/Photo.cs | 17 +++ MediaBrowser.Controller/Entities/TV/Season.cs | 1 + MediaBrowser.Controller/Entities/TV/Series.cs | 1 + MediaBrowser.Controller/Entities/Video.cs | 2 + .../MediaBrowser.Controller.csproj | 1 + MediaBrowser.Controller/Net/IHttpResultFactory.cs | 42 ++----- MediaBrowser.Controller/Net/StaticResultOptions.cs | 42 +++++++ .../Subtitles/SubtitleEncoder.cs | 35 ++---- MediaBrowser.Model/Dto/BaseItemDto.cs | 6 +- MediaBrowser.Providers/Photos/PhotoProvider.cs | 15 ++- .../Dto/DtoService.cs | 16 ++- .../HttpServer/HttpResultFactory.cs | 139 ++++++++------------- .../HttpServer/RangeRequestWriter.cs | 3 +- .../HttpServer/StreamWriter.cs | 5 +- 25 files changed, 250 insertions(+), 217 deletions(-) create mode 100644 MediaBrowser.Controller/Net/StaticResultOptions.cs (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.Api/AppThemeService.cs b/MediaBrowser.Api/AppThemeService.cs index 0c8a0aaa63..87084e415a 100644 --- a/MediaBrowser.Api/AppThemeService.cs +++ b/MediaBrowser.Api/AppThemeService.cs @@ -94,7 +94,7 @@ namespace MediaBrowser.Api var contentType = MimeTypes.GetMimeType(info.Path); - return ToCachedResult(cacheGuid, info.DateModified, cacheDuration, () => _fileSystem.GetFileStream(info.Path, FileMode.Open, FileAccess.Read, FileShare.Read), contentType); + return ResultFactory.GetCachedResult(Request, cacheGuid, null, cacheDuration, () => _fileSystem.GetFileStream(info.Path, FileMode.Open, FileAccess.Read, FileShare.Read), contentType); } } } diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs index 727ee6fbcc..1af7054d95 100644 --- a/MediaBrowser.Api/BaseApiService.cs +++ b/MediaBrowser.Api/BaseApiService.cs @@ -97,24 +97,6 @@ namespace MediaBrowser.Api return session; } - /// - /// To the cached result. - /// - /// - /// The cache key. - /// The last date modified. - /// Duration of the cache. - /// The factory fn. - /// Type of the content. - /// The response headers. - /// System.Object. - /// cacheKey - protected object ToCachedResult(Guid cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, Func factoryFn, string contentType, IDictionary responseHeaders = null) - where T : class - { - return ResultFactory.GetCachedResult(Request, cacheKey, lastDateModified, cacheDuration, factoryFn, contentType, responseHeaders); - } - /// /// To the static file result. /// diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 43e9ad3efe..2213a5af1b 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -361,7 +361,7 @@ namespace MediaBrowser.Api.Images /// System.Object. public object Get(GetItemImage request) { - var item = string.IsNullOrEmpty(request.Id) ? + var item = string.IsNullOrEmpty(request.Id) ? _libraryManager.RootFolder : _libraryManager.GetItemById(request.Id); @@ -542,24 +542,24 @@ namespace MediaBrowser.Api.Images {"realTimeInfo.dlna.org", "DLNA.ORG_TLAG=*"} }; - return GetImageResult(item, - request, - imageInfo, - supportedImageEnhancers, - contentType, + return GetImageResult(item, + request, + imageInfo, + supportedImageEnhancers, + contentType, cacheDuration, responseHeaders, isHeadRequest) .Result; } - private async Task GetImageResult(IHasImages item, + private async Task GetImageResult(IHasImages item, ImageRequest request, ItemImageInfo image, List enhancers, string contentType, TimeSpan? cacheDuration, - IDictionary headers, + IDictionary headers, bool isHeadRequest) { var cropwhitespace = request.Type == ImageType.Logo || request.Type == ImageType.Art; @@ -590,7 +590,14 @@ namespace MediaBrowser.Api.Images var file = await _imageProcessor.ProcessImage(options).ConfigureAwait(false); - return ResultFactory.GetStaticFileResult(Request, file, contentType, cacheDuration, FileShare.Read, headers, isHeadRequest); + return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions + { + CacheDuration = cacheDuration, + ResponseHeaders = headers, + ContentType = contentType, + IsHeadRequest = isHeadRequest, + Path = file + }); } private string GetMimeType(ImageOutputFormat format, string path) diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index a0a8ee61ea..31a81de731 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -348,14 +348,16 @@ namespace MediaBrowser.Api.Playback var profileScore = 0; string crf; + var qmin = "0"; + var qmax = "50"; switch (qualitySetting) { case EncodingQuality.HighSpeed: - crf = "12"; + crf = "10"; break; case EncodingQuality.HighQuality: - crf = "8"; + crf = "6"; break; case EncodingQuality.MaxQuality: crf = "4"; @@ -371,11 +373,13 @@ namespace MediaBrowser.Api.Playback // Max of 2 profileScore = Math.Min(profileScore, 2); - + // http://www.webmproject.org/docs/encoder-parameters/ - param = string.Format("-speed 16 -quality good -profile:v {0} -slices 8 -crf {1}", + param = string.Format("-speed 16 -quality good -profile:v {0} -slices 8 -crf {1} -qmin {2} -qmax {3}", profileScore.ToString(UsCulture), - crf); + crf, + qmin, + qmax); } else if (string.Equals(videoCodec, "mpeg4", StringComparison.OrdinalIgnoreCase)) @@ -789,7 +793,7 @@ namespace MediaBrowser.Api.Playback { if (state.RunTimeTicks.Value >= TimeSpan.FromMinutes(5).Ticks && state.IsInputVideo) { - var url = "http://localhost:8096/mediabrowser/videos/" + state.Request.Id + "/stream?static=true&Throttle=true&mediaSourceId=" + state.Request.MediaSourceId; + var url = "http://localhost:" + ServerConfigurationManager.Configuration.HttpServerPortNumber.ToString(UsCulture) + "/mediabrowser/videos/" + state.Request.Id + "/stream?static=true&Throttle=true&mediaSourceId=" + state.Request.MediaSourceId; return string.Format("\"{0}\"", url); } diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs index 0d90e37395..2e9b9d36fe 100644 --- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs @@ -10,7 +10,6 @@ using ServiceStack; using System; using System.IO; using System.Linq; -using System.Threading; using System.Threading.Tasks; namespace MediaBrowser.Api.Playback.Hls @@ -79,14 +78,6 @@ namespace MediaBrowser.Api.Playback.Hls return ResultFactory.GetStaticFileResult(Request, file); } - protected override bool SupportsThrottling - { - get - { - return false; - } - } - /// /// Called when [begin request]. /// diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index d8255bd290..997cc7ca4b 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs @@ -7,6 +7,7 @@ using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Controller.Net; using MediaBrowser.Model.IO; using MediaBrowser.Model.MediaInfo; using ServiceStack.Web; @@ -26,7 +27,8 @@ namespace MediaBrowser.Api.Playback.Progressive protected readonly IImageProcessor ImageProcessor; protected readonly IHttpClient HttpClient; - protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder) + protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IImageProcessor imageProcessor, IHttpClient httpClient) + : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder) { ImageProcessor = imageProcessor; HttpClient = httpClient; @@ -52,23 +54,23 @@ namespace MediaBrowser.Api.Playback.Progressive if (isVideoRequest) { var videoCodec = state.VideoRequest.VideoCodec; - - if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase)) - { - return ".ts"; - } - if (string.Equals(videoCodec, "theora", StringComparison.OrdinalIgnoreCase)) - { - return ".ogv"; - } - if (string.Equals(videoCodec, "vpx", StringComparison.OrdinalIgnoreCase)) - { - return ".webm"; - } - if (string.Equals(videoCodec, "wmv", StringComparison.OrdinalIgnoreCase)) - { - return ".asf"; - } + + if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase)) + { + return ".ts"; + } + if (string.Equals(videoCodec, "theora", StringComparison.OrdinalIgnoreCase)) + { + return ".ogv"; + } + if (string.Equals(videoCodec, "vpx", StringComparison.OrdinalIgnoreCase)) + { + return ".webm"; + } + if (string.Equals(videoCodec, "wmv", StringComparison.OrdinalIgnoreCase)) + { + return ".asf"; + } } // Try to infer based on the desired audio codec @@ -153,7 +155,20 @@ namespace MediaBrowser.Api.Playback.Progressive { var throttleLimit = state.InputBitrate.HasValue ? (state.InputBitrate.Value / 8) : 0; - return ResultFactory.GetStaticFileResult(Request, state.MediaPath, contentType, null, FileShare.Read, responseHeaders, isHeadRequest, request.Throttle, throttleLimit); + return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions + { + ResponseHeaders = responseHeaders, + ContentType = contentType, + IsHeadRequest = isHeadRequest, + Path = state.MediaPath, + Throttle = request.Throttle, + + // Pad by 20% to play it safe + ThrottleLimit = Convert.ToInt64(1.2 * throttleLimit), + + // Three minutes + MinThrottlePosition = throttleLimit * 180 + }); } } @@ -164,7 +179,13 @@ namespace MediaBrowser.Api.Playback.Progressive try { - return ResultFactory.GetStaticFileResult(Request, outputPath, contentType, null, FileShare.Read, responseHeaders, isHeadRequest); + return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions + { + ResponseHeaders = responseHeaders, + ContentType = contentType, + IsHeadRequest = isHeadRequest, + Path = outputPath + }); } finally { diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index b13403bbf8..25d41565ae 100644 --- a/MediaBrowser.Controller/Entities/Audio/Audio.cs +++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs @@ -38,6 +38,7 @@ namespace MediaBrowser.Controller.Entities.Audio Tags = new List(); } + [IgnoreDataMember] public override bool SupportsAddingToPlaylist { get { return LocationType == LocationType.FileSystem && RunTimeTicks.HasValue; } @@ -118,6 +119,7 @@ namespace MediaBrowser.Controller.Entities.Audio /// Gets the type of the media. /// /// The type of the media. + [IgnoreDataMember] public override string MediaType { get diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 2eeec9715a..dc9f83b3c9 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -22,6 +22,7 @@ namespace MediaBrowser.Controller.Entities.Audio AlbumArtists = new List(); } + [IgnoreDataMember] public override bool SupportsAddingToPlaylist { get { return true; } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index de527b68b3..070572b9b2 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.Progress; +using System.Runtime.Serialization; +using MediaBrowser.Common.Progress; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; @@ -26,6 +27,7 @@ namespace MediaBrowser.Controller.Entities.Audio } } + [IgnoreDataMember] public override bool SupportsAddingToPlaylist { get { return true; } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs index f1dc56ac68..928eb64630 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; namespace MediaBrowser.Controller.Entities.Audio { @@ -18,6 +19,7 @@ namespace MediaBrowser.Controller.Entities.Audio return "MusicGenre-" + Name; } + [IgnoreDataMember] public override bool SupportsAddingToPlaylist { get { return true; } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index fd7a33ddf4..26b28ec72b 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -53,6 +53,7 @@ namespace MediaBrowser.Controller.Entities public List ImageInfos { get; set; } + [IgnoreDataMember] public virtual bool SupportsAddingToPlaylist { get @@ -192,6 +193,7 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] public virtual bool SupportsLocalMetadata { get diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs index 1f38de9a31..367db5dcb5 100644 --- a/MediaBrowser.Controller/Entities/Photo.cs +++ b/MediaBrowser.Controller/Entities/Photo.cs @@ -17,6 +17,7 @@ namespace MediaBrowser.Controller.Entities Taglines = new List(); } + [IgnoreDataMember] public override bool SupportsLocalMetadata { get @@ -25,6 +26,7 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] public override string MediaType { get @@ -35,6 +37,16 @@ namespace MediaBrowser.Controller.Entities [IgnoreDataMember] public override Folder LatestItemsIndexContainer + { + get + { + return Album; + } + } + + + [IgnoreDataMember] + public PhotoAlbum Album { get { @@ -53,6 +65,11 @@ namespace MediaBrowser.Controller.Entities public double? Aperture { get; set; } public double? ShutterSpeed { get; set; } + public double? Latitude { get; set; } + public double? Longitude { get; set; } + public double? Altitude { get; set; } + public int? IsoSpeedRating { get; set; } + protected override bool GetBlockUnratedValue(UserConfiguration config) { return config.BlockUnratedItems.Contains(UnratedItem.Other); diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index b82a400fe8..6804b29b73 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -29,6 +29,7 @@ namespace MediaBrowser.Controller.Entities.TV } } + [IgnoreDataMember] public override bool SupportsAddingToPlaylist { get { return true; } diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 856ed4fdf2..d3b95eb0c6 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -39,6 +39,7 @@ namespace MediaBrowser.Controller.Entities.TV DisplaySpecialsWithSeasons = true; } + [IgnoreDataMember] public override bool SupportsAddingToPlaylist { get { return true; } diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index ea530272dd..492a4a02f9 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -58,6 +58,7 @@ namespace MediaBrowser.Controller.Entities LinkedAlternateVersions = new List(); } + [IgnoreDataMember] public override bool SupportsAddingToPlaylist { get { return LocationType == LocationType.FileSystem && RunTimeTicks.HasValue; } @@ -238,6 +239,7 @@ namespace MediaBrowser.Controller.Entities /// Gets the type of the media. /// /// The type of the media. + [IgnoreDataMember] public override string MediaType { get diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index aeeaae073b..6a78fa5d9f 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -214,6 +214,7 @@ + diff --git a/MediaBrowser.Controller/Net/IHttpResultFactory.cs b/MediaBrowser.Controller/Net/IHttpResultFactory.cs index f0cfbbcfae..526bf4be2e 100644 --- a/MediaBrowser.Controller/Net/IHttpResultFactory.cs +++ b/MediaBrowser.Controller/Net/IHttpResultFactory.cs @@ -1,8 +1,8 @@ -using System; +using ServiceStack.Web; +using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; -using ServiceStack.Web; namespace MediaBrowser.Controller.Net { @@ -89,47 +89,29 @@ namespace MediaBrowser.Controller.Net bool isHeadRequest = false); /// - /// Gets the static file result. + /// Gets the static result. /// /// The request context. - /// The path. - /// The file share. - /// The response headers. - /// if set to true [is head request]. + /// The options. /// System.Object. - object GetStaticFileResult(IRequest requestContext, string path, FileShare fileShare = FileShare.Read, IDictionary responseHeaders = null, bool isHeadRequest = false); + object GetStaticResult(IRequest requestContext, StaticResultOptions options); /// /// Gets the static file result. /// /// The request context. /// The path. - /// Type of the content. - /// The cache curation. /// The file share. - /// The response headers. - /// if set to true [is head request]. - /// if set to true [throttle]. - /// The throttle limit. /// System.Object. - object GetStaticFileResult(IRequest requestContext, - string path, - string contentType, - TimeSpan? cacheCuration = null, - FileShare fileShare = FileShare.Read, - IDictionary responseHeaders = null, - bool isHeadRequest = false, - bool throttle = false, - long throttleLimit = 0); - + object GetStaticFileResult(IRequest requestContext, string path, FileShare fileShare = FileShare.Read); + /// - /// Gets the optimized serialized result using cache. + /// Gets the static file result. /// - /// - /// The request. - /// The result. + /// The request context. + /// The options. /// System.Object. - object GetOptimizedSerializedResultUsingCache(IRequest request, T result) - where T : class; + object GetStaticFileResult(IRequest requestContext, + StaticFileResultOptions options); } } diff --git a/MediaBrowser.Controller/Net/StaticResultOptions.cs b/MediaBrowser.Controller/Net/StaticResultOptions.cs new file mode 100644 index 0000000000..fde08c269d --- /dev/null +++ b/MediaBrowser.Controller/Net/StaticResultOptions.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +namespace MediaBrowser.Controller.Net +{ + public class StaticResultOptions + { + public string ContentType { get; set; } + public TimeSpan? CacheDuration { get; set; } + public DateTime? DateLastModified { get; set; } + public Guid CacheKey { get; set; } + + public Func> ContentFactory { get; set; } + + public bool IsHeadRequest { get; set; } + + public IDictionary ResponseHeaders { get; set; } + + public bool Throttle { get; set; } + public long ThrottleLimit { get; set; } + public long MinThrottlePosition { get; set; } + + public StaticResultOptions() + { + ResponseHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + } + + public class StaticFileResultOptions : StaticResultOptions + { + public string Path { get; set; } + + public FileShare FileShare { get; set; } + + public StaticFileResultOptions() + { + FileShare = FileShare.Read; + } + } +} diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index df22b5e1f7..87d706a16a 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -201,7 +201,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles // Extract var outputPath = GetSubtitleCachePath(mediaPath, subtitleStream.Index, "." + extractedFormat); - await ExtractTextSubtitle(inputFiles, protocol, subtitleStream.Index, false, outputPath, cancellationToken) + await ExtractTextSubtitle(inputFiles, protocol, subtitleStream.Index, "srt", outputPath, cancellationToken) .ConfigureAwait(false); return new Tuple(outputPath, extractedFormat); @@ -477,13 +477,13 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// The input files. /// The protocol. /// Index of the subtitle stream. - /// if set to true, copy stream instead of converting. + /// The output codec. /// The output path. /// The cancellation token. /// Task. /// Must use inputPath list overload private async Task ExtractTextSubtitle(string[] inputFiles, MediaProtocol protocol, int subtitleStreamIndex, - bool copySubtitleStream, string outputPath, CancellationToken cancellationToken) + string outputCodec, string outputPath, CancellationToken cancellationToken) { var semaphore = GetLock(outputPath); @@ -494,7 +494,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles if (!File.Exists(outputPath)) { await ExtractTextSubtitleInternal(_mediaEncoder.GetInputArgument(inputFiles, protocol), subtitleStreamIndex, - copySubtitleStream, outputPath, cancellationToken).ConfigureAwait(false); + outputCodec, outputPath, cancellationToken).ConfigureAwait(false); } } finally @@ -503,23 +503,8 @@ namespace MediaBrowser.MediaEncoding.Subtitles } } - /// - /// 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) + string outputCodec, string outputPath, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(inputPath)) { @@ -533,14 +518,8 @@ namespace MediaBrowser.MediaEncoding.Subtitles Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); - var processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s srt \"{2}\"", inputPath, - subtitleStreamIndex, outputPath); - - if (copySubtitleStream) - { - processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s copy \"{2}\"", inputPath, - subtitleStreamIndex, outputPath); - } + var processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s {2} \"{3}\"", inputPath, + subtitleStreamIndex, outputCodec, outputPath); var process = new Process { diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index 360d2d8621..ec5a26eee1 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -732,7 +732,11 @@ namespace MediaBrowser.Model.Dto public ImageOrientation? ImageOrientation { get; set; } public double? Aperture { get; set; } public double? ShutterSpeed { get; set; } - + public double? Latitude { get; set; } + public double? Longitude { get; set; } + public double? Altitude { get; set; } + public int? IsoSpeedRating { get; set; } + /// /// Gets a value indicating whether this instance can resume. /// diff --git a/MediaBrowser.Providers/Photos/PhotoProvider.cs b/MediaBrowser.Providers/Photos/PhotoProvider.cs index 123c91d075..b298c62e74 100644 --- a/MediaBrowser.Providers/Photos/PhotoProvider.cs +++ b/MediaBrowser.Providers/Photos/PhotoProvider.cs @@ -123,6 +123,19 @@ namespace MediaBrowser.Providers.Photos item.ExposureTime = image.ImageTag.ExposureTime; item.FocalLength = image.ImageTag.FocalLength; + + item.Latitude = image.ImageTag.Latitude; + item.Longitude = image.ImageTag.Longitude; + item.Altitude = image.ImageTag.Altitude; + + if (image.ImageTag.ISOSpeedRatings.HasValue) + { + item.IsoSpeedRating = Convert.ToInt32(image.ImageTag.ISOSpeedRatings.Value); + } + else + { + item.IsoSpeedRating = null; + } } catch (Exception e) { @@ -145,7 +158,7 @@ namespace MediaBrowser.Providers.Photos public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date) { // Moved to plural AlbumArtists - if (date < new DateTime(2014, 8, 28)) + if (date < new DateTime(2014, 8, 29)) { // Revamped vaptured metadata return true; diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index 61517ce6ef..922287f6ee 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.IO; +using MediaBrowser.Common.IO; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Drawing; @@ -369,6 +368,19 @@ namespace MediaBrowser.Server.Implementations.Dto dto.ImageOrientation = item.Orientation; dto.Aperture = item.Aperture; dto.ShutterSpeed = item.ShutterSpeed; + + dto.Latitude = item.Latitude; + dto.Longitude = item.Longitude; + dto.Altitude = item.Altitude; + dto.IsoSpeedRating = item.IsoSpeedRating; + + var album = item.Album; + + if (album != null) + { + dto.Album = item.Name; + dto.AlbumId = item.Id.ToString("N"); + } } private void SetMusicVideoProperties(BaseItemDto dto, MusicVideo item) diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs index be3e5f0051..9997cfbdb0 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -289,41 +289,28 @@ namespace MediaBrowser.Server.Implementations.HttpServer return null; } - /// - /// Gets the static file result. - /// - /// The request context. - /// The path. - /// The file share. - /// The response headers. - /// if set to true [is head request]. - /// System.Object. - /// path - /// path public object GetStaticFileResult(IRequest requestContext, string path, - FileShare fileShare = FileShare.Read, - IDictionary responseHeaders = null, - bool isHeadRequest = false) + FileShare fileShare = FileShare.Read) { if (string.IsNullOrEmpty(path)) { throw new ArgumentNullException("path"); } - return GetStaticFileResult(requestContext, path, MimeTypes.GetMimeType(path), null, fileShare, responseHeaders, isHeadRequest); + return GetStaticFileResult(requestContext, new StaticFileResultOptions + { + Path = path, + FileShare = fileShare + }); } public object GetStaticFileResult(IRequest requestContext, - string path, - string contentType, - TimeSpan? cacheCuration = null, - FileShare fileShare = FileShare.Read, - IDictionary responseHeaders = null, - bool isHeadRequest = false, - bool throttle = false, - long throttleLimit = 0) + StaticFileResultOptions options) { + var path = options.Path; + var fileShare = options.FileShare; + if (string.IsNullOrEmpty(path)) { throw new ArgumentNullException("path"); @@ -334,11 +321,18 @@ namespace MediaBrowser.Server.Implementations.HttpServer throw new ArgumentException("FileShare must be either Read or ReadWrite"); } - var dateModified = _fileSystem.GetLastWriteTimeUtc(path); + if (string.IsNullOrWhiteSpace(options.ContentType)) + { + options.ContentType = MimeTypes.GetMimeType(path); + } - var cacheKey = path + dateModified.Ticks; + options.DateLastModified = _fileSystem.GetLastWriteTimeUtc(path); + var cacheKey = path + options.DateLastModified.Value.Ticks; - return GetStaticResult(requestContext, cacheKey.GetMD5(), dateModified, cacheCuration, contentType, () => Task.FromResult(GetFileStream(path, fileShare)), responseHeaders, isHeadRequest, throttle, throttleLimit); + options.CacheKey = cacheKey.GetMD5(); + options.ContentFactory = () => Task.FromResult(GetFileStream(path, fileShare)); + + return GetStaticResult(requestContext, options); } /// @@ -352,21 +346,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer return _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, fileShare, true); } - /// - /// Gets the static result. - /// - /// The request context. - /// The cache key. - /// The last date modified. - /// Duration of the cache. - /// Type of the content. - /// The factory fn. - /// The response headers. - /// if set to true [is head request]. - /// System.Object. - /// cacheKey - /// or - /// factoryFn public object GetStaticResult(IRequest requestContext, Guid cacheKey, DateTime? lastDateModified, @@ -376,39 +355,37 @@ namespace MediaBrowser.Server.Implementations.HttpServer IDictionary responseHeaders = null, bool isHeadRequest = false) { - return GetStaticResult(requestContext, cacheKey, lastDateModified, cacheDuration, contentType, factoryFn, - responseHeaders, isHeadRequest, false, 0); + return GetStaticResult(requestContext, new StaticResultOptions + { + CacheDuration = cacheDuration, + CacheKey = cacheKey, + ContentFactory = factoryFn, + ContentType = contentType, + DateLastModified = lastDateModified, + IsHeadRequest = isHeadRequest, + ResponseHeaders = responseHeaders + }); } - public object GetStaticResult(IRequest requestContext, - Guid cacheKey, - DateTime? lastDateModified, - TimeSpan? cacheDuration, - string contentType, - Func> factoryFn, - IDictionary responseHeaders = null, - bool isHeadRequest = false, - bool throttle = false, - long throttleLimit = 0) + public object GetStaticResult(IRequest requestContext, StaticResultOptions options) { + var cacheKey = options.CacheKey; + options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary(); + var contentType = options.ContentType; + if (cacheKey == Guid.Empty) { throw new ArgumentNullException("cacheKey"); } - if (factoryFn == null) + if (options.ContentFactory == null) { throw new ArgumentNullException("factoryFn"); } var key = cacheKey.ToString("N"); - if (responseHeaders == null) - { - responseHeaders = new Dictionary(); - } - // See if the result is already cached in the browser - var result = GetCachedResult(requestContext, responseHeaders, cacheKey, key, lastDateModified, cacheDuration, contentType); + var result = GetCachedResult(requestContext, options.ResponseHeaders, cacheKey, key, options.DateLastModified, options.CacheDuration, contentType); if (result != null) { @@ -416,8 +393,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer } var compress = ShouldCompressResponse(requestContext, contentType); - var hasOptions = GetStaticResult(requestContext, responseHeaders, contentType, factoryFn, compress, isHeadRequest, throttle, throttleLimit).Result; - AddResponseHeaders(hasOptions, responseHeaders); + var hasOptions = GetStaticResult(requestContext, options, compress).Result; + AddResponseHeaders(hasOptions, options.ResponseHeaders); return hasOptions; } @@ -473,20 +450,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - /// - /// Gets the static result. - /// - /// The request context. - /// The response headers. - /// Type of the content. - /// The factory fn. - /// if set to true [compress]. - /// if set to true [is head request]. - /// if set to true [throttle]. - /// The throttle limit. - /// Task{IHasOptions}. - private async Task GetStaticResult(IRequest requestContext, IDictionary responseHeaders, string contentType, Func> factoryFn, bool compress, bool isHeadRequest, bool throttle, long throttleLimit = 0) + private async Task GetStaticResult(IRequest requestContext, StaticResultOptions options, bool compress) { + var isHeadRequest = options.IsHeadRequest; + var factoryFn = options.ContentFactory; + var contentType = options.ContentType; + var responseHeaders = options.ResponseHeaders; + var requestedCompressionType = requestContext.GetCompressionType(); if (!compress || string.IsNullOrEmpty(requestedCompressionType)) @@ -499,8 +469,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer { return new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest) { - Throttle = throttle, - ThrottleLimit = throttleLimit + Throttle = options.Throttle, + ThrottleLimit = options.ThrottleLimit, + MinThrottlePosition = options.MinThrottlePosition }; } @@ -515,8 +486,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer return new StreamWriter(stream, contentType, _logger) { - Throttle = throttle, - ThrottleLimit = throttleLimit + Throttle = options.Throttle, + ThrottleLimit = options.ThrottleLimit, + MinThrottlePosition = options.MinThrottlePosition }; } @@ -746,14 +718,5 @@ namespace MediaBrowser.Server.Implementations.HttpServer throw error; } - - public object GetOptimizedSerializedResultUsingCache(IRequest request, T result) - where T : class - { - var json = _jsonSerializer.SerializeToString(result); - var cacheKey = json.GetMD5(); - - return GetOptimizedResultUsingCache(request, cacheKey, null, null, () => result); - } } } \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs index 5fd43aa76b..657545069a 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs @@ -26,6 +26,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer public bool Throttle { get; set; } public long ThrottleLimit { get; set; } + public long MinThrottlePosition; /// /// The _options @@ -166,7 +167,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer { responseStream = new ThrottledStream(responseStream, ThrottleLimit) { - MinThrottlePosition = ThrottleLimit * 180 + MinThrottlePosition = MinThrottlePosition }; } var task = WriteToAsync(responseStream); diff --git a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs index f1112ae0b3..28fc094f7d 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs @@ -38,7 +38,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer public bool Throttle { get; set; } public long ThrottleLimit { get; set; } - + public long MinThrottlePosition; + /// /// Initializes a new instance of the class. /// @@ -84,7 +85,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer { responseStream = new ThrottledStream(responseStream, ThrottleLimit) { - MinThrottlePosition = ThrottleLimit * 180 + MinThrottlePosition = MinThrottlePosition }; } var task = WriteToAsync(responseStream); -- cgit v1.2.3 From 9d36f518182bc075c19d78084870f5115fa62d1e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 30 Aug 2014 11:12:28 -0400 Subject: adjust subtitle extraction --- .../Subtitles/SubtitleEncoder.cs | 35 +++++++++++++++++----- 1 file changed, 28 insertions(+), 7 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 87d706a16a..7a3a7d2d0c 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -194,17 +194,38 @@ namespace MediaBrowser.MediaEncoding.Subtitles MediaStream subtitleStream, CancellationToken cancellationToken) { - const string extractedFormat = "srt"; - if (!subtitleStream.IsExternal) { + string outputFormat; + string outputCodec; + + if (string.Equals(subtitleStream.Codec, "ass", StringComparison.OrdinalIgnoreCase)) + { + // Extract + outputCodec = "copy"; + outputFormat = "ass"; + } + else if (string.Equals(subtitleStream.Codec, "subrip", StringComparison.OrdinalIgnoreCase) || + string.Equals(subtitleStream.Codec, "srt", StringComparison.OrdinalIgnoreCase)) + { + // Extract + outputCodec = "copy"; + outputFormat = "srt"; + } + else + { + // Extract + outputCodec = "srt"; + outputFormat = "srt"; + } + // Extract - var outputPath = GetSubtitleCachePath(mediaPath, subtitleStream.Index, "." + extractedFormat); + var outputPath = GetSubtitleCachePath(mediaPath, subtitleStream.Index, "." + outputFormat); - await ExtractTextSubtitle(inputFiles, protocol, subtitleStream.Index, "srt", outputPath, cancellationToken) + await ExtractTextSubtitle(inputFiles, protocol, subtitleStream.Index, outputCodec, outputPath, cancellationToken) .ConfigureAwait(false); - return new Tuple(outputPath, extractedFormat); + return new Tuple(outputPath, outputFormat); } var currentFormat = (Path.GetExtension(subtitleStream.Path) ?? subtitleStream.Codec) @@ -213,12 +234,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles if (GetReader(currentFormat, false) == null) { // Convert - var outputPath = GetSubtitleCachePath(mediaPath, subtitleStream.Index, "." + extractedFormat); + var outputPath = GetSubtitleCachePath(mediaPath, subtitleStream.Index, ".srt"); await ConvertTextSubtitleToSrt(subtitleStream.Path, outputPath, subtitleStream.Language, cancellationToken) .ConfigureAwait(false); - return new Tuple(outputPath, extractedFormat); + return new Tuple(outputPath, "srt"); } return new Tuple(subtitleStream.Path, currentFormat); -- cgit v1.2.3