aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs27
-rw-r--r--MediaBrowser.Controller/Trickplay/ITrickplayManager.cs77
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs2
-rw-r--r--MediaBrowser.Model/Configuration/TrickplayOptions.cs109
-rw-r--r--MediaBrowser.Model/Configuration/TrickplayScanBehavior.cs25
-rw-r--r--MediaBrowser.Model/Entities/TrickplayTilesInfo.cs79
-rw-r--r--MediaBrowser.Providers/Trickplay/TrickplayImagesTask.cs147
-rw-r--r--MediaBrowser.Providers/Trickplay/TrickplayManager.cs569
-rw-r--r--MediaBrowser.Providers/Trickplay/TrickplayProvider.cs181
9 files changed, 602 insertions, 614 deletions
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index bcdf2934a..01b6e31e9 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -90,6 +90,13 @@ namespace MediaBrowser.Controller.MediaEncoding
{ "truehd", 6 },
};
+ private static readonly string _defaultMjpegEncoder = "mjpeg";
+ private static readonly Dictionary<string, string> _mjpegCodecMap = new(StringComparer.OrdinalIgnoreCase)
+ {
+ { "vaapi", _defaultMjpegEncoder + "_vaapi" },
+ { "qsv", _defaultMjpegEncoder + "_qsv" }
+ };
+
public static readonly string[] LosslessAudioCodecs = new string[]
{
"alac",
@@ -151,32 +158,20 @@ namespace MediaBrowser.Controller.MediaEncoding
private string GetMjpegEncoder(EncodingJobInfo state, EncodingOptions encodingOptions)
{
- var defaultEncoder = "mjpeg";
-
if (state.VideoType == VideoType.VideoFile)
{
var hwType = encodingOptions.HardwareAccelerationType;
- var codecMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
- {
- { "vaapi", defaultEncoder + "_vaapi" },
- { "qsv", defaultEncoder + "_qsv" }
- };
-
if (!string.IsNullOrEmpty(hwType)
&& encodingOptions.EnableHardwareEncoding
- && codecMap.ContainsKey(hwType))
+ && _mjpegCodecMap.TryGetValue(hwType, out var preferredEncoder)
+ && _mediaEncoder.SupportsEncoder(preferredEncoder))
{
- var preferredEncoder = codecMap[hwType];
-
- if (_mediaEncoder.SupportsEncoder(preferredEncoder))
- {
- return preferredEncoder;
- }
+ return preferredEncoder;
}
}
- return defaultEncoder;
+ return _defaultMjpegEncoder;
}
private bool IsVaapiSupported(EncodingJobInfo state)
diff --git a/MediaBrowser.Controller/Trickplay/ITrickplayManager.cs b/MediaBrowser.Controller/Trickplay/ITrickplayManager.cs
index bae458f98..8e82c57d4 100644
--- a/MediaBrowser.Controller/Trickplay/ITrickplayManager.cs
+++ b/MediaBrowser.Controller/Trickplay/ITrickplayManager.cs
@@ -5,50 +5,49 @@ using System.Threading.Tasks;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Entities;
-namespace MediaBrowser.Controller.Trickplay
+namespace MediaBrowser.Controller.Trickplay;
+
+/// <summary>
+/// Interface ITrickplayManager.
+/// </summary>
+public interface ITrickplayManager
{
/// <summary>
- /// Interface ITrickplayManager.
+ /// Generate or replace trickplay data.
/// </summary>
- public interface ITrickplayManager
- {
- /// <summary>
- /// Generate or replace trickplay data.
- /// </summary>
- /// <param name="video">The video.</param>
- /// <param name="replace">Whether or not existing data should be replaced.</param>
- /// <param name="cancellationToken">CancellationToken to use for operation.</param>
- /// <returns>Task.</returns>
- Task RefreshTrickplayData(Video video, bool replace, CancellationToken cancellationToken);
+ /// <param name="video">The video.</param>
+ /// <param name="replace">Whether or not existing data should be replaced.</param>
+ /// <param name="cancellationToken">CancellationToken to use for operation.</param>
+ /// <returns>Task.</returns>
+ Task RefreshTrickplayDataAsync(Video video, bool replace, CancellationToken cancellationToken);
- /// <summary>
- /// Get available trickplay resolutions and corresponding info.
- /// </summary>
- /// <param name="itemId">The item.</param>
- /// <returns>Map of width resolutions to trickplay tiles info.</returns>
- Dictionary<int, TrickplayTilesInfo> GetTilesResolutions(Guid itemId);
+ /// <summary>
+ /// Get available trickplay resolutions and corresponding info.
+ /// </summary>
+ /// <param name="itemId">The item.</param>
+ /// <returns>Map of width resolutions to trickplay tiles info.</returns>
+ Dictionary<int, TrickplayTilesInfo> GetTilesResolutions(Guid itemId);
- /// <summary>
- /// Saves trickplay tiles info.
- /// </summary>
- /// <param name="itemId">The item.</param>
- /// <param name="tilesInfo">The trickplay tiles info.</param>
- void SaveTilesInfo(Guid itemId, TrickplayTilesInfo tilesInfo);
+ /// <summary>
+ /// Saves trickplay tiles info.
+ /// </summary>
+ /// <param name="itemId">The item.</param>
+ /// <param name="tilesInfo">The trickplay tiles info.</param>
+ void SaveTilesInfo(Guid itemId, TrickplayTilesInfo tilesInfo);
- /// <summary>
- /// Gets the trickplay manifest.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <returns>A map of media source id to a map of tile width to tile info.</returns>
- Dictionary<Guid, Dictionary<int, TrickplayTilesInfo>> GetTrickplayManifest(BaseItem item);
+ /// <summary>
+ /// Gets the trickplay manifest.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <returns>A map of media source id to a map of tile width to tile info.</returns>
+ Dictionary<Guid, Dictionary<int, TrickplayTilesInfo>> GetTrickplayManifest(BaseItem item);
- /// <summary>
- /// Gets the path to a trickplay tiles image.
- /// </summary>
- /// <param name="item">The item.</param>
- /// <param name="width">The width of a single tile.</param>
- /// <param name="index">The tile grid's index.</param>
- /// <returns>The absolute path.</returns>
- string GetTrickplayTilePath(BaseItem item, int width, int index);
- }
+ /// <summary>
+ /// Gets the path to a trickplay tiles image.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="width">The width of a single tile.</param>
+ /// <param name="index">The tile grid's index.</param>
+ /// <returns>The absolute path.</returns>
+ string GetTrickplayTilePath(BaseItem item, int width, int index);
}
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index 4692bf504..000831fe2 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -793,7 +793,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
CancellationToken cancellationToken)
{
var options = allowHwAccel ? _configurationManager.GetEncodingOptions() : new EncodingOptions();
- threads = threads ?? _threads;
+ threads ??= _threads;
// A new EncodingOptions instance must be used as to not disable HW acceleration for all of Jellyfin.
// Additionally, we must set a few fields without defaults to prevent null pointer exceptions.
diff --git a/MediaBrowser.Model/Configuration/TrickplayOptions.cs b/MediaBrowser.Model/Configuration/TrickplayOptions.cs
index d89e5f590..1fff1a5ed 100644
--- a/MediaBrowser.Model/Configuration/TrickplayOptions.cs
+++ b/MediaBrowser.Model/Configuration/TrickplayOptions.cs
@@ -1,61 +1,60 @@
using System.Collections.Generic;
using System.Diagnostics;
-namespace MediaBrowser.Model.Configuration
+namespace MediaBrowser.Model.Configuration;
+
+/// <summary>
+/// Class TrickplayOptions.
+/// </summary>
+public class TrickplayOptions
{
/// <summary>
- /// Class TrickplayOptions.
- /// </summary>
- public class TrickplayOptions
- {
- /// <summary>
- /// Gets or sets a value indicating whether or not to use HW acceleration.
- /// </summary>
- public bool EnableHwAcceleration { get; set; } = false;
-
- /// <summary>
- /// Gets or sets the behavior used by trickplay provider on library scan/update.
- /// </summary>
- public TrickplayScanBehavior ScanBehavior { get; set; } = TrickplayScanBehavior.NonBlocking;
-
- /// <summary>
- /// Gets or sets the process priority for the ffmpeg process.
- /// </summary>
- public ProcessPriorityClass ProcessPriority { get; set; } = ProcessPriorityClass.BelowNormal;
-
- /// <summary>
- /// Gets or sets the interval, in ms, between each new trickplay image.
- /// </summary>
- public int Interval { get; set; } = 10000;
-
- /// <summary>
- /// Gets or sets the target width resolutions, in px, to generates preview images for.
- /// </summary>
- public int[] WidthResolutions { get; set; } = new[] { 320 };
-
- /// <summary>
- /// Gets or sets number of tile images to allow in X dimension.
- /// </summary>
- public int TileWidth { get; set; } = 10;
-
- /// <summary>
- /// Gets or sets number of tile images to allow in Y dimension.
- /// </summary>
- public int TileHeight { get; set; } = 10;
-
- /// <summary>
- /// Gets or sets the ffmpeg output quality level.
- /// </summary>
- public int Qscale { get; set; } = 4;
-
- /// <summary>
- /// Gets or sets the jpeg quality to use for image tiles.
- /// </summary>
- public int JpegQuality { get; set; } = 90;
-
- /// <summary>
- /// Gets or sets the number of threads to be used by ffmpeg.
- /// </summary>
- public int ProcessThreads { get; set; } = 0;
- }
+ /// Gets or sets a value indicating whether or not to use HW acceleration.
+ /// </summary>
+ public bool EnableHwAcceleration { get; set; } = false;
+
+ /// <summary>
+ /// Gets or sets the behavior used by trickplay provider on library scan/update.
+ /// </summary>
+ public TrickplayScanBehavior ScanBehavior { get; set; } = TrickplayScanBehavior.NonBlocking;
+
+ /// <summary>
+ /// Gets or sets the process priority for the ffmpeg process.
+ /// </summary>
+ public ProcessPriorityClass ProcessPriority { get; set; } = ProcessPriorityClass.BelowNormal;
+
+ /// <summary>
+ /// Gets or sets the interval, in ms, between each new trickplay image.
+ /// </summary>
+ public int Interval { get; set; } = 10000;
+
+ /// <summary>
+ /// Gets or sets the target width resolutions, in px, to generates preview images for.
+ /// </summary>
+ public int[] WidthResolutions { get; set; } = new[] { 320 };
+
+ /// <summary>
+ /// Gets or sets number of tile images to allow in X dimension.
+ /// </summary>
+ public int TileWidth { get; set; } = 10;
+
+ /// <summary>
+ /// Gets or sets number of tile images to allow in Y dimension.
+ /// </summary>
+ public int TileHeight { get; set; } = 10;
+
+ /// <summary>
+ /// Gets or sets the ffmpeg output quality level.
+ /// </summary>
+ public int Qscale { get; set; } = 4;
+
+ /// <summary>
+ /// Gets or sets the jpeg quality to use for image tiles.
+ /// </summary>
+ public int JpegQuality { get; set; } = 90;
+
+ /// <summary>
+ /// Gets or sets the number of threads to be used by ffmpeg.
+ /// </summary>
+ public int ProcessThreads { get; set; } = 0;
}
diff --git a/MediaBrowser.Model/Configuration/TrickplayScanBehavior.cs b/MediaBrowser.Model/Configuration/TrickplayScanBehavior.cs
index 799794176..d0db53218 100644
--- a/MediaBrowser.Model/Configuration/TrickplayScanBehavior.cs
+++ b/MediaBrowser.Model/Configuration/TrickplayScanBehavior.cs
@@ -1,18 +1,17 @@
-namespace MediaBrowser.Model.Configuration
+namespace MediaBrowser.Model.Configuration;
+
+/// <summary>
+/// Enum TrickplayScanBehavior.
+/// </summary>
+public enum TrickplayScanBehavior
{
/// <summary>
- /// Enum TrickplayScanBehavior.
+ /// Starts generation, only return once complete.
/// </summary>
- public enum TrickplayScanBehavior
- {
- /// <summary>
- /// Starts generation, only return once complete.
- /// </summary>
- Blocking,
+ Blocking,
- /// <summary>
- /// Start generation, return immediately.
- /// </summary>
- NonBlocking
- }
+ /// <summary>
+ /// Start generation, return immediately.
+ /// </summary>
+ NonBlocking
}
diff --git a/MediaBrowser.Model/Entities/TrickplayTilesInfo.cs b/MediaBrowser.Model/Entities/TrickplayTilesInfo.cs
index 84b6b0322..86d37787f 100644
--- a/MediaBrowser.Model/Entities/TrickplayTilesInfo.cs
+++ b/MediaBrowser.Model/Entities/TrickplayTilesInfo.cs
@@ -1,50 +1,49 @@
-namespace MediaBrowser.Model.Entities
+namespace MediaBrowser.Model.Entities;
+
+/// <summary>
+/// Class TrickplayTilesInfo.
+/// </summary>
+public class TrickplayTilesInfo
{
/// <summary>
- /// Class TrickplayTilesInfo.
+ /// Gets or sets width of an individual tile.
/// </summary>
- public class TrickplayTilesInfo
- {
- /// <summary>
- /// Gets or sets width of an individual tile.
- /// </summary>
- /// <value>The width.</value>
- public int Width { get; set; }
+ /// <value>The width.</value>
+ public int Width { get; set; }
- /// <summary>
- /// Gets or sets height of an individual tile.
- /// </summary>
- /// <value>The height.</value>
- public int Height { get; set; }
+ /// <summary>
+ /// Gets or sets height of an individual tile.
+ /// </summary>
+ /// <value>The height.</value>
+ public int Height { get; set; }
- /// <summary>
- /// Gets or sets amount of tiles per row.
- /// </summary>
- /// <value>The tile grid's width.</value>
- public int TileWidth { get; set; }
+ /// <summary>
+ /// Gets or sets amount of tiles per row.
+ /// </summary>
+ /// <value>The tile grid's width.</value>
+ public int TileWidth { get; set; }
- /// <summary>
- /// Gets or sets amount of tiles per column.
- /// </summary>
- /// <value>The tile grid's height.</value>
- public int TileHeight { get; set; }
+ /// <summary>
+ /// Gets or sets amount of tiles per column.
+ /// </summary>
+ /// <value>The tile grid's height.</value>
+ public int TileHeight { get; set; }
- /// <summary>
- /// Gets or sets total amount of non-black tiles.
- /// </summary>
- /// <value>The tile count.</value>
- public int TileCount { get; set; }
+ /// <summary>
+ /// Gets or sets total amount of non-black tiles.
+ /// </summary>
+ /// <value>The tile count.</value>
+ public int TileCount { get; set; }
- /// <summary>
- /// Gets or sets interval in milliseconds between each trickplay tile.
- /// </summary>
- /// <value>The interval.</value>
- public int Interval { get; set; }
+ /// <summary>
+ /// Gets or sets interval in milliseconds between each trickplay tile.
+ /// </summary>
+ /// <value>The interval.</value>
+ public int Interval { get; set; }
- /// <summary>
- /// Gets or sets peak bandwith usage in bits per second.
- /// </summary>
- /// <value>The bandwidth.</value>
- public int Bandwidth { get; set; }
- }
+ /// <summary>
+ /// Gets or sets peak bandwith usage in bits per second.
+ /// </summary>
+ /// <value>The bandwidth.</value>
+ public int Bandwidth { get; set; }
}
diff --git a/MediaBrowser.Providers/Trickplay/TrickplayImagesTask.cs b/MediaBrowser.Providers/Trickplay/TrickplayImagesTask.cs
index 8d0d9d5a3..f32557cd1 100644
--- a/MediaBrowser.Providers/Trickplay/TrickplayImagesTask.cs
+++ b/MediaBrowser.Providers/Trickplay/TrickplayImagesTask.cs
@@ -12,98 +12,97 @@ using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Tasks;
using Microsoft.Extensions.Logging;
-namespace MediaBrowser.Providers.Trickplay
+namespace MediaBrowser.Providers.Trickplay;
+
+/// <summary>
+/// Class TrickplayImagesTask.
+/// </summary>
+public class TrickplayImagesTask : IScheduledTask
{
+ private readonly ILogger<TrickplayImagesTask> _logger;
+ private readonly ILibraryManager _libraryManager;
+ private readonly ILocalizationManager _localization;
+ private readonly ITrickplayManager _trickplayManager;
+
/// <summary>
- /// Class TrickplayImagesTask.
+ /// Initializes a new instance of the <see cref="TrickplayImagesTask"/> class.
/// </summary>
- public class TrickplayImagesTask : IScheduledTask
+ /// <param name="logger">The logger.</param>
+ /// <param name="libraryManager">The library manager.</param>
+ /// <param name="localization">The localization manager.</param>
+ /// <param name="trickplayManager">The trickplay manager.</param>
+ public TrickplayImagesTask(
+ ILogger<TrickplayImagesTask> logger,
+ ILibraryManager libraryManager,
+ ILocalizationManager localization,
+ ITrickplayManager trickplayManager)
{
- private readonly ILogger<TrickplayImagesTask> _logger;
- private readonly ILibraryManager _libraryManager;
- private readonly ILocalizationManager _localization;
- private readonly ITrickplayManager _trickplayManager;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="TrickplayImagesTask"/> class.
- /// </summary>
- /// <param name="logger">The logger.</param>
- /// <param name="libraryManager">The library manager.</param>
- /// <param name="localization">The localization manager.</param>
- /// <param name="trickplayManager">The trickplay manager.</param>
- public TrickplayImagesTask(
- ILogger<TrickplayImagesTask> logger,
- ILibraryManager libraryManager,
- ILocalizationManager localization,
- ITrickplayManager trickplayManager)
- {
- _libraryManager = libraryManager;
- _logger = logger;
- _localization = localization;
- _trickplayManager = trickplayManager;
- }
+ _libraryManager = libraryManager;
+ _logger = logger;
+ _localization = localization;
+ _trickplayManager = trickplayManager;
+ }
- /// <inheritdoc />
- public string Name => _localization.GetLocalizedString("TaskRefreshTrickplayImages");
+ /// <inheritdoc />
+ public string Name => _localization.GetLocalizedString("TaskRefreshTrickplayImages");
- /// <inheritdoc />
- public string Description => _localization.GetLocalizedString("TaskRefreshTrickplayImagesDescription");
+ /// <inheritdoc />
+ public string Description => _localization.GetLocalizedString("TaskRefreshTrickplayImagesDescription");
- /// <inheritdoc />
- public string Key => "RefreshTrickplayImages";
+ /// <inheritdoc />
+ public string Key => "RefreshTrickplayImages";
- /// <inheritdoc />
- public string Category => _localization.GetLocalizedString("TasksLibraryCategory");
+ /// <inheritdoc />
+ public string Category => _localization.GetLocalizedString("TasksLibraryCategory");
- /// <inheritdoc />
- public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
+ /// <inheritdoc />
+ public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
+ {
+ return new[]
{
- return new[]
+ new TaskTriggerInfo
{
- new TaskTriggerInfo
- {
- Type = TaskTriggerInfo.TriggerDaily,
- TimeOfDayTicks = TimeSpan.FromHours(3).Ticks
- }
- };
- }
+ Type = TaskTriggerInfo.TriggerDaily,
+ TimeOfDayTicks = TimeSpan.FromHours(3).Ticks
+ }
+ };
+ }
- /// <inheritdoc />
- public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
+ /// <inheritdoc />
+ public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
+ {
+ var items = _libraryManager.GetItemList(new InternalItemsQuery
{
- var items = _libraryManager.GetItemList(new InternalItemsQuery
- {
- MediaTypes = new[] { MediaType.Video },
- IsVirtualItem = false,
- IsFolder = false,
- Recursive = true
- }).OfType<Video>().ToList();
+ MediaTypes = new[] { MediaType.Video },
+ IsVirtualItem = false,
+ IsFolder = false,
+ Recursive = true
+ }).OfType<Video>().ToList();
- var numComplete = 0;
+ var numComplete = 0;
- foreach (var item in items)
+ foreach (var item in items)
+ {
+ try
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+ await _trickplayManager.RefreshTrickplayDataAsync(item, false, cancellationToken).ConfigureAwait(false);
+ }
+ catch (OperationCanceledException)
{
- try
- {
- cancellationToken.ThrowIfCancellationRequested();
- await _trickplayManager.RefreshTrickplayData(item, false, cancellationToken).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
- break;
- }
- catch (Exception ex)
- {
- _logger.LogError("Error creating trickplay files for {ItemName}: {Msg}", item.Name, ex);
- }
+ break;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError("Error creating trickplay files for {ItemName}: {Msg}", item.Name, ex);
+ }
- numComplete++;
- double percent = numComplete;
- percent /= items.Count;
- percent *= 100;
+ numComplete++;
+ double percent = numComplete;
+ percent /= items.Count;
+ percent *= 100;
- progress.Report(percent);
- }
+ progress.Report(percent);
}
}
}
diff --git a/MediaBrowser.Providers/Trickplay/TrickplayManager.cs b/MediaBrowser.Providers/Trickplay/TrickplayManager.cs
index ed2c11281..9b8eb8150 100644
--- a/MediaBrowser.Providers/Trickplay/TrickplayManager.cs
+++ b/MediaBrowser.Providers/Trickplay/TrickplayManager.cs
@@ -17,370 +17,369 @@ using MediaBrowser.Model.IO;
using Microsoft.Extensions.Logging;
using SkiaSharp;
-namespace MediaBrowser.Providers.Trickplay
+namespace MediaBrowser.Providers.Trickplay;
+
+/// <summary>
+/// ITrickplayManager implementation.
+/// </summary>
+public class TrickplayManager : ITrickplayManager
{
+ private readonly ILogger<TrickplayManager> _logger;
+ private readonly IItemRepository _itemRepo;
+ private readonly IMediaEncoder _mediaEncoder;
+ private readonly IFileSystem _fileSystem;
+ private readonly EncodingHelper _encodingHelper;
+ private readonly ILibraryManager _libraryManager;
+ private readonly IServerConfigurationManager _config;
+
+ private static readonly SemaphoreSlim _resourcePool = new(1, 1);
+
/// <summary>
- /// ITrickplayManager implementation.
+ /// Initializes a new instance of the <see cref="TrickplayManager"/> class.
/// </summary>
- public class TrickplayManager : ITrickplayManager
+ /// <param name="logger">The logger.</param>
+ /// <param name="itemRepo">The item repository.</param>
+ /// <param name="mediaEncoder">The media encoder.</param>
+ /// <param name="fileSystem">The file systen.</param>
+ /// <param name="encodingHelper">The encoding helper.</param>
+ /// <param name="libraryManager">The library manager.</param>
+ /// <param name="config">The server configuration manager.</param>
+ public TrickplayManager(
+ ILogger<TrickplayManager> logger,
+ IItemRepository itemRepo,
+ IMediaEncoder mediaEncoder,
+ IFileSystem fileSystem,
+ EncodingHelper encodingHelper,
+ ILibraryManager libraryManager,
+ IServerConfigurationManager config)
{
- private readonly ILogger<TrickplayManager> _logger;
- private readonly IItemRepository _itemRepo;
- private readonly IMediaEncoder _mediaEncoder;
- private readonly IFileSystem _fileSystem;
- private readonly EncodingHelper _encodingHelper;
- private readonly ILibraryManager _libraryManager;
- private readonly IServerConfigurationManager _config;
-
- private static readonly SemaphoreSlim _resourcePool = new(1, 1);
-
- /// <summary>
- /// Initializes a new instance of the <see cref="TrickplayManager"/> class.
- /// </summary>
- /// <param name="logger">The logger.</param>
- /// <param name="itemRepo">The item repository.</param>
- /// <param name="mediaEncoder">The media encoder.</param>
- /// <param name="fileSystem">The file systen.</param>
- /// <param name="encodingHelper">The encoding helper.</param>
- /// <param name="libraryManager">The library manager.</param>
- /// <param name="config">The server configuration manager.</param>
- public TrickplayManager(
- ILogger<TrickplayManager> logger,
- IItemRepository itemRepo,
- IMediaEncoder mediaEncoder,
- IFileSystem fileSystem,
- EncodingHelper encodingHelper,
- ILibraryManager libraryManager,
- IServerConfigurationManager config)
+ _logger = logger;
+ _itemRepo = itemRepo;
+ _mediaEncoder = mediaEncoder;
+ _fileSystem = fileSystem;
+ _encodingHelper = encodingHelper;
+ _libraryManager = libraryManager;
+ _config = config;
+ }
+
+ /// <inheritdoc />
+ public async Task RefreshTrickplayDataAsync(Video video, bool replace, CancellationToken cancellationToken)
+ {
+ _logger.LogDebug("Trickplay refresh for {ItemId} (replace existing: {Replace})", video.Id, replace);
+
+ var options = _config.Configuration.TrickplayOptions;
+ foreach (var width in options.WidthResolutions)
{
- _logger = logger;
- _itemRepo = itemRepo;
- _mediaEncoder = mediaEncoder;
- _fileSystem = fileSystem;
- _encodingHelper = encodingHelper;
- _libraryManager = libraryManager;
- _config = config;
+ cancellationToken.ThrowIfCancellationRequested();
+ await RefreshTrickplayDataInternal(
+ video,
+ replace,
+ width,
+ options,
+ cancellationToken).ConfigureAwait(false);
}
+ }
- /// <inheritdoc />
- public async Task RefreshTrickplayData(Video video, bool replace, CancellationToken cancellationToken)
+ private async Task RefreshTrickplayDataInternal(
+ Video video,
+ bool replace,
+ int width,
+ TrickplayOptions options,
+ CancellationToken cancellationToken)
+ {
+ if (!CanGenerateTrickplay(video, options.Interval))
{
- _logger.LogDebug("Trickplay refresh for {ItemId} (replace existing: {Replace})", video.Id, replace);
-
- var options = _config.Configuration.TrickplayOptions;
- foreach (var width in options.WidthResolutions)
- {
- cancellationToken.ThrowIfCancellationRequested();
- await RefreshTrickplayDataInternal(
- video,
- replace,
- width,
- options,
- cancellationToken).ConfigureAwait(false);
- }
+ return;
}
- private async Task RefreshTrickplayDataInternal(
- Video video,
- bool replace,
- int width,
- TrickplayOptions options,
- CancellationToken cancellationToken)
+ var imgTempDir = string.Empty;
+ var outputDir = GetTrickplayDirectory(video, width);
+
+ try
{
- if (!CanGenerateTrickplay(video, options.Interval))
+ await _resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
+
+ if (!replace && Directory.Exists(outputDir) && GetTilesResolutions(video.Id).ContainsKey(width))
{
+ _logger.LogDebug("Found existing trickplay files for {ItemId}. Exiting.", video.Id);
return;
}
- var imgTempDir = string.Empty;
- var outputDir = GetTrickplayDirectory(video, width);
+ // Extract images
+ // Note: Media sources under parent items exist as their own video/item as well. Only use this video stream for trickplay.
+ var mediaSource = video.GetMediaSources(false).Find(source => Guid.Parse(source.Id).Equals(video.Id));
- try
+ if (mediaSource is null)
{
- await _resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- if (!replace && Directory.Exists(outputDir) && GetTilesResolutions(video.Id).ContainsKey(width))
- {
- _logger.LogDebug("Found existing trickplay files for {ItemId}. Exiting.", video.Id);
- return;
- }
-
- // Extract images
- // Note: Media sources under parent items exist as their own video/item as well. Only use this video stream for trickplay.
- var mediaSource = video.GetMediaSources(false).Find(source => Guid.Parse(source.Id).Equals(video.Id));
-
- if (mediaSource is null)
- {
- _logger.LogDebug("Found no matching media source for item {ItemId}", video.Id);
- return;
- }
+ _logger.LogDebug("Found no matching media source for item {ItemId}", video.Id);
+ return;
+ }
- var mediaPath = mediaSource.Path;
- var mediaStream = mediaSource.VideoStream;
- var container = mediaSource.Container;
-
- _logger.LogInformation("Creating trickplay files at {Width} width, for {Path} [ID: {ItemId}]", width, mediaPath, video.Id);
- imgTempDir = await _mediaEncoder.ExtractVideoImagesOnIntervalAccelerated(
- mediaPath,
- container,
- mediaSource,
- mediaStream,
- width,
- TimeSpan.FromMilliseconds(options.Interval),
- options.EnableHwAcceleration,
- options.ProcessThreads,
- options.Qscale,
- options.ProcessPriority,
- _encodingHelper,
- cancellationToken).ConfigureAwait(false);
-
- if (string.IsNullOrEmpty(imgTempDir) || !Directory.Exists(imgTempDir))
- {
- throw new InvalidOperationException("Null or invalid directory from media encoder.");
- }
+ var mediaPath = mediaSource.Path;
+ var mediaStream = mediaSource.VideoStream;
+ var container = mediaSource.Container;
+
+ _logger.LogInformation("Creating trickplay files at {Width} width, for {Path} [ID: {ItemId}]", width, mediaPath, video.Id);
+ imgTempDir = await _mediaEncoder.ExtractVideoImagesOnIntervalAccelerated(
+ mediaPath,
+ container,
+ mediaSource,
+ mediaStream,
+ width,
+ TimeSpan.FromMilliseconds(options.Interval),
+ options.EnableHwAcceleration,
+ options.ProcessThreads,
+ options.Qscale,
+ options.ProcessPriority,
+ _encodingHelper,
+ cancellationToken).ConfigureAwait(false);
+
+ if (string.IsNullOrEmpty(imgTempDir) || !Directory.Exists(imgTempDir))
+ {
+ throw new InvalidOperationException("Null or invalid directory from media encoder.");
+ }
- var images = _fileSystem.GetFiles(imgTempDir, new string[] { ".jpg" }, false, false)
- .Where(img => string.Equals(img.Extension, ".jpg", StringComparison.Ordinal))
- .OrderBy(i => i.FullName)
- .ToList();
+ var images = _fileSystem.GetFiles(imgTempDir, new string[] { ".jpg" }, false, false)
+ .Where(img => string.Equals(img.Extension, ".jpg", StringComparison.Ordinal))
+ .OrderBy(i => i.FullName)
+ .ToList();
- // Create tiles
- var tilesTempDir = Path.Combine(imgTempDir, Guid.NewGuid().ToString("N"));
- var tilesInfo = CreateTiles(images, width, options, tilesTempDir, outputDir);
+ // Create tiles
+ var tilesTempDir = Path.Combine(imgTempDir, Guid.NewGuid().ToString("N"));
+ var tilesInfo = CreateTiles(images, width, options, tilesTempDir, outputDir);
- // Save tiles info
- try
+ // Save tiles info
+ try
+ {
+ if (tilesInfo is not null)
{
- if (tilesInfo is not null)
- {
- SaveTilesInfo(video.Id, tilesInfo);
- _logger.LogInformation("Finished creation of trickplay files for {0}", mediaPath);
- }
- else
- {
- throw new InvalidOperationException("Null trickplay tiles info from CreateTiles.");
- }
+ SaveTilesInfo(video.Id, tilesInfo);
+ _logger.LogInformation("Finished creation of trickplay files for {0}", mediaPath);
}
- catch (Exception ex)
+ else
{
- _logger.LogError(ex, "Error while saving trickplay tiles info.");
-
- // Make sure no files stay in metadata folders on failure
- // if tiles info wasn't saved.
- Directory.Delete(outputDir, true);
+ throw new InvalidOperationException("Null trickplay tiles info from CreateTiles.");
}
}
catch (Exception ex)
{
- _logger.LogError(ex, "Error creating trickplay images.");
- }
- finally
- {
- _resourcePool.Release();
+ _logger.LogError(ex, "Error while saving trickplay tiles info.");
- if (!string.IsNullOrEmpty(imgTempDir))
- {
- Directory.Delete(imgTempDir, true);
- }
+ // Make sure no files stay in metadata folders on failure
+ // if tiles info wasn't saved.
+ Directory.Delete(outputDir, true);
}
}
-
- private TrickplayTilesInfo CreateTiles(List<FileSystemMetadata> images, int width, TrickplayOptions options, string workDir, string outputDir)
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error creating trickplay images.");
+ }
+ finally
{
- if (images.Count == 0)
+ _resourcePool.Release();
+
+ if (!string.IsNullOrEmpty(imgTempDir))
{
- throw new InvalidOperationException("Can't create trickplay from 0 images.");
+ Directory.Delete(imgTempDir, true);
}
+ }
+ }
- Directory.CreateDirectory(workDir);
+ private TrickplayTilesInfo CreateTiles(List<FileSystemMetadata> images, int width, TrickplayOptions options, string workDir, string outputDir)
+ {
+ if (images.Count == 0)
+ {
+ throw new InvalidOperationException("Can't create trickplay from 0 images.");
+ }
- var tilesInfo = new TrickplayTilesInfo
- {
- Width = width,
- Interval = options.Interval,
- TileWidth = options.TileWidth,
- TileHeight = options.TileHeight,
- TileCount = 0,
- Bandwidth = 0
- };
-
- var firstImg = SKBitmap.Decode(images[0].FullName);
- if (firstImg == null)
- {
- throw new InvalidDataException("Could not decode image data.");
- }
+ Directory.CreateDirectory(workDir);
- tilesInfo.Height = firstImg.Height;
- if (tilesInfo.Width != firstImg.Width)
- {
- throw new InvalidOperationException("Image width does not match config width.");
- }
+ var tilesInfo = new TrickplayTilesInfo
+ {
+ Width = width,
+ Interval = options.Interval,
+ TileWidth = options.TileWidth,
+ TileHeight = options.TileHeight,
+ TileCount = 0,
+ Bandwidth = 0
+ };
+
+ var firstImg = SKBitmap.Decode(images[0].FullName);
+ if (firstImg == null)
+ {
+ throw new InvalidDataException("Could not decode image data.");
+ }
- /*
- * Generate grids of trickplay image tiles
- */
- var imgNo = 0;
- var i = 0;
- while (i < images.Count)
- {
- var tileGrid = new SKBitmap(tilesInfo.Width * tilesInfo.TileWidth, tilesInfo.Height * tilesInfo.TileHeight);
+ tilesInfo.Height = firstImg.Height;
+ if (tilesInfo.Width != firstImg.Width)
+ {
+ throw new InvalidOperationException("Image width does not match config width.");
+ }
+
+ /*
+ * Generate grids of trickplay image tiles
+ */
+ var imgNo = 0;
+ var i = 0;
+ while (i < images.Count)
+ {
+ var tileGrid = new SKBitmap(tilesInfo.Width * tilesInfo.TileWidth, tilesInfo.Height * tilesInfo.TileHeight);
- using (var canvas = new SKCanvas(tileGrid))
+ using (var canvas = new SKCanvas(tileGrid))
+ {
+ for (var y = 0; y < tilesInfo.TileHeight; y++)
{
- for (var y = 0; y < tilesInfo.TileHeight; y++)
+ for (var x = 0; x < tilesInfo.TileWidth; x++)
{
- for (var x = 0; x < tilesInfo.TileWidth; x++)
+ if (i >= images.Count)
{
- if (i >= images.Count)
- {
- break;
- }
-
- var img = SKBitmap.Decode(images[i].FullName);
- if (img == null)
- {
- throw new InvalidDataException("Could not decode image data.");
- }
-
- if (tilesInfo.Width != img.Width)
- {
- throw new InvalidOperationException("Image width does not match config width.");
- }
-
- if (tilesInfo.Height != img.Height)
- {
- throw new InvalidOperationException("Image height does not match first image height.");
- }
-
- canvas.DrawBitmap(img, x * tilesInfo.Width, y * tilesInfo.Height);
- tilesInfo.TileCount++;
- i++;
+ break;
}
- }
- }
- // Output each tile grid to singular file
- var tileGridPath = Path.Combine(workDir, $"{imgNo}.jpg");
- using (var stream = File.OpenWrite(tileGridPath))
- {
- tileGrid.Encode(stream, SKEncodedImageFormat.Jpeg, options.JpegQuality);
- }
+ var img = SKBitmap.Decode(images[i].FullName);
+ if (img == null)
+ {
+ throw new InvalidDataException("Could not decode image data.");
+ }
+
+ if (tilesInfo.Width != img.Width)
+ {
+ throw new InvalidOperationException("Image width does not match config width.");
+ }
- var bitrate = (int)Math.Ceiling((decimal)new FileInfo(tileGridPath).Length * 8 / tilesInfo.TileWidth / tilesInfo.TileHeight / (tilesInfo.Interval / 1000));
- tilesInfo.Bandwidth = Math.Max(tilesInfo.Bandwidth, bitrate);
+ if (tilesInfo.Height != img.Height)
+ {
+ throw new InvalidOperationException("Image height does not match first image height.");
+ }
- imgNo++;
+ canvas.DrawBitmap(img, x * tilesInfo.Width, y * tilesInfo.Height);
+ tilesInfo.TileCount++;
+ i++;
+ }
+ }
}
- /*
- * Move trickplay tiles to output directory
- */
- Directory.CreateDirectory(outputDir);
-
- // Replace existing tile grids if they already exist
- if (Directory.Exists(outputDir))
+ // Output each tile grid to singular file
+ var tileGridPath = Path.Combine(workDir, $"{imgNo}.jpg");
+ using (var stream = File.OpenWrite(tileGridPath))
{
- Directory.Delete(outputDir, true);
+ tileGrid.Encode(stream, SKEncodedImageFormat.Jpeg, options.JpegQuality);
}
- MoveDirectory(workDir, outputDir);
+ var bitrate = (int)Math.Ceiling((decimal)new FileInfo(tileGridPath).Length * 8 / tilesInfo.TileWidth / tilesInfo.TileHeight / (tilesInfo.Interval / 1000));
+ tilesInfo.Bandwidth = Math.Max(tilesInfo.Bandwidth, bitrate);
- return tilesInfo;
+ imgNo++;
}
- private bool CanGenerateTrickplay(Video video, int interval)
- {
- var videoType = video.VideoType;
- if (videoType == VideoType.Iso || videoType == VideoType.Dvd || videoType == VideoType.BluRay)
- {
- return false;
- }
-
- if (video.IsPlaceHolder)
- {
- return false;
- }
+ /*
+ * Move trickplay tiles to output directory
+ */
+ Directory.CreateDirectory(outputDir);
- if (video.IsShortcut)
- {
- return false;
- }
+ // Replace existing tile grids if they already exist
+ if (Directory.Exists(outputDir))
+ {
+ Directory.Delete(outputDir, true);
+ }
- if (!video.IsCompleteMedia)
- {
- return false;
- }
+ MoveDirectory(workDir, outputDir);
- if (!video.RunTimeTicks.HasValue || video.RunTimeTicks.Value < TimeSpan.FromMilliseconds(interval).Ticks)
- {
- return false;
- }
-
- var libraryOptions = _libraryManager.GetLibraryOptions(video);
- if (libraryOptions is not null)
- {
- if (!libraryOptions.EnableTrickplayImageExtraction)
- {
- return false;
- }
- }
- else
- {
- return false;
- }
+ return tilesInfo;
+ }
- // Can't extract images if there are no video streams
- return video.GetMediaStreams().Count > 0;
+ private bool CanGenerateTrickplay(Video video, int interval)
+ {
+ var videoType = video.VideoType;
+ if (videoType == VideoType.Iso || videoType == VideoType.Dvd || videoType == VideoType.BluRay)
+ {
+ return false;
}
- /// <inheritdoc />
- public Dictionary<int, TrickplayTilesInfo> GetTilesResolutions(Guid itemId)
+ if (video.IsPlaceHolder)
{
- return _itemRepo.GetTilesResolutions(itemId);
+ return false;
}
- /// <inheritdoc />
- public void SaveTilesInfo(Guid itemId, TrickplayTilesInfo tilesInfo)
+ if (video.IsShortcut)
{
- _itemRepo.SaveTilesInfo(itemId, tilesInfo);
+ return false;
}
- /// <inheritdoc />
- public Dictionary<Guid, Dictionary<int, TrickplayTilesInfo>> GetTrickplayManifest(BaseItem item)
+ if (!video.IsCompleteMedia)
{
- return _itemRepo.GetTrickplayManifest(item);
+ return false;
}
- /// <inheritdoc />
- public string GetTrickplayTilePath(BaseItem item, int width, int index)
+ if (!video.RunTimeTicks.HasValue || video.RunTimeTicks.Value < TimeSpan.FromMilliseconds(interval).Ticks)
{
- return Path.Combine(GetTrickplayDirectory(item, width), index + ".jpg");
+ return false;
}
- private string GetTrickplayDirectory(BaseItem item, int? width = null)
+ var libraryOptions = _libraryManager.GetLibraryOptions(video);
+ if (libraryOptions is not null)
{
- var path = Path.Combine(item.GetInternalMetadataPath(), "trickplay");
-
- return width.HasValue ? Path.Combine(path, width.Value.ToString(CultureInfo.InvariantCulture)) : path;
+ if (!libraryOptions.EnableTrickplayImageExtraction)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
}
- private void MoveDirectory(string source, string destination)
+ // Can't extract images if there are no video streams
+ return video.GetMediaStreams().Count > 0;
+ }
+
+ /// <inheritdoc />
+ public Dictionary<int, TrickplayTilesInfo> GetTilesResolutions(Guid itemId)
+ {
+ return _itemRepo.GetTilesResolutions(itemId);
+ }
+
+ /// <inheritdoc />
+ public void SaveTilesInfo(Guid itemId, TrickplayTilesInfo tilesInfo)
+ {
+ _itemRepo.SaveTilesInfo(itemId, tilesInfo);
+ }
+
+ /// <inheritdoc />
+ public Dictionary<Guid, Dictionary<int, TrickplayTilesInfo>> GetTrickplayManifest(BaseItem item)
+ {
+ return _itemRepo.GetTrickplayManifest(item);
+ }
+
+ /// <inheritdoc />
+ public string GetTrickplayTilePath(BaseItem item, int width, int index)
+ {
+ return Path.Combine(GetTrickplayDirectory(item, width), index + ".jpg");
+ }
+
+ private string GetTrickplayDirectory(BaseItem item, int? width = null)
+ {
+ var path = Path.Combine(item.GetInternalMetadataPath(), "trickplay");
+
+ return width.HasValue ? Path.Combine(path, width.Value.ToString(CultureInfo.InvariantCulture)) : path;
+ }
+
+ private void MoveDirectory(string source, string destination)
+ {
+ try
{
- try
+ Directory.Move(source, destination);
+ }
+ catch (IOException)
+ {
+ // Cross device move requires a copy
+ Directory.CreateDirectory(destination);
+ foreach (string file in Directory.GetFiles(source))
{
- Directory.Move(source, destination);
+ File.Copy(file, Path.Join(destination, Path.GetFileName(file)), true);
}
- catch (IOException)
- {
- // Cross device move requires a copy
- Directory.CreateDirectory(destination);
- foreach (string file in Directory.GetFiles(source))
- {
- File.Copy(file, Path.Join(destination, Path.GetFileName(file)), true);
- }
- Directory.Delete(source, true);
- }
+ Directory.Delete(source, true);
}
}
}
diff --git a/MediaBrowser.Providers/Trickplay/TrickplayProvider.cs b/MediaBrowser.Providers/Trickplay/TrickplayProvider.cs
index e29646725..d467c480e 100644
--- a/MediaBrowser.Providers/Trickplay/TrickplayProvider.cs
+++ b/MediaBrowser.Providers/Trickplay/TrickplayProvider.cs
@@ -10,118 +10,117 @@ using MediaBrowser.Controller.Trickplay;
using MediaBrowser.Model.Configuration;
using Microsoft.Extensions.Logging;
-namespace MediaBrowser.Providers.Trickplay
+namespace MediaBrowser.Providers.Trickplay;
+
+/// <summary>
+/// Class TrickplayProvider. Provides images and metadata for trickplay
+/// scrubbing previews.
+/// </summary>
+public class TrickplayProvider : ICustomMetadataProvider<Episode>,
+ ICustomMetadataProvider<MusicVideo>,
+ ICustomMetadataProvider<Movie>,
+ ICustomMetadataProvider<Trailer>,
+ ICustomMetadataProvider<Video>,
+ IHasItemChangeMonitor,
+ IHasOrder,
+ IForcedProvider
{
+ private readonly ILogger<TrickplayProvider> _logger;
+ private readonly IServerConfigurationManager _config;
+ private readonly ITrickplayManager _trickplayManager;
+ private readonly ILibraryManager _libraryManager;
+
/// <summary>
- /// Class TrickplayProvider. Provides images and metadata for trickplay
- /// scrubbing previews.
+ /// Initializes a new instance of the <see cref="TrickplayProvider"/> class.
/// </summary>
- public class TrickplayProvider : ICustomMetadataProvider<Episode>,
- ICustomMetadataProvider<MusicVideo>,
- ICustomMetadataProvider<Movie>,
- ICustomMetadataProvider<Trailer>,
- ICustomMetadataProvider<Video>,
- IHasItemChangeMonitor,
- IHasOrder,
- IForcedProvider
+ /// <param name="logger">The logger.</param>
+ /// <param name="config">The configuration manager.</param>
+ /// <param name="trickplayManager">The trickplay manager.</param>
+ /// <param name="libraryManager">The library manager.</param>
+ public TrickplayProvider(
+ ILogger<TrickplayProvider> logger,
+ IServerConfigurationManager config,
+ ITrickplayManager trickplayManager,
+ ILibraryManager libraryManager)
{
- private readonly ILogger<TrickplayProvider> _logger;
- private readonly IServerConfigurationManager _config;
- private readonly ITrickplayManager _trickplayManager;
- private readonly ILibraryManager _libraryManager;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="TrickplayProvider"/> class.
- /// </summary>
- /// <param name="logger">The logger.</param>
- /// <param name="config">The configuration manager.</param>
- /// <param name="trickplayManager">The trickplay manager.</param>
- /// <param name="libraryManager">The library manager.</param>
- public TrickplayProvider(
- ILogger<TrickplayProvider> logger,
- IServerConfigurationManager config,
- ITrickplayManager trickplayManager,
- ILibraryManager libraryManager)
- {
- _logger = logger;
- _config = config;
- _trickplayManager = trickplayManager;
- _libraryManager = libraryManager;
- }
+ _logger = logger;
+ _config = config;
+ _trickplayManager = trickplayManager;
+ _libraryManager = libraryManager;
+ }
- /// <inheritdoc />
- public string Name => "Trickplay Provider";
+ /// <inheritdoc />
+ public string Name => "Trickplay Provider";
- /// <inheritdoc />
- public int Order => 100;
+ /// <inheritdoc />
+ public int Order => 100;
- /// <inheritdoc />
- public bool HasChanged(BaseItem item, IDirectoryService directoryService)
+ /// <inheritdoc />
+ public bool HasChanged(BaseItem item, IDirectoryService directoryService)
+ {
+ if (item.IsFileProtocol)
{
- if (item.IsFileProtocol)
+ var file = directoryService.GetFile(item.Path);
+ if (file is not null && item.DateModified != file.LastWriteTimeUtc)
{
- var file = directoryService.GetFile(item.Path);
- if (file is not null && item.DateModified != file.LastWriteTimeUtc)
- {
- return true;
- }
+ return true;
}
-
- return false;
}
- /// <inheritdoc />
- public Task<ItemUpdateType> FetchAsync(Episode item, MetadataRefreshOptions options, CancellationToken cancellationToken)
- {
- return FetchInternal(item, options, cancellationToken);
- }
+ return false;
+ }
- /// <inheritdoc />
- public Task<ItemUpdateType> FetchAsync(MusicVideo item, MetadataRefreshOptions options, CancellationToken cancellationToken)
- {
- return FetchInternal(item, options, cancellationToken);
- }
+ /// <inheritdoc />
+ public Task<ItemUpdateType> FetchAsync(Episode item, MetadataRefreshOptions options, CancellationToken cancellationToken)
+ {
+ return FetchInternal(item, options, cancellationToken);
+ }
- /// <inheritdoc />
- public Task<ItemUpdateType> FetchAsync(Movie item, MetadataRefreshOptions options, CancellationToken cancellationToken)
- {
- return FetchInternal(item, options, cancellationToken);
- }
+ /// <inheritdoc />
+ public Task<ItemUpdateType> FetchAsync(MusicVideo item, MetadataRefreshOptions options, CancellationToken cancellationToken)
+ {
+ return FetchInternal(item, options, cancellationToken);
+ }
+
+ /// <inheritdoc />
+ public Task<ItemUpdateType> FetchAsync(Movie item, MetadataRefreshOptions options, CancellationToken cancellationToken)
+ {
+ return FetchInternal(item, options, cancellationToken);
+ }
- /// <inheritdoc />
- public Task<ItemUpdateType> FetchAsync(Trailer item, MetadataRefreshOptions options, CancellationToken cancellationToken)
+ /// <inheritdoc />
+ public Task<ItemUpdateType> FetchAsync(Trailer item, MetadataRefreshOptions options, CancellationToken cancellationToken)
+ {
+ return FetchInternal(item, options, cancellationToken);
+ }
+
+ /// <inheritdoc />
+ public Task<ItemUpdateType> FetchAsync(Video item, MetadataRefreshOptions options, CancellationToken cancellationToken)
+ {
+ return FetchInternal(item, options, cancellationToken);
+ }
+
+ private async Task<ItemUpdateType> FetchInternal(Video video, MetadataRefreshOptions options, CancellationToken cancellationToken)
+ {
+ var libraryOptions = _libraryManager.GetLibraryOptions(video);
+ bool? enableDuringScan = libraryOptions?.ExtractTrickplayImagesDuringLibraryScan;
+ bool replace = options.ReplaceAllImages;
+
+ if (options.IsAutomated && !enableDuringScan.GetValueOrDefault(false))
{
- return FetchInternal(item, options, cancellationToken);
+ return ItemUpdateType.None;
}
- /// <inheritdoc />
- public Task<ItemUpdateType> FetchAsync(Video item, MetadataRefreshOptions options, CancellationToken cancellationToken)
+ if (_config.Configuration.TrickplayOptions.ScanBehavior == TrickplayScanBehavior.Blocking)
{
- return FetchInternal(item, options, cancellationToken);
+ await _trickplayManager.RefreshTrickplayDataAsync(video, replace, cancellationToken).ConfigureAwait(false);
}
-
- private async Task<ItemUpdateType> FetchInternal(Video video, MetadataRefreshOptions options, CancellationToken cancellationToken)
+ else
{
- var libraryOptions = _libraryManager.GetLibraryOptions(video);
- bool? enableDuringScan = libraryOptions?.ExtractTrickplayImagesDuringLibraryScan;
- bool replace = options.ReplaceAllImages;
-
- if (options.IsAutomated && !enableDuringScan.GetValueOrDefault(false))
- {
- return ItemUpdateType.None;
- }
-
- if (_config.Configuration.TrickplayOptions.ScanBehavior == TrickplayScanBehavior.Blocking)
- {
- await _trickplayManager.RefreshTrickplayData(video, replace, cancellationToken).ConfigureAwait(false);
- }
- else
- {
- _ = _trickplayManager.RefreshTrickplayData(video, replace, cancellationToken).ConfigureAwait(false);
- }
-
- // The core doesn't need to trigger any save operations over this
- return ItemUpdateType.None;
+ _ = _trickplayManager.RefreshTrickplayDataAsync(video, replace, cancellationToken).ConfigureAwait(false);
}
+
+ // The core doesn't need to trigger any save operations over this
+ return ItemUpdateType.None;
}
}