From 92efc27d6a7cd57e4826e87a327e46a5a2e9c7f3 Mon Sep 17 00:00:00 2001 From: Scrub <72096833+ScrubN@users.noreply.github.com> Date: Fri, 27 Dec 2024 20:10:37 -0500 Subject: [PATCH] Rewrite cache directory handling (#1279) * Create CacheDirectoryService * Implement CacheDirectoryService in CLI * Implement CacheDirectoryService in WPF * Root cache directory * Implement CacheDirectoryService in Twitch tasks --- TwitchDownloaderCLI/Modes/CacheHandler.cs | 13 ++-- TwitchDownloaderCore/ChatDownloader.cs | 14 ++--- TwitchDownloaderCore/ChatRenderer.cs | 16 ++--- TwitchDownloaderCore/ChatUpdater.cs | 18 +++--- TwitchDownloaderCore/ClipDownloader.cs | 12 ++-- .../Services/CacheDirectoryService.cs | 48 ++++++++++++++ TwitchDownloaderCore/VideoDownloader.cs | 62 ++++++++++--------- TwitchDownloaderWPF/WindowSettings.xaml.cs | 21 +------ 8 files changed, 119 insertions(+), 85 deletions(-) create mode 100644 TwitchDownloaderCore/Services/CacheDirectoryService.cs diff --git a/TwitchDownloaderCLI/Modes/CacheHandler.cs b/TwitchDownloaderCLI/Modes/CacheHandler.cs index f2f8122b..dab907fc 100644 --- a/TwitchDownloaderCLI/Modes/CacheHandler.cs +++ b/TwitchDownloaderCLI/Modes/CacheHandler.cs @@ -1,6 +1,7 @@ using System; using System.IO; using TwitchDownloaderCLI.Modes.Arguments; +using TwitchDownloaderCore.Services; namespace TwitchDownloaderCLI.Modes { @@ -42,19 +43,17 @@ private static void PromptClearCache() private static void ClearTempCache() { - var defaultCacheDirectory = Path.Combine(Path.GetTempPath(), "TwitchDownloader"); + var defaultCacheDirectory = CacheDirectoryService.GetCacheDirectory(Path.GetTempPath()); if (Directory.Exists(defaultCacheDirectory)) { Console.WriteLine("Clearing cache..."); - try + if (CacheDirectoryService.ClearCacheDirectory(Path.GetTempPath(), out var exception)) { - Directory.Delete(defaultCacheDirectory, true); Console.WriteLine("Cache cleared successfully."); + return; } - catch (UnauthorizedAccessException) - { - Console.WriteLine("Insufficient access to clear cache folder."); - } + + Console.WriteLine($"Failed to clear cache: {exception.Message}"); return; } diff --git a/TwitchDownloaderCore/ChatDownloader.cs b/TwitchDownloaderCore/ChatDownloader.cs index 53aaefe0..1e4f7189 100644 --- a/TwitchDownloaderCore/ChatDownloader.cs +++ b/TwitchDownloaderCore/ChatDownloader.cs @@ -10,6 +10,7 @@ using TwitchDownloaderCore.Chat; using TwitchDownloaderCore.Interfaces; using TwitchDownloaderCore.Options; +using TwitchDownloaderCore.Services; using TwitchDownloaderCore.Tools; using TwitchDownloaderCore.TwitchObjects; using TwitchDownloaderCore.TwitchObjects.Gql; @@ -20,6 +21,7 @@ public sealed class ChatDownloader { private readonly ChatDownloadOptions downloadOptions; private readonly ITaskProgress _progress; + private readonly string _cacheDir; private static readonly HttpClient HttpClient = new() { @@ -37,9 +39,7 @@ public ChatDownloader(ChatDownloadOptions chatDownloadOptions, ITaskProgress pro { downloadOptions = chatDownloadOptions; _progress = progress; - downloadOptions.TempFolder = Path.Combine( - string.IsNullOrWhiteSpace(downloadOptions.TempFolder) ? Path.GetTempPath() : Path.GetFullPath(downloadOptions.TempFolder), - "TwitchDownloader"); + _cacheDir = CacheDirectoryService.GetCacheDirectory(downloadOptions.TempFolder); } private static async Task> DownloadSection(Range downloadRange, string videoId, IProgress progress, ITaskLogger logger, ChatFormat format, CancellationToken cancellationToken) @@ -471,13 +471,13 @@ private async Task EmbedImages(ChatRoot chatRoot, CancellationToken cancellation // This is the exact same process as in ChatUpdater.cs but not in a task oriented manner // TODO: Combine this with ChatUpdater in a different file - List thirdPartyEmotes = await TwitchHelper.GetThirdPartyEmotes(chatRoot.comments, chatRoot.streamer.id, downloadOptions.TempFolder, _progress, bttv: downloadOptions.BttvEmotes, ffz: downloadOptions.FfzEmotes, stv: downloadOptions.StvEmotes, cancellationToken: cancellationToken); + List thirdPartyEmotes = await TwitchHelper.GetThirdPartyEmotes(chatRoot.comments, chatRoot.streamer.id, _cacheDir, _progress, bttv: downloadOptions.BttvEmotes, ffz: downloadOptions.FfzEmotes, stv: downloadOptions.StvEmotes, cancellationToken: cancellationToken); _progress.ReportProgress(25); - List firstPartyEmotes = await TwitchHelper.GetEmotes(chatRoot.comments, downloadOptions.TempFolder, _progress, cancellationToken: cancellationToken); + List firstPartyEmotes = await TwitchHelper.GetEmotes(chatRoot.comments, _cacheDir, _progress, cancellationToken: cancellationToken); _progress.ReportProgress(50); - List twitchBadges = await TwitchHelper.GetChatBadges(chatRoot.comments, chatRoot.streamer.id, downloadOptions.TempFolder, _progress, cancellationToken: cancellationToken); + List twitchBadges = await TwitchHelper.GetChatBadges(chatRoot.comments, chatRoot.streamer.id, _cacheDir, _progress, cancellationToken: cancellationToken); _progress.ReportProgress(75); - List twitchBits = await TwitchHelper.GetBits(chatRoot.comments, downloadOptions.TempFolder, chatRoot.streamer.id.ToString(), _progress, cancellationToken: cancellationToken); + List twitchBits = await TwitchHelper.GetBits(chatRoot.comments, _cacheDir, chatRoot.streamer.id.ToString(), _progress, cancellationToken: cancellationToken); _progress.ReportProgress(100); _progress.SetTemplateStatus("Embedding Images {0}%", 0); diff --git a/TwitchDownloaderCore/ChatRenderer.cs b/TwitchDownloaderCore/ChatRenderer.cs index 2851ccd3..db933e4a 100644 --- a/TwitchDownloaderCore/ChatRenderer.cs +++ b/TwitchDownloaderCore/ChatRenderer.cs @@ -18,6 +18,7 @@ using TwitchDownloaderCore.Extensions; using TwitchDownloaderCore.Interfaces; using TwitchDownloaderCore.Options; +using TwitchDownloaderCore.Services; using TwitchDownloaderCore.Tools; using TwitchDownloaderCore.TwitchObjects; @@ -41,6 +42,7 @@ public sealed class ChatRenderer : IDisposable private readonly ITaskProgress _progress; private readonly ChatRenderOptions renderOptions; + private readonly string _cacheDir; private List badgeList = new List(); private List emoteList = new List(); private List emoteThirdList = new List(); @@ -57,9 +59,7 @@ public sealed class ChatRenderer : IDisposable public ChatRenderer(ChatRenderOptions chatRenderOptions, ITaskProgress progress) { renderOptions = chatRenderOptions; - renderOptions.TempFolder = Path.Combine( - string.IsNullOrWhiteSpace(renderOptions.TempFolder) ? Path.GetTempPath() : Path.GetFullPath(renderOptions.TempFolder), - "TwitchDownloader"); + _cacheDir = CacheDirectoryService.GetCacheDirectory(renderOptions.TempFolder); renderOptions.BlockArtPreWrapWidth = 29.166 * renderOptions.FontSize - renderOptions.SidePadding * 2; renderOptions.BlockArtPreWrap = renderOptions.ChatWidth > renderOptions.BlockArtPreWrapWidth; _progress = progress; @@ -1691,7 +1691,7 @@ private async Task> GetScaledBadges(CancellationToken cancellati return new List(); } - var badgeTask = await TwitchHelper.GetChatBadges(chatRoot.comments, chatRoot.streamer.id, renderOptions.TempFolder, _progress, chatRoot.embeddedData, renderOptions.Offline, cancellationToken); + var badgeTask = await TwitchHelper.GetChatBadges(chatRoot.comments, chatRoot.streamer.id, _cacheDir, _progress, chatRoot.embeddedData, renderOptions.Offline, cancellationToken); foreach (var badge in badgeTask) { @@ -1710,7 +1710,7 @@ private async Task> GetScaledBadges(CancellationToken cancellati private async Task> GetScaledEmotes(CancellationToken cancellationToken) { - var emoteTask = await TwitchHelper.GetEmotes(chatRoot.comments, renderOptions.TempFolder, _progress, chatRoot.embeddedData, renderOptions.Offline, cancellationToken); + var emoteTask = await TwitchHelper.GetEmotes(chatRoot.comments, _cacheDir, _progress, chatRoot.embeddedData, renderOptions.Offline, cancellationToken); foreach (var emote in emoteTask) { @@ -1729,7 +1729,7 @@ private async Task> GetScaledEmotes(CancellationToken cancella private async Task> GetScaledThirdEmotes(CancellationToken cancellationToken) { - var emoteThirdTask = await TwitchHelper.GetThirdPartyEmotes(chatRoot.comments, chatRoot.streamer.id, renderOptions.TempFolder, _progress, chatRoot.embeddedData, renderOptions.BttvEmotes, renderOptions.FfzEmotes, + var emoteThirdTask = await TwitchHelper.GetThirdPartyEmotes(chatRoot.comments, chatRoot.streamer.id, _cacheDir, _progress, chatRoot.embeddedData, renderOptions.BttvEmotes, renderOptions.FfzEmotes, renderOptions.StvEmotes, renderOptions.AllowUnlistedEmotes, renderOptions.Offline, cancellationToken); foreach (var emote in emoteThirdTask) @@ -1749,7 +1749,7 @@ private async Task> GetScaledThirdEmotes(CancellationToken can private async Task> GetScaledBits(CancellationToken cancellationToken) { - var cheerTask = await TwitchHelper.GetBits(chatRoot.comments, renderOptions.TempFolder, chatRoot.streamer.id.ToString(), _progress, chatRoot.embeddedData, renderOptions.Offline, cancellationToken); + var cheerTask = await TwitchHelper.GetBits(chatRoot.comments, _cacheDir, chatRoot.streamer.id.ToString(), _progress, chatRoot.embeddedData, renderOptions.Offline, cancellationToken); foreach (var cheer in cheerTask) { @@ -1768,7 +1768,7 @@ private async Task> GetScaledBits(CancellationToken cancellatio private async Task> GetScaledEmojis(CancellationToken cancellationToken) { - var emojis = await TwitchHelper.GetEmojis(renderOptions.TempFolder, renderOptions.EmojiVendor, _progress, cancellationToken); + var emojis = await TwitchHelper.GetEmojis(_cacheDir, renderOptions.EmojiVendor, _progress, cancellationToken); //Assume emojis are 4x (they're 72x72) double emojiScale = 0.5 * renderOptions.ReferenceScale * renderOptions.EmojiScale; diff --git a/TwitchDownloaderCore/ChatUpdater.cs b/TwitchDownloaderCore/ChatUpdater.cs index aee1f5f1..f2aaa22b 100644 --- a/TwitchDownloaderCore/ChatUpdater.cs +++ b/TwitchDownloaderCore/ChatUpdater.cs @@ -7,6 +7,7 @@ using TwitchDownloaderCore.Chat; using TwitchDownloaderCore.Interfaces; using TwitchDownloaderCore.Options; +using TwitchDownloaderCore.Services; using TwitchDownloaderCore.Tools; using TwitchDownloaderCore.TwitchObjects; using TwitchDownloaderCore.TwitchObjects.Gql; @@ -20,14 +21,13 @@ public sealed class ChatUpdater private readonly ChatUpdateOptions _updateOptions; private readonly ITaskProgress _progress; + private readonly string _cacheDir; public ChatUpdater(ChatUpdateOptions updateOptions, ITaskProgress progress) { _updateOptions = updateOptions; _progress = progress; - _updateOptions.TempFolder = Path.Combine( - string.IsNullOrWhiteSpace(_updateOptions.TempFolder) ? Path.GetTempPath() : Path.GetFullPath(_updateOptions.TempFolder), - "TwitchDownloader"); + _cacheDir = CacheDirectoryService.GetCacheDirectory(_updateOptions.TempFolder); } public async Task UpdateAsync(CancellationToken cancellationToken) @@ -273,7 +273,7 @@ private async Task UpdateEmbeds(int currentStep, int totalSteps, CancellationTok private async Task FirstPartyEmoteTask(CancellationToken cancellationToken = default) { - List firstPartyEmoteList = await TwitchHelper.GetEmotes(chatRoot.comments, _updateOptions.TempFolder, _progress, _updateOptions.ReplaceEmbeds ? null : chatRoot.embeddedData, cancellationToken: cancellationToken); + List firstPartyEmoteList = await TwitchHelper.GetEmotes(chatRoot.comments, _cacheDir, _progress, _updateOptions.ReplaceEmbeds ? null : chatRoot.embeddedData, cancellationToken: cancellationToken); int inputCount = chatRoot.embeddedData.firstParty.Count; chatRoot.embeddedData.firstParty = new List(); @@ -292,7 +292,7 @@ private async Task FirstPartyEmoteTask(CancellationToken cancellationToken = def private async Task ThirdPartyEmoteTask(CancellationToken cancellationToken = default) { - List thirdPartyEmoteList = await TwitchHelper.GetThirdPartyEmotes(chatRoot.comments, chatRoot.streamer.id, _updateOptions.TempFolder, _progress, _updateOptions.ReplaceEmbeds ? null : chatRoot.embeddedData, _updateOptions.BttvEmotes, _updateOptions.FfzEmotes, _updateOptions.StvEmotes, cancellationToken: cancellationToken); + List thirdPartyEmoteList = await TwitchHelper.GetThirdPartyEmotes(chatRoot.comments, chatRoot.streamer.id, _cacheDir, _progress, _updateOptions.ReplaceEmbeds ? null : chatRoot.embeddedData, _updateOptions.BttvEmotes, _updateOptions.FfzEmotes, _updateOptions.StvEmotes, cancellationToken: cancellationToken); int inputCount = chatRoot.embeddedData.thirdParty.Count; chatRoot.embeddedData.thirdParty = new List(); @@ -313,7 +313,7 @@ private async Task ThirdPartyEmoteTask(CancellationToken cancellationToken = def private async Task ChatBadgeTask(CancellationToken cancellationToken = default) { - List badgeList = await TwitchHelper.GetChatBadges(chatRoot.comments, chatRoot.streamer.id, _updateOptions.TempFolder, _progress, _updateOptions.ReplaceEmbeds ? null : chatRoot.embeddedData, cancellationToken: cancellationToken); + List badgeList = await TwitchHelper.GetChatBadges(chatRoot.comments, chatRoot.streamer.id, _cacheDir, _progress, _updateOptions.ReplaceEmbeds ? null : chatRoot.embeddedData, cancellationToken: cancellationToken); int inputCount = chatRoot.embeddedData.twitchBadges.Count; chatRoot.embeddedData.twitchBadges = new List(); @@ -329,7 +329,7 @@ private async Task ChatBadgeTask(CancellationToken cancellationToken = default) private async Task BitTask(CancellationToken cancellationToken = default) { - List bitList = await TwitchHelper.GetBits(chatRoot.comments, _updateOptions.TempFolder, chatRoot.streamer.id.ToString(), _progress, _updateOptions.ReplaceEmbeds ? null : chatRoot.embeddedData, cancellationToken: cancellationToken); + List bitList = await TwitchHelper.GetBits(chatRoot.comments, _cacheDir, chatRoot.streamer.id.ToString(), _progress, _updateOptions.ReplaceEmbeds ? null : chatRoot.embeddedData, cancellationToken: cancellationToken); int inputCount = chatRoot.embeddedData.twitchBits.Count; chatRoot.embeddedData.twitchBits = new List(); @@ -363,7 +363,7 @@ private async Task ChatTrimBeginningTask(CancellationToken cancellationToken) return; } - string tempFile = Path.Combine(_updateOptions.TempFolder, Path.GetRandomFileName()); + string tempFile = Path.Combine(_cacheDir, Path.GetRandomFileName()); try { @@ -400,7 +400,7 @@ private async Task ChatTrimEndingTask(CancellationToken cancellationToken) return; } - string tempFile = Path.Combine(_updateOptions.TempFolder, Path.GetRandomFileName()); + string tempFile = Path.Combine(_cacheDir, Path.GetRandomFileName()); try { diff --git a/TwitchDownloaderCore/ClipDownloader.cs b/TwitchDownloaderCore/ClipDownloader.cs index 0130f5fe..2ebce91f 100644 --- a/TwitchDownloaderCore/ClipDownloader.cs +++ b/TwitchDownloaderCore/ClipDownloader.cs @@ -9,6 +9,7 @@ using TwitchDownloaderCore.Extensions; using TwitchDownloaderCore.Interfaces; using TwitchDownloaderCore.Options; +using TwitchDownloaderCore.Services; using TwitchDownloaderCore.Tools; using TwitchDownloaderCore.TwitchObjects.Gql; @@ -19,14 +20,13 @@ public sealed class ClipDownloader private readonly ClipDownloadOptions downloadOptions; private readonly ITaskProgress _progress; private static readonly HttpClient HttpClient = new(); + private readonly string _cacheDir; public ClipDownloader(ClipDownloadOptions clipDownloadOptions, ITaskProgress progress) { downloadOptions = clipDownloadOptions; _progress = progress; - downloadOptions.TempFolder = Path.Combine( - string.IsNullOrWhiteSpace(downloadOptions.TempFolder) ? Path.GetTempPath() : Path.GetFullPath(downloadOptions.TempFolder), - "TwitchDownloader"); + _cacheDir = CacheDirectoryService.GetCacheDirectory(downloadOptions.TempFolder); } public async Task DownloadAsync(CancellationToken cancellationToken) @@ -68,12 +68,12 @@ private async Task DownloadAsyncImpl(FileInfo outputFileInfo, FileStream outputF return; } - if (!Directory.Exists(downloadOptions.TempFolder)) + if (!Directory.Exists(_cacheDir)) { - TwitchHelper.CreateDirectory(downloadOptions.TempFolder); + TwitchHelper.CreateDirectory(_cacheDir); } - var tempFile = Path.Combine(downloadOptions.TempFolder, $"{downloadOptions.Id}_{DateTimeOffset.UtcNow.Ticks}.mp4"); + var tempFile = Path.Combine(_cacheDir, $"{downloadOptions.Id}_{DateTimeOffset.UtcNow.Ticks}.mp4"); try { await using (var tempFileStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read)) diff --git a/TwitchDownloaderCore/Services/CacheDirectoryService.cs b/TwitchDownloaderCore/Services/CacheDirectoryService.cs new file mode 100644 index 00000000..c9e4e4c9 --- /dev/null +++ b/TwitchDownloaderCore/Services/CacheDirectoryService.cs @@ -0,0 +1,48 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; + +namespace TwitchDownloaderCore.Services +{ + public static class CacheDirectoryService + { + private const string CACHE_DIRECTORY_SUFFIX = "TwitchDownloader"; + + public static string GetCacheDirectory([AllowNull] string baseDirectory) + { + if (string.IsNullOrWhiteSpace(baseDirectory)) + baseDirectory = Path.GetTempPath(); + + baseDirectory = Path.GetFullPath(baseDirectory); + + if (new DirectoryInfo(baseDirectory).Name == CACHE_DIRECTORY_SUFFIX) + { + return baseDirectory; + } + + return Path.Combine(baseDirectory, CACHE_DIRECTORY_SUFFIX); + } + + public static bool ClearCacheDirectory([AllowNull] string baseDirectory, out Exception exception) + { + var cacheDirectory = GetCacheDirectory(baseDirectory); + if (!Directory.Exists(cacheDirectory)) + { + exception = null; + return true; + } + + try + { + Directory.Delete(cacheDirectory, true); + exception = null; + return true; + } + catch (Exception ex) + { + exception = ex; + return false; + } + } + } +} \ No newline at end of file diff --git a/TwitchDownloaderCore/VideoDownloader.cs b/TwitchDownloaderCore/VideoDownloader.cs index 282096ab..cc4eb671 100644 --- a/TwitchDownloaderCore/VideoDownloader.cs +++ b/TwitchDownloaderCore/VideoDownloader.cs @@ -14,6 +14,7 @@ using TwitchDownloaderCore.Extensions; using TwitchDownloaderCore.Interfaces; using TwitchDownloaderCore.Options; +using TwitchDownloaderCore.Services; using TwitchDownloaderCore.Tools; using TwitchDownloaderCore.TwitchObjects.Gql; @@ -24,14 +25,15 @@ public sealed class VideoDownloader private readonly VideoDownloadOptions downloadOptions; private readonly HttpClient _httpClient = new() { Timeout = TimeSpan.FromSeconds(30) }; private readonly ITaskProgress _progress; + private readonly string _cacheDir; + private readonly string _vodCacheDir; private bool _shouldClearCache = true; public VideoDownloader(VideoDownloadOptions videoDownloadOptions, ITaskProgress progress = default) { downloadOptions = videoDownloadOptions; - downloadOptions.TempFolder = Path.Combine( - string.IsNullOrWhiteSpace(downloadOptions.TempFolder) ? Path.GetTempPath() : Path.GetFullPath(downloadOptions.TempFolder), - "TwitchDownloader"); + _cacheDir = CacheDirectoryService.GetCacheDirectory(downloadOptions.TempFolder); + _vodCacheDir = Path.Combine(_cacheDir, $"{downloadOptions.Id}_{DateTimeOffset.UtcNow.Ticks}"); downloadOptions.TrimBeginningTime = downloadOptions.TrimBeginningTime >= TimeSpan.Zero ? downloadOptions.TrimBeginningTime : TimeSpan.Zero; downloadOptions.TrimEndingTime = downloadOptions.TrimEndingTime >= TimeSpan.Zero ? downloadOptions.TrimEndingTime : TimeSpan.Zero; _progress = progress; @@ -61,11 +63,7 @@ public async Task DownloadAsync(CancellationToken cancellationToken) private async Task DownloadAsyncImpl(FileInfo outputFileInfo, FileStream outputFs, CancellationToken cancellationToken) { - await TwitchHelper.CleanupAbandonedVideoCaches(downloadOptions.TempFolder, downloadOptions.CacheCleanerCallback, _progress); - - string downloadFolder = Path.Combine( - downloadOptions.TempFolder, - $"{downloadOptions.Id}_{DateTimeOffset.UtcNow.Ticks}"); + await TwitchHelper.CleanupAbandonedVideoCaches(_cacheDir, downloadOptions.CacheCleanerCallback, _progress); _progress.SetStatus("Fetching Video Info [1/4]"); @@ -91,9 +89,13 @@ private async Task DownloadAsyncImpl(FileInfo outputFileInfo, FileStream outputF CheckAvailableStorageSpace(qualityPlaylist.StreamInfo.Bandwidth, videoLength); - if (Directory.Exists(downloadFolder)) - Directory.Delete(downloadFolder, true); - TwitchHelper.CreateDirectory(downloadFolder); + if (Directory.Exists(_vodCacheDir)) + { + _progress.LogVerbose("Download cache already exists! Attempting to delete..."); + Directory.Delete(_vodCacheDir, true); + } + + TwitchHelper.CreateDirectory(_vodCacheDir); if (qualityPlaylist.StreamInfo.Codecs.Any(x => x.StartsWith("av01"))) { @@ -101,23 +103,23 @@ private async Task DownloadAsyncImpl(FileInfo outputFileInfo, FileStream outputF "If you encounter playback issues, try using an FFmpeg-based application like MPV, Kdenlive, or Blender, or re-encode the video file as H.264/AVC or H.265/HEVC with FFmpeg or Handbrake."); } - var headerFile = await GetHeaderFile(playlist, baseUrl, downloadFolder, cancellationToken); + var headerFile = await GetHeaderFile(playlist, baseUrl, cancellationToken); _progress.SetTemplateStatus("Downloading {0}% [2/4]", 0); - await DownloadVideoPartsAsync(playlist.Streams, videoListCrop, baseUrl, downloadFolder, headerFile, airDate, cancellationToken); + await DownloadVideoPartsAsync(playlist.Streams, videoListCrop, baseUrl, headerFile, airDate, cancellationToken); _progress.SetTemplateStatus("Verifying Parts {0}% [3/4]", 0); - await VerifyDownloadedParts(playlist.Streams, videoListCrop, baseUrl, downloadFolder, headerFile, airDate, cancellationToken); + await VerifyDownloadedParts(playlist.Streams, videoListCrop, baseUrl, headerFile, airDate, cancellationToken); _progress.SetTemplateStatus("Finalizing Video {0}% [4/4]", 0); - string metadataPath = Path.Combine(downloadFolder, "metadata.txt"); + string metadataPath = Path.Combine(_vodCacheDir, "metadata.txt"); await FfmpegMetadata.SerializeAsync(metadataPath, downloadOptions.Id.ToString(), videoInfo, downloadOptions.TrimBeginning ? downloadOptions.TrimBeginningTime : TimeSpan.Zero, videoLength, videoChapterResponse.data.video.moments.edges); - var concatListPath = Path.Combine(downloadFolder, "concat.txt"); + var concatListPath = Path.Combine(_vodCacheDir, "concat.txt"); var streamIds = GetStreamIds(playlist); await FfmpegConcatList.SerializeAsync(concatListPath, playlist, videoListCrop, streamIds, cancellationToken); @@ -127,7 +129,7 @@ await FfmpegMetadata.SerializeAsync(metadataPath, downloadOptions.Id.ToString(), var ffmpegRetries = 0; do { - ffmpegExitCode = await RunFfmpegVideoCopy(downloadFolder, outputFileInfo, concatListPath, metadataPath, startOffset, endDuration, videoLength, ffmpegRetries > 0, cancellationToken); + ffmpegExitCode = await RunFfmpegVideoCopy(outputFileInfo, concatListPath, metadataPath, startOffset, endDuration, videoLength, ffmpegRetries > 0, cancellationToken); if (ffmpegExitCode != 0) { _progress.LogError($"Failed to finalize video (code {ffmpegExitCode}), retrying in 5 seconds..."); @@ -139,7 +141,7 @@ await FfmpegMetadata.SerializeAsync(metadataPath, downloadOptions.Id.ToString(), if (ffmpegExitCode != 0 || !outputFileInfo.Exists || outputFileInfo.Length == 0) { _shouldClearCache = false; - throw new Exception($"Failed to finalize video. The download cache has not been cleared and can be found at {downloadFolder} along with a log file."); + throw new Exception($"Failed to finalize video. The download cache has not been cleared and can be found at {_vodCacheDir} along with a log file."); } _progress.ReportProgress(100); @@ -150,12 +152,12 @@ await FfmpegMetadata.SerializeAsync(metadataPath, downloadOptions.Id.ToString(), if (_shouldClearCache) { - Cleanup(downloadFolder); + Cleanup(_vodCacheDir); } } } - private async Task GetHeaderFile(M3U8 playlist, Uri baseUrl, string downloadFolder, CancellationToken cancellationToken) + private async Task GetHeaderFile(M3U8 playlist, Uri baseUrl, CancellationToken cancellationToken) { var map = playlist.FileMetadata.Map; if (string.IsNullOrWhiteSpace(map?.Uri)) @@ -168,7 +170,7 @@ private async Task GetHeaderFile(M3U8 playlist, Uri baseUrl, string down _progress.LogWarning($"Byte range was {map.ByteRange}, but is not yet implemented!"); } - var destinationFile = Path.Combine(downloadFolder, map.Uri); + var destinationFile = Path.Combine(_vodCacheDir, map.Uri); var uri = new Uri(baseUrl, map.Uri); _progress.LogVerbose($"Downloading header file from '{uri}' to '{destinationFile}'"); @@ -188,7 +190,7 @@ private void CheckAvailableStorageSpace(int bandwidth, TimeSpan videoLength) var videoSizeInBytes = VideoSizeEstimator.EstimateVideoSize(bandwidth, downloadOptions.TrimBeginning ? downloadOptions.TrimBeginningTime : TimeSpan.Zero, downloadOptions.TrimEnding ? downloadOptions.TrimEndingTime : videoLength); - var tempFolderDrive = DriveHelper.GetOutputDrive(downloadOptions.TempFolder); + var tempFolderDrive = DriveHelper.GetOutputDrive(_vodCacheDir); var destinationDrive = DriveHelper.GetOutputDrive(downloadOptions.Filename); if (tempFolderDrive.Name == destinationDrive.Name) @@ -213,7 +215,7 @@ private void CheckAvailableStorageSpace(int bandwidth, TimeSpan videoLength) } } - private async Task DownloadVideoPartsAsync(IReadOnlyCollection playlist, Range videoListCrop, Uri baseUrl, string downloadFolder, [AllowNull] string headerFile, DateTimeOffset vodAirDate, CancellationToken cancellationToken) + private async Task DownloadVideoPartsAsync(IReadOnlyCollection playlist, Range videoListCrop, Uri baseUrl, [AllowNull] string headerFile, DateTimeOffset vodAirDate, CancellationToken cancellationToken) { var partCount = videoListCrop.GetOffsetAndLength(playlist.Count).Length; var videoPartsQueue = new ConcurrentQueue(playlist.Take(videoListCrop).Select(x => x.Path)); @@ -221,7 +223,7 @@ private async Task DownloadVideoPartsAsync(IReadOnlyCollection play var downloadThreads = new VideoDownloadThread[downloadOptions.DownloadThreads]; for (var i = 0; i < downloadOptions.DownloadThreads; i++) { - downloadThreads[i] = new VideoDownloadThread(videoPartsQueue, _httpClient, baseUrl, downloadFolder, headerFile, vodAirDate, downloadOptions.ThrottleKib, _progress, cancellationToken); + downloadThreads[i] = new VideoDownloadThread(videoPartsQueue, _httpClient, baseUrl, _vodCacheDir, headerFile, vodAirDate, downloadOptions.ThrottleKib, _progress, cancellationToken); } var downloadExceptions = await WaitForDownloadThreads(downloadThreads, videoPartsQueue, partCount, cancellationToken); @@ -320,7 +322,7 @@ private void LogDownloadThreadExceptions(IReadOnlyCollection download _progress.LogInfo(sb.ToString()); } - private async Task VerifyDownloadedParts(IReadOnlyCollection playlist, Range videoListCrop, Uri baseUrl, string downloadFolder, [AllowNull] string headerFile, DateTimeOffset vodAirDate, CancellationToken cancellationToken) + private async Task VerifyDownloadedParts(IReadOnlyCollection playlist, Range videoListCrop, Uri baseUrl, [AllowNull] string headerFile, DateTimeOffset vodAirDate, CancellationToken cancellationToken) { var failedParts = new List(); var partCount = videoListCrop.GetOffsetAndLength(playlist.Count).Length; @@ -328,7 +330,7 @@ private async Task VerifyDownloadedParts(IReadOnlyCollection playli foreach (var part in playlist.Take(videoListCrop)) { - var filePath = Path.Combine(downloadFolder, DownloadTools.RemoveQueryString(part.Path)); + var filePath = Path.Combine(_vodCacheDir, DownloadTools.RemoveQueryString(part.Path)); var fi = new FileInfo(filePath); if (!fi.Exists || fi.Length == 0) { @@ -352,7 +354,7 @@ private async Task VerifyDownloadedParts(IReadOnlyCollection playli } _progress.LogInfo($"The following parts will be redownloaded: {string.Join(", ", failedParts)}"); - await DownloadVideoPartsAsync(failedParts, Range.All, baseUrl, downloadFolder, headerFile, vodAirDate, cancellationToken); + await DownloadVideoPartsAsync(failedParts, Range.All, baseUrl, headerFile, vodAirDate, cancellationToken); } } @@ -372,7 +374,7 @@ private FfmpegConcatList.StreamIds GetStreamIds(M3U8 playlist) } } - private async Task RunFfmpegVideoCopy(string tempFolder, FileInfo outputFile, string concatListPath, string metadataPath, decimal startOffset, decimal endDuration, TimeSpan videoLength, bool disableAudioCopy, CancellationToken cancellationToken) + private async Task RunFfmpegVideoCopy(FileInfo outputFile, string concatListPath, string metadataPath, decimal startOffset, decimal endDuration, TimeSpan videoLength, bool disableAudioCopy, CancellationToken cancellationToken) { using var process = new Process { @@ -384,7 +386,7 @@ private async Task RunFfmpegVideoCopy(string tempFolder, FileInfo outputFil RedirectStandardInput = false, RedirectStandardOutput = true, RedirectStandardError = true, - WorkingDirectory = tempFolder + WorkingDirectory = _vodCacheDir } }; @@ -445,7 +447,7 @@ private async Task RunFfmpegVideoCopy(string tempFolder, FileInfo outputFil process.Start(); process.BeginErrorReadLine(); - await using var logWriter = File.AppendText(Path.Combine(tempFolder, "ffmpegLog.txt")); + await using var logWriter = File.AppendText(Path.Combine(_vodCacheDir, "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 { diff --git a/TwitchDownloaderWPF/WindowSettings.xaml.cs b/TwitchDownloaderWPF/WindowSettings.xaml.cs index dd6d4b17..2349c934 100644 --- a/TwitchDownloaderWPF/WindowSettings.xaml.cs +++ b/TwitchDownloaderWPF/WindowSettings.xaml.cs @@ -8,6 +8,7 @@ using System.Windows.Documents; using System.Windows.Input; using HandyControl.Data; +using TwitchDownloaderCore.Services; using TwitchDownloaderWPF.Extensions; using TwitchDownloaderWPF.Models; using TwitchDownloaderWPF.Properties; @@ -112,24 +113,8 @@ private void BtnClearCache_Click(object sender, RoutedEventArgs e) if (messageBoxResult == MessageBoxResult.Yes) { //Let's clear the user selected temp folder and the default one - string defaultDir = Path.Combine(Path.GetTempPath(), "TwitchDownloader"); - string tempDir = Path.Combine(Settings.Default.TempPath, "TwitchDownloader"); - if (Directory.Exists(defaultDir)) - { - try - { - Directory.Delete(defaultDir, true); - } - catch { } - } - if (Directory.Exists(tempDir)) - { - try - { - Directory.Delete(tempDir, true); - } - catch { } - } + CacheDirectoryService.ClearCacheDirectory(Settings.Default.TempPath, out _); + CacheDirectoryService.ClearCacheDirectory(Path.GetTempPath(), out _); } }