diff --git a/TwitchDownloaderCore/ChatDownloader.cs b/TwitchDownloaderCore/ChatDownloader.cs index d560654a..3a0c5e8b 100644 --- a/TwitchDownloaderCore/ChatDownloader.cs +++ b/TwitchDownloaderCore/ChatDownloader.cs @@ -265,16 +265,7 @@ public async Task DownloadAsync(CancellationToken cancellationToken) { await Task.Delay(100, CancellationToken.None); - outputFileInfo.Refresh(); - if (outputFileInfo.Exists && outputFileInfo.Length == 0) - { - try - { - await outputFs.DisposeAsync(); - outputFileInfo.Delete(); - } - catch { } - } + TwitchHelper.CleanUpClaimedFile(outputFileInfo, outputFs, _progress); throw; } diff --git a/TwitchDownloaderCore/ChatRenderer.cs b/TwitchDownloaderCore/ChatRenderer.cs index 5ffabb11..e34dd419 100644 --- a/TwitchDownloaderCore/ChatRenderer.cs +++ b/TwitchDownloaderCore/ChatRenderer.cs @@ -87,30 +87,8 @@ public async Task RenderVideoAsync(CancellationToken cancellationToken) { await Task.Delay(100, CancellationToken.None); - outputFileInfo.Refresh(); - if (outputFileInfo.Exists && outputFileInfo.Length == 0) - { - try - { - await outputFs.DisposeAsync(); - outputFileInfo.Delete(); - } - catch { } - } - - if (maskFileInfo is not null) - { - maskFileInfo.Refresh(); - if (maskFileInfo.Exists && maskFileInfo.Length == 0) - { - try - { - await maskFs.DisposeAsync(); - maskFileInfo.Delete(); - } - catch { } - } - } + TwitchHelper.CleanUpClaimedFile(outputFileInfo, outputFs, _progress); + TwitchHelper.CleanUpClaimedFile(maskFileInfo, maskFs, _progress); throw; } diff --git a/TwitchDownloaderCore/ChatUpdater.cs b/TwitchDownloaderCore/ChatUpdater.cs index 8cf753e8..cf3c7dc3 100644 --- a/TwitchDownloaderCore/ChatUpdater.cs +++ b/TwitchDownloaderCore/ChatUpdater.cs @@ -46,16 +46,7 @@ public async Task UpdateAsync(CancellationToken cancellationToken) { await Task.Delay(100, CancellationToken.None); - outputFileInfo.Refresh(); - if (outputFileInfo.Exists && outputFileInfo.Length == 0) - { - try - { - await outputFs.DisposeAsync(); - outputFileInfo.Delete(); - } - catch { } - } + TwitchHelper.CleanUpClaimedFile(outputFileInfo, outputFs, _progress); throw; } diff --git a/TwitchDownloaderCore/ClipDownloader.cs b/TwitchDownloaderCore/ClipDownloader.cs index 4ea6393d..12151782 100644 --- a/TwitchDownloaderCore/ClipDownloader.cs +++ b/TwitchDownloaderCore/ClipDownloader.cs @@ -45,16 +45,7 @@ public async Task DownloadAsync(CancellationToken cancellationToken) { await Task.Delay(100, CancellationToken.None); - outputFileInfo.Refresh(); - if (outputFileInfo.Exists && outputFileInfo.Length == 0) - { - try - { - await outputFs.DisposeAsync(); - outputFileInfo.Delete(); - } - catch { } - } + TwitchHelper.CleanUpClaimedFile(outputFileInfo, outputFs, _progress); throw; } @@ -98,7 +89,7 @@ private async Task DownloadAsyncImpl(FileInfo outputFileInfo, FileStream outputF await EncodeClipWithMetadata(tempFile, outputFileInfo.FullName, clipInfo.data.clip, clipChapter, cancellationToken); outputFileInfo.Refresh(); - if (!outputFileInfo.Exists) + if (!outputFileInfo.Exists || outputFileInfo.Length == 0) { File.Move(tempFile, outputFileInfo.FullName); _progress.LogError("Unable to serialize metadata. The download has been completed without custom metadata."); diff --git a/TwitchDownloaderCore/TsMerger.cs b/TwitchDownloaderCore/TsMerger.cs index e913f1bc..c10030c2 100644 --- a/TwitchDownloaderCore/TsMerger.cs +++ b/TwitchDownloaderCore/TsMerger.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -40,16 +41,7 @@ public async Task MergeAsync(CancellationToken cancellationToken) { await Task.Delay(100, CancellationToken.None); - outputFileInfo.Refresh(); - if (outputFileInfo.Exists && outputFileInfo.Length == 0) - { - try - { - await outputFs.DisposeAsync(); - outputFileInfo.Delete(); - } - catch { } - } + TwitchHelper.CleanUpClaimedFile(outputFileInfo, outputFs, _progress); throw; } diff --git a/TwitchDownloaderCore/TwitchHelper.cs b/TwitchDownloaderCore/TwitchHelper.cs index 9c78ceaa..cd16d92d 100644 --- a/TwitchDownloaderCore/TwitchHelper.cs +++ b/TwitchDownloaderCore/TwitchHelper.cs @@ -1,6 +1,7 @@ using SkiaSharp; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.IO.Compression; using System.Linq; @@ -899,6 +900,36 @@ public static FileInfo ClaimFile(string path, Func<FileInfo, FileInfo> fileAlrea return fileInfo; } + public static void CleanUpClaimedFile([AllowNull] FileInfo fileInfo, [AllowNull] FileStream fileStream, ITaskLogger logger) + { + if (fileInfo is null) + { + return; + } + + fileInfo.Refresh(); + if (fileInfo.Exists && fileInfo.Length == 0) + { + try + { + fileStream?.Dispose(); + } + catch + { + // Ignored + } + + try + { + fileInfo.Delete(); + } + catch (Exception e) + { + logger.LogWarning($"Failed to clean up {fileInfo.FullName}: {e.Message}"); + } + } + } + public static DirectoryInfo CreateDirectory(string path) { DirectoryInfo directoryInfo = Directory.CreateDirectory(path); diff --git a/TwitchDownloaderCore/VideoDownloader.cs b/TwitchDownloaderCore/VideoDownloader.cs index 27b7e24e..a026a8cb 100644 --- a/TwitchDownloaderCore/VideoDownloader.cs +++ b/TwitchDownloaderCore/VideoDownloader.cs @@ -53,16 +53,7 @@ public async Task DownloadAsync(CancellationToken cancellationToken) { await Task.Delay(100, CancellationToken.None); - outputFileInfo.Refresh(); - if (outputFileInfo.Exists && outputFileInfo.Length == 0) - { - try - { - await outputFs.DisposeAsync(); - outputFileInfo.Delete(); - } - catch { } - } + TwitchHelper.CleanUpClaimedFile(outputFileInfo, outputFs, _progress); throw; } @@ -128,7 +119,7 @@ await FfmpegMetadata.SerializeAsync(metadataPath, videoInfo.owner.displayName, d var ffmpegRetries = 0; do { - ffmpegExitCode = await Task.Run(() => RunFfmpegVideoCopy(downloadFolder, outputFileInfo, concatListPath, metadataPath, startOffset, endDuration, videoLength), cancellationToken); + ffmpegExitCode = await RunFfmpegVideoCopy(downloadFolder, outputFileInfo, concatListPath, metadataPath, startOffset, endDuration, videoLength, cancellationToken); if (ffmpegExitCode != 0) { _progress.LogError($"Failed to finalize video (code {ffmpegExitCode}), retrying in 10 seconds..."); @@ -326,7 +317,7 @@ private async Task VerifyDownloadedParts(ICollection<M3U8.Stream> playlist, Rang } } - private int RunFfmpegVideoCopy(string tempFolder, FileInfo outputFile, string concatListPath, string metadataPath, decimal startOffset, decimal endDuration, TimeSpan videoLength) + private async Task<int> RunFfmpegVideoCopy(string tempFolder, FileInfo outputFile, string concatListPath, string metadataPath, decimal startOffset, decimal endDuration, TimeSpan videoLength, CancellationToken cancellationToken) { using var process = new Process { @@ -357,7 +348,6 @@ private int RunFfmpegVideoCopy(string tempFolder, FileInfo outputFile, string co outputFile.FullName }; - // TODO: Make this optional - "Safe" and "Exact" trimming methods if (endDuration > 0) { args.Insert(0, "-t"); @@ -391,14 +381,14 @@ private int RunFfmpegVideoCopy(string tempFolder, FileInfo outputFile, string co process.Start(); process.BeginErrorReadLine(); - using var logWriter = File.AppendText(Path.Combine(tempFolder, "ffmpegLog.txt")); + await using var logWriter = File.AppendText(Path.Combine(tempFolder, "ffmpegLog.txt")); logWriter.AutoFlush = true; do // We cannot handle logging inside the ErrorDataReceived lambda because more than 1 can come in at once and cause a race condition. lay295#598 { - Thread.Sleep(100); + await Task.Delay(200, cancellationToken); while (!logQueue.IsEmpty && logQueue.TryDequeue(out var logMessage)) { - logWriter.WriteLine(logMessage); + await logWriter.WriteLineAsync(logMessage); } } while (!process.HasExited || !logQueue.IsEmpty);