Skip to content
This repository has been archived by the owner on Apr 13, 2024. It is now read-only.

Commit

Permalink
Adds video integrity handler
Browse files Browse the repository at this point in the history
  • Loading branch information
redbaty committed Nov 9, 2023
1 parent 76682b0 commit 6cb9608
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Wasari.App/NotificationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public async ValueTask SendNotifcationForDownloadedEpisodeAsync(IEnumerable<Down
await SendNotificationAsync(message);
}

private async ValueTask SendNotificationAsync(string message)
public async ValueTask SendNotificationAsync(string message)
{
await HttpClient.PostAsJsonAsync(string.Empty, new
{
Expand Down
11 changes: 11 additions & 0 deletions Wasari.Daemon/Controllers/MediaController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,15 @@ public async Task<IActionResult> Download([FromBody] DownloadRequest request, [F
await Bus.SendAsync(request);
return Accepted();
}

[HttpPost("check-video-integrity")]
public async Task<IActionResult> CheckVideoIntegrity([FromBody] CheckVideoIntegrityRequest request, [FromServices] IValidator<CheckVideoIntegrityRequest> validator)
{
var validationResult = await validator.ValidateAsync(request);

if (!validationResult.IsValid) return BadRequest(validationResult.Errors);

await Bus.SendAsync(request);
return Accepted();
}
}
33 changes: 33 additions & 0 deletions Wasari.Daemon/Handlers/CheckVideoIntegrityHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System.Text;
using Microsoft.Extensions.Options;
using Wasari.App;
using Wasari.Daemon.Models;
using Wasari.Daemon.Options;
using Wasari.FFmpeg;

namespace Wasari.Daemon.Handlers;

public class CheckVideoIntegrityHandler
{
public async ValueTask Handle(CheckVideoIntegrityRequest request, IOptions<DaemonOptions> daemonOptions, IServiceProvider serviceProvider, FFmpegService fFmpegService, ILogger<CheckVideoIntegrityHandler> logger)
{
var fileIsValid = await fFmpegService.CheckIfVideoStreamIsValid(request.Path);
logger.LogInformation("File {Path} is {Status}", request.Path, fileIsValid ? "valid" : "invalid");

if(fileIsValid) return;

if (request.DeleteFileIfInvalid)
{
File.Delete(request.Path);
logger.LogInformation("File {Path} was deleted", request.Path);
}

if (daemonOptions.Value.NotificationEnabled && serviceProvider.GetService<NotificationService>() is { } notificationService)
{
var fileName = Path.GetFileName(request.Path);
var sb = new StringBuilder($"File {fileName} was corrupted");
if(request.DeleteFileIfInvalid) sb.Append(" and was deleted");
await notificationService.SendNotificationAsync(sb.ToString());
}
}
}
3 changes: 3 additions & 0 deletions Wasari.Daemon/Models/CheckVideoIntegrityRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace Wasari.Daemon.Models;

public record CheckVideoIntegrityRequest(string Path, bool DeleteFileIfInvalid);
1 change: 1 addition & 0 deletions Wasari.Daemon/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@

opts.Discovery.DisableConventionalDiscovery();
opts.Discovery.IncludeType<DownloadRequestHandler>();
opts.Discovery.IncludeType<CheckVideoIntegrityHandler>();

opts.PersistMessagesWithPostgresql(postgresCs, Environment.GetEnvironmentVariable("POSTGRESQL_SCHEMA") ?? "public");
opts.UseEntityFrameworkCoreTransactions();
Expand Down
15 changes: 15 additions & 0 deletions Wasari.Daemon/Validators/CheckVideoIntegrityRequestValidator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using FluentValidation;
using Wasari.Daemon.Models;

// ReSharper disable UnusedType.Global

namespace Wasari.Daemon.Validators;

public class CheckVideoIntegrityRequestValidator : AbstractValidator<CheckVideoIntegrityRequest>
{
public CheckVideoIntegrityRequestValidator()
{
RuleFor(i => i.Path)
.NotEmpty();
}
}
26 changes: 26 additions & 0 deletions Wasari.FFmpeg/FFmpegService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,32 @@ private static Command CreateCommand()
var tempFileName = Path.GetFileNameWithoutExtension(Path.GetTempFileName());
return Path.Combine(Path.GetTempPath(), $"{tempFileName}.mkv");
}

public async Task<bool> CheckIfVideoStreamIsValid(string filePath)
{
try
{
var fileAnalysis = await FFProbe.AnalyseAsync(filePath);

if (fileAnalysis.ErrorData.Count > 0)
return false;

var videoDuration = fileAnalysis.VideoStreams.Max(o => o.Duration);

if (videoDuration == TimeSpan.Zero && (fileAnalysis.PrimaryVideoStream?.Tags?.TryGetValue("DURATION", out var durationStr) ?? false))
{
videoDuration = TimeSpan.Parse(durationStr);
}

var subtitleDuration = fileAnalysis.SubtitleStreams.Max(o => o.Duration).Subtract(TimeSpan.FromSeconds(5));
return subtitleDuration <= videoDuration;
}
catch (Exception e)
{
Logger.LogError(e, "Failed to check if video stream is valid");
return false;
}
}

public async Task DownloadEpisode<T>(T episode, string filePath, IProgress<FFmpegProgressUpdate>? progress) where T : IWasariEpisode
{
Expand Down

0 comments on commit 6cb9608

Please sign in to comment.