diff --git a/MediaBrowser.Controller/Providers/MediaInfo/BaseFFProbeProvider.cs b/MediaBrowser.Controller/Providers/MediaInfo/BaseFFProbeProvider.cs
index bc8052f0e..7c977d02f 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 9dec93a8c..bc851a0cb 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";
-
- var path = Kernel.Instance.FFMpegManager.VideoImageCache.GetResourcePath(filename, ".jpg");
-
- if (!Kernel.Instance.FFMpegManager.VideoImageCache.ContainsFilePath(path))
+ // 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))
{
- return ExtractImage(video, path, cancellationToken);
- }
+ var filename = item.Id + "_" + item.DateModified.Ticks + "_primary";
- // Image is already in the cache
- item.PrimaryImagePath = path;
+ var path = Kernel.Instance.FFMpegManager.VideoImageCache.GetResourcePath(filename, ".jpg");
+
+ if (!Kernel.Instance.FFMpegManager.VideoImageCache.ContainsFilePath(path))
+ {
+ return ExtractImage(video, path, cancellationToken);
+ }
+
+ // 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 a7cc4985b..8390a0cee 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 cae74a910..a2a9fa0d1 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))
{
- // 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;
- }
+ video.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.format.duration, UsCulture)).Ticks;
}
+ }
- if (data.streams != null)
- {
- video.MediaStreams = data.streams.Select(s => GetMediaStream(s, data.format)).ToList();
- }
+ if (data.streams != null)
+ {
+ video.MediaStreams = data.streams.Select(s => GetMediaStream(s, data.format)).ToList();
+ }
- if (data.Chapters != null)
- {
- video.Chapters = data.Chapters;
- }
+ if (data.Chapters != null)
+ {
+ video.Chapters = data.Chapters;
+ }
- if (video.Chapters == null || video.Chapters.Count == 0)
- {
- AddDummyChapters(video);
- }
+ 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);
- }
+ 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 dced1ce28..c34f8a1ba 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 376cf5065..e722ac3dc 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 2c8d7f437..b2e11d06f 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 812c98789..f55b13d19 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();
+
+ var serialized = _jsonSerializer.SerializeToBytes(user);
+
+ 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);
+
+ using (var tran = connection.BeginTransaction())
{
- cancellationToken.ThrowIfCancellationRequested();
+ try
+ {
+ cmd.Transaction = tran;
- var serialized = _jsonSerializer.SerializeToBytes(user);
+ await cmd.ExecuteNonQueryAsync(cancellationToken);
- 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);
- });
+ 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 7fef4935d..90de11976 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);