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);