From 9c7f492e2cd3b940d8041e6949cea9898a057826 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 5 Apr 2013 21:03:38 -0400 Subject: [PATCH] fixed an issue with the video image provider requiring two-pass refreshing --- .../MediaInfo/BaseFFProbeProvider.cs | 4 +- .../MediaInfo/FFMpegVideoImageProvider.cs | 26 ++++----- .../MediaInfo/FFProbeAudioInfoProvider.cs | 51 ++++++++--------- .../MediaInfo/FFProbeVideoInfoProvider.cs | 55 +++++++++---------- .../Providers/ProviderManager.cs | 2 +- .../Sqlite/SQLiteRepository.cs | 2 +- .../Sqlite/SQLiteUserDataRepository.cs | 51 +++++++++++++---- .../Sqlite/SQLiteUserRepository.cs | 53 ++++++++++++++---- .../ApplicationHost.cs | 2 +- 9 files changed, 148 insertions(+), 98 deletions(-) diff --git a/MediaBrowser.Controller/Providers/MediaInfo/BaseFFProbeProvider.cs b/MediaBrowser.Controller/Providers/MediaInfo/BaseFFProbeProvider.cs index bc8052f0eb..7c977d02f7 100644 --- a/MediaBrowser.Controller/Providers/MediaInfo/BaseFFProbeProvider.cs +++ b/MediaBrowser.Controller/Providers/MediaInfo/BaseFFProbeProvider.cs @@ -93,7 +93,7 @@ namespace MediaBrowser.Controller.Providers.MediaInfo cancellationToken.ThrowIfCancellationRequested(); - await Fetch(myItem, cancellationToken, result, isoMount).ConfigureAwait(false); + Fetch(myItem, cancellationToken, result, isoMount); cancellationToken.ThrowIfCancellationRequested(); @@ -180,7 +180,7 @@ namespace MediaBrowser.Controller.Providers.MediaInfo /// The result. /// The iso mount. /// Task. - protected abstract Task Fetch(T item, CancellationToken cancellationToken, FFProbeResult result, IIsoMount isoMount); + protected abstract void Fetch(T item, CancellationToken cancellationToken, FFProbeResult result, IIsoMount isoMount); /// /// Converts ffprobe stream info to our MediaStream class diff --git a/MediaBrowser.Controller/Providers/MediaInfo/FFMpegVideoImageProvider.cs b/MediaBrowser.Controller/Providers/MediaInfo/FFMpegVideoImageProvider.cs index 9dec93a8c8..bc851a0cba 100644 --- a/MediaBrowser.Controller/Providers/MediaInfo/FFMpegVideoImageProvider.cs +++ b/MediaBrowser.Controller/Providers/MediaInfo/FFMpegVideoImageProvider.cs @@ -57,12 +57,6 @@ namespace MediaBrowser.Controller.Providers.MediaInfo if (video != null) { - // Can't extract images if there are no video streams - if (video.MediaStreams == null || video.MediaStreams.All(m => m.Type != MediaStreamType.Video)) - { - return false; - } - if (video.VideoType == VideoType.Iso && video.IsoType.HasValue && _isoManager.CanMount(item.Path)) { return true; @@ -93,17 +87,21 @@ namespace MediaBrowser.Controller.Providers.MediaInfo { var video = (Video)item; - var filename = item.Id + "_" + item.DateModified.Ticks + "_primary"; + // We can only extract images from videos if we know there's an embedded video stream + if (video.MediaStreams != null && video.MediaStreams.Any(m => m.Type == MediaStreamType.Video)) + { + var filename = item.Id + "_" + item.DateModified.Ticks + "_primary"; - var path = Kernel.Instance.FFMpegManager.VideoImageCache.GetResourcePath(filename, ".jpg"); + var path = Kernel.Instance.FFMpegManager.VideoImageCache.GetResourcePath(filename, ".jpg"); - if (!Kernel.Instance.FFMpegManager.VideoImageCache.ContainsFilePath(path)) - { - return ExtractImage(video, path, cancellationToken); - } + if (!Kernel.Instance.FFMpegManager.VideoImageCache.ContainsFilePath(path)) + { + return ExtractImage(video, path, cancellationToken); + } - // Image is already in the cache - item.PrimaryImagePath = path; + // Image is already in the cache + item.PrimaryImagePath = path; + } } SetLastRefreshed(item, DateTime.UtcNow); diff --git a/MediaBrowser.Controller/Providers/MediaInfo/FFProbeAudioInfoProvider.cs b/MediaBrowser.Controller/Providers/MediaInfo/FFProbeAudioInfoProvider.cs index a7cc4985b0..8390a0ceeb 100644 --- a/MediaBrowser.Controller/Providers/MediaInfo/FFProbeAudioInfoProvider.cs +++ b/MediaBrowser.Controller/Providers/MediaInfo/FFProbeAudioInfoProvider.cs @@ -42,41 +42,38 @@ namespace MediaBrowser.Controller.Providers.MediaInfo /// The data. /// The iso mount. /// Task. - protected override Task Fetch(Audio audio, CancellationToken cancellationToken, FFProbeResult data, IIsoMount isoMount) + protected override void Fetch(Audio audio, CancellationToken cancellationToken, FFProbeResult data, IIsoMount isoMount) { - return Task.Run(() => + if (data.streams == null) { - if (data.streams == null) - { - Logger.Error("Audio item has no streams: " + audio.Path); - return; - } + Logger.Error("Audio item has no streams: " + audio.Path); + return; + } - audio.MediaStreams = data.streams.Select(s => GetMediaStream(s, data.format)).ToList(); + audio.MediaStreams = data.streams.Select(s => GetMediaStream(s, data.format)).ToList(); - // Get the first audio stream - var stream = data.streams.First(s => s.codec_type.Equals("audio", StringComparison.OrdinalIgnoreCase)); + // Get the first audio stream + var stream = data.streams.First(s => s.codec_type.Equals("audio", StringComparison.OrdinalIgnoreCase)); - // Get duration from stream properties - var duration = stream.duration; + // Get duration from stream properties + var duration = stream.duration; - // If it's not there go into format properties - if (string.IsNullOrEmpty(duration)) - { - duration = data.format.duration; - } + // If it's not there go into format properties + if (string.IsNullOrEmpty(duration)) + { + duration = data.format.duration; + } - // If we got something, parse it - if (!string.IsNullOrEmpty(duration)) - { - audio.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(duration, UsCulture)).Ticks; - } + // If we got something, parse it + if (!string.IsNullOrEmpty(duration)) + { + audio.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(duration, UsCulture)).Ticks; + } - if (data.format.tags != null) - { - FetchDataFromTags(audio, data.format.tags); - } - }); + if (data.format.tags != null) + { + FetchDataFromTags(audio, data.format.tags); + } } /// diff --git a/MediaBrowser.Controller/Providers/MediaInfo/FFProbeVideoInfoProvider.cs b/MediaBrowser.Controller/Providers/MediaInfo/FFProbeVideoInfoProvider.cs index cae74a910b..a2a9fa0d14 100644 --- a/MediaBrowser.Controller/Providers/MediaInfo/FFProbeVideoInfoProvider.cs +++ b/MediaBrowser.Controller/Providers/MediaInfo/FFProbeVideoInfoProvider.cs @@ -187,44 +187,41 @@ namespace MediaBrowser.Controller.Providers.MediaInfo /// The data. /// The iso mount. /// Task. - protected override Task Fetch(Video video, CancellationToken cancellationToken, FFProbeResult data, IIsoMount isoMount) + protected override void Fetch(Video video, CancellationToken cancellationToken, FFProbeResult data, IIsoMount isoMount) { - return Task.Run(() => + if (data.format != null) { - if (data.format != null) - { - // For dvd's this may not always be accurate, so don't set the runtime if the item already has one - var needToSetRuntime = video.VideoType != VideoType.Dvd || video.RunTimeTicks == null || video.RunTimeTicks.Value == 0; - - if (needToSetRuntime && !string.IsNullOrEmpty(data.format.duration)) - { - video.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.format.duration, UsCulture)).Ticks; - } - } + // For dvd's this may not always be accurate, so don't set the runtime if the item already has one + var needToSetRuntime = video.VideoType != VideoType.Dvd || video.RunTimeTicks == null || video.RunTimeTicks.Value == 0; - if (data.streams != null) + if (needToSetRuntime && !string.IsNullOrEmpty(data.format.duration)) { - video.MediaStreams = data.streams.Select(s => GetMediaStream(s, data.format)).ToList(); + video.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.format.duration, UsCulture)).Ticks; } + } - if (data.Chapters != null) - { - video.Chapters = data.Chapters; - } + if (data.streams != null) + { + video.MediaStreams = data.streams.Select(s => GetMediaStream(s, data.format)).ToList(); + } - if (video.Chapters == null || video.Chapters.Count == 0) - { - AddDummyChapters(video); - } + if (data.Chapters != null) + { + video.Chapters = data.Chapters; + } - if (video.VideoType == VideoType.BluRay || (video.IsoType.HasValue && video.IsoType.Value == IsoType.BluRay)) - { - var inputPath = isoMount != null ? isoMount.MountedPath : video.Path; - FetchBdInfo(video, inputPath, BdInfoCache, cancellationToken); - } + if (video.Chapters == null || video.Chapters.Count == 0) + { + AddDummyChapters(video); + } + + if (video.VideoType == VideoType.BluRay || (video.IsoType.HasValue && video.IsoType.Value == IsoType.BluRay)) + { + var inputPath = isoMount != null ? isoMount.MountedPath : video.Path; + FetchBdInfo(video, inputPath, BdInfoCache, cancellationToken); + } - AddExternalSubtitles(video); - }); + AddExternalSubtitles(video); } /// diff --git a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs index dced1ce28d..c34f8a1baf 100644 --- a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs +++ b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs @@ -104,7 +104,7 @@ namespace MediaBrowser.Server.Implementations.Providers /// The providers. public void AddMetadataProviders(IEnumerable providers) { - MetadataProviders = providers.ToArray(); + MetadataProviders = providers.OrderBy(e => e.Priority).ToArray(); } /// diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs index 376cf50657..e722ac3dc8 100644 --- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs +++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs @@ -30,7 +30,7 @@ namespace MediaBrowser.Server.Implementations.Sqlite /// /// The flush interval /// - private const int FlushInterval = 5000; + private const int FlushInterval = 2000; /// /// The flush timer diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs index 2c8d7f437f..b2e11d06f3 100644 --- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs +++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs @@ -34,6 +34,18 @@ namespace MediaBrowser.Server.Implementations.Sqlite } } + /// + /// Gets a value indicating whether [enable delayed commands]. + /// + /// true if [enable delayed commands]; otherwise, false. + protected override bool EnableDelayedCommands + { + get + { + return false; + } + } + /// /// The _protobuf serializer /// @@ -106,7 +118,7 @@ namespace MediaBrowser.Server.Implementations.Sqlite /// or /// userDataId /// - public Task SaveUserData(Guid userId, Guid userDataId, UserItemData userData, CancellationToken cancellationToken) + public async Task SaveUserData(Guid userId, Guid userDataId, UserItemData userData, CancellationToken cancellationToken) { if (userData == null) { @@ -127,19 +139,36 @@ namespace MediaBrowser.Server.Implementations.Sqlite cancellationToken.ThrowIfCancellationRequested(); - return Task.Run(() => + var serialized = _protobufSerializer.SerializeToBytes(userData); + + cancellationToken.ThrowIfCancellationRequested(); + + var cmd = connection.CreateCommand(); + cmd.CommandText = "replace into userdata (id, userId, data) values (@1, @2, @3)"; + cmd.AddParam("@1", userDataId); + cmd.AddParam("@2", userId); + cmd.AddParam("@3", serialized); + + using (var tran = connection.BeginTransaction()) { - var serialized = _protobufSerializer.SerializeToBytes(userData); + try + { + cmd.Transaction = tran; - cancellationToken.ThrowIfCancellationRequested(); + await cmd.ExecuteNonQueryAsync(cancellationToken); - var cmd = connection.CreateCommand(); - cmd.CommandText = "replace into userdata (id, userId, data) values (@1, @2, @3)"; - cmd.AddParam("@1", userDataId); - cmd.AddParam("@2", userId); - cmd.AddParam("@3", serialized); - QueueCommand(cmd); - }); + tran.Commit(); + } + catch (OperationCanceledException) + { + tran.Rollback(); + } + catch (Exception e) + { + Logger.ErrorException("Failed to commit transaction.", e); + tran.Rollback(); + } + } } /// diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserRepository.cs index 812c98789f..f55b13d196 100644 --- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserRepository.cs +++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserRepository.cs @@ -45,6 +45,18 @@ namespace MediaBrowser.Server.Implementations.Sqlite /// private readonly IApplicationPaths _appPaths; + /// + /// Gets a value indicating whether [enable delayed commands]. + /// + /// true if [enable delayed commands]; otherwise, false. + protected override bool EnableDelayedCommands + { + get + { + return false; + } + } + /// /// Initializes a new instance of the class. /// @@ -97,7 +109,7 @@ namespace MediaBrowser.Server.Implementations.Sqlite /// The cancellation token. /// Task. /// user - public Task SaveUser(User user, CancellationToken cancellationToken) + public async Task SaveUser(User user, CancellationToken cancellationToken) { if (user == null) { @@ -109,20 +121,37 @@ namespace MediaBrowser.Server.Implementations.Sqlite throw new ArgumentNullException("cancellationToken"); } - return Task.Run(() => - { - cancellationToken.ThrowIfCancellationRequested(); + cancellationToken.ThrowIfCancellationRequested(); - var serialized = _jsonSerializer.SerializeToBytes(user); + var serialized = _jsonSerializer.SerializeToBytes(user); - cancellationToken.ThrowIfCancellationRequested(); + cancellationToken.ThrowIfCancellationRequested(); - var cmd = connection.CreateCommand(); - cmd.CommandText = "replace into users (guid, data) values (@1, @2)"; - cmd.AddParam("@1", user.Id); - cmd.AddParam("@2", serialized); - QueueCommand(cmd); - }); + var cmd = connection.CreateCommand(); + cmd.CommandText = "replace into users (guid, data) values (@1, @2)"; + cmd.AddParam("@1", user.Id); + cmd.AddParam("@2", serialized); + + using (var tran = connection.BeginTransaction()) + { + try + { + cmd.Transaction = tran; + + await cmd.ExecuteNonQueryAsync(cancellationToken); + + tran.Commit(); + } + catch (OperationCanceledException) + { + tran.Rollback(); + } + catch (Exception e) + { + Logger.ErrorException("Failed to commit transaction.", e); + tran.Rollback(); + } + } } /// diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index 7fef4935d7..90de11976c 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -298,7 +298,7 @@ namespace MediaBrowser.ServerApplication () => LibraryManager.AddParts(GetExports(), GetExports(), GetExports(), GetExports(), GetExports()), - () => ProviderManager.AddMetadataProviders(GetExports().OrderBy(e => e.Priority).ToArray()) + () => ProviderManager.AddMetadataProviders(GetExports().ToArray()) ); UdpServer = new UdpServer(Logger, NetworkManager, ServerConfigurationManager);