mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-09 03:04:24 -04:00
Prune trickplay data on regenerate and scan (#14085)
This commit is contained in:
parent
44b5de1568
commit
e1a5c16404
@ -7,6 +7,7 @@ using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsyncKeyedLock;
|
||||
using J2N.Collections.Generic.Extensions;
|
||||
using Jellyfin.Database.Implementations;
|
||||
using Jellyfin.Database.Implementations.Entities;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
@ -80,7 +81,7 @@ public class TrickplayManager : ITrickplayManager
|
||||
public async Task MoveGeneratedTrickplayDataAsync(Video video, LibraryOptions libraryOptions, CancellationToken cancellationToken)
|
||||
{
|
||||
var options = _config.Configuration.TrickplayOptions;
|
||||
if (!CanGenerateTrickplay(video, options.Interval, libraryOptions))
|
||||
if (libraryOptions is null || !libraryOptions.EnableTrickplayImageExtraction || !CanGenerateTrickplay(video, options.Interval))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -137,25 +138,84 @@ public class TrickplayManager : ITrickplayManager
|
||||
/// <inheritdoc />
|
||||
public async Task RefreshTrickplayDataAsync(Video video, bool replace, LibraryOptions libraryOptions, CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.LogDebug("Trickplay refresh for {ItemId} (replace existing: {Replace})", video.Id, replace);
|
||||
|
||||
var options = _config.Configuration.TrickplayOptions;
|
||||
if (options.Interval < 1000)
|
||||
if (!CanGenerateTrickplay(video, options.Interval) || libraryOptions is null)
|
||||
{
|
||||
_logger.LogWarning("Trickplay image interval {Interval} is too small, reset to the minimum valid value of 1000", options.Interval);
|
||||
options.Interval = 1000;
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var width in options.WidthResolutions)
|
||||
var dbContext = await _dbProvider.CreateDbContextAsync(cancellationToken).ConfigureAwait(false);
|
||||
await using (dbContext.ConfigureAwait(false))
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
await RefreshTrickplayDataInternal(
|
||||
video,
|
||||
replace,
|
||||
width,
|
||||
options,
|
||||
libraryOptions,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
var saveWithMedia = libraryOptions.SaveTrickplayWithMedia;
|
||||
var trickplayDirectory = _pathManager.GetTrickplayDirectory(video, saveWithMedia);
|
||||
if (!libraryOptions.EnableTrickplayImageExtraction || replace)
|
||||
{
|
||||
// Prune existing data
|
||||
if (Directory.Exists(trickplayDirectory))
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.Delete(trickplayDirectory, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning("Unable to clear trickplay directory: {Directory}: {Exception}", trickplayDirectory, ex);
|
||||
}
|
||||
}
|
||||
|
||||
await dbContext.TrickplayInfos
|
||||
.Where(i => i.ItemId.Equals(video.Id))
|
||||
.ExecuteDeleteAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (!replace)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogDebug("Trickplay refresh for {ItemId} (replace existing: {Replace})", video.Id, replace);
|
||||
|
||||
if (options.Interval < 1000)
|
||||
{
|
||||
_logger.LogWarning("Trickplay image interval {Interval} is too small, reset to the minimum valid value of 1000", options.Interval);
|
||||
options.Interval = 1000;
|
||||
}
|
||||
|
||||
foreach (var width in options.WidthResolutions)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
await RefreshTrickplayDataInternal(
|
||||
video,
|
||||
replace,
|
||||
width,
|
||||
options,
|
||||
saveWithMedia,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
// Cleanup old trickplay files
|
||||
var existingFolders = Directory.GetDirectories(trickplayDirectory).ToList();
|
||||
var trickplayInfos = await dbContext.TrickplayInfos
|
||||
.AsNoTracking()
|
||||
.Where(i => i.ItemId.Equals(video.Id))
|
||||
.ToListAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
var expectedFolders = trickplayInfos.Select(i => GetTrickplayDirectory(video, i.TileWidth, i.TileHeight, i.Width, saveWithMedia)).ToList();
|
||||
var foldersToRemove = existingFolders.Except(expectedFolders);
|
||||
foreach (var folder in foldersToRemove)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogWarning("Pruning trickplay files for {Item}", video.Path);
|
||||
Directory.Delete(folder, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning("Unable to remove trickplay directory: {Directory}: {Exception}", folder, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,14 +224,9 @@ public class TrickplayManager : ITrickplayManager
|
||||
bool replace,
|
||||
int width,
|
||||
TrickplayOptions options,
|
||||
LibraryOptions libraryOptions,
|
||||
bool saveWithMedia,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (!CanGenerateTrickplay(video, options.Interval, libraryOptions))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var imgTempDir = string.Empty;
|
||||
|
||||
using (await _resourcePool.LockAsync(cancellationToken).ConfigureAwait(false))
|
||||
@ -215,7 +270,6 @@ public class TrickplayManager : ITrickplayManager
|
||||
|
||||
var tileWidth = options.TileWidth;
|
||||
var tileHeight = options.TileHeight;
|
||||
var saveWithMedia = libraryOptions is not null && libraryOptions.SaveTrickplayWithMedia;
|
||||
var outputDir = new DirectoryInfo(GetTrickplayDirectory(video, tileWidth, tileHeight, actualWidth, saveWithMedia));
|
||||
|
||||
// Import existing trickplay tiles
|
||||
@ -402,7 +456,7 @@ public class TrickplayManager : ITrickplayManager
|
||||
return trickplayInfo;
|
||||
}
|
||||
|
||||
private bool CanGenerateTrickplay(Video video, int interval, LibraryOptions libraryOptions)
|
||||
private bool CanGenerateTrickplay(Video video, int interval)
|
||||
{
|
||||
var videoType = video.VideoType;
|
||||
if (videoType == VideoType.Iso || videoType == VideoType.Dvd || videoType == VideoType.BluRay)
|
||||
@ -430,11 +484,6 @@ public class TrickplayManager : ITrickplayManager
|
||||
return false;
|
||||
}
|
||||
|
||||
if (libraryOptions is null || !libraryOptions.EnableTrickplayImageExtraction)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Can't extract images if there are no video streams
|
||||
return video.GetMediaStreams().Count > 0;
|
||||
}
|
||||
|
@ -59,14 +59,14 @@ public class TrickplayImagesTask : IScheduledTask
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
return
|
||||
[
|
||||
new TaskTriggerInfo
|
||||
{
|
||||
Type = TaskTriggerInfoType.DailyTrigger,
|
||||
TimeOfDayTicks = TimeSpan.FromHours(3).Ticks
|
||||
}
|
||||
};
|
||||
];
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -74,8 +74,8 @@ public class TrickplayImagesTask : IScheduledTask
|
||||
{
|
||||
var query = new InternalItemsQuery
|
||||
{
|
||||
MediaTypes = new[] { MediaType.Video },
|
||||
SourceTypes = new[] { SourceType.Library },
|
||||
MediaTypes = [MediaType.Video],
|
||||
SourceTypes = [SourceType.Library],
|
||||
IsVirtualItem = false,
|
||||
IsFolder = false,
|
||||
Recursive = true,
|
||||
|
Loading…
x
Reference in New Issue
Block a user