From ee9ce2840b07523f8081257157fb0999e65c1e76 Mon Sep 17 00:00:00 2001 From: Roger Far Date: Mon, 28 Nov 2022 20:29:03 -0700 Subject: [PATCH] Add support for multiple layers of compression in the unpack client. --- .../RdtClient.Service/Helpers/FileHelper.cs | 36 +++++ .../Services/UnpackClient.cs | 136 ++++++++++++------ 2 files changed, 131 insertions(+), 41 deletions(-) diff --git a/server/RdtClient.Service/Helpers/FileHelper.cs b/server/RdtClient.Service/Helpers/FileHelper.cs index 1766984..d7cb248 100644 --- a/server/RdtClient.Service/Helpers/FileHelper.cs +++ b/server/RdtClient.Service/Helpers/FileHelper.cs @@ -37,4 +37,40 @@ public static class FileHelper } } } + + public static async Task DeleteDirectory(String path) + { + if (String.IsNullOrWhiteSpace(path)) + { + return; + } + + if (!Directory.Exists(path)) + { + return; + } + + var retry = 0; + + while (true) + { + try + { + Directory.Delete(path, true); + + break; + } + catch + { + if (retry >= 3) + { + throw; + } + + retry++; + + await Task.Delay(1000 * retry); + } + } + } } \ No newline at end of file diff --git a/server/RdtClient.Service/Services/UnpackClient.cs b/server/RdtClient.Service/Services/UnpackClient.cs index 6994d03..d58c0e2 100644 --- a/server/RdtClient.Service/Services/UnpackClient.cs +++ b/server/RdtClient.Service/Services/UnpackClient.cs @@ -74,50 +74,52 @@ public class UnpackClient return; } - await using (Stream stream = File.OpenRead(filePath)) + var extractPath = _destinationPath; + String? extractPathTemp = null; + + var archiveEntries = await GetArchiveFiles(filePath); + + if (!archiveEntries.Any(m => m.StartsWith(_torrent.RdName + @"\")) && !archiveEntries.Any(m => m.StartsWith(_torrent.RdName + @"/"))) { - using var archive = RarArchive.Open(stream); - - BytesTotal = archive.TotalSize; - - var entries = archive.Entries.Where(entry => !entry.IsDirectory) - .ToList(); - - _rarfileStatus = entries.ToDictionary(entry => entry.Key, _ => 0L); - _rarCurrentEntry = null; - archive.CompressedBytesRead += ArchiveOnCompressedBytesRead; - - var extractPath = _destinationPath; - - if (!entries.Any(m => m.Key.StartsWith(_torrent.RdName + @"\")) && !entries.Any(m => m.Key.StartsWith(_torrent.RdName + @"/"))) - { - extractPath = Path.Combine(_destinationPath, _torrent.RdName!); - } - - if (entries.Any(m => m.Key.Contains(".r00"))) - { - extractPath = Path.Combine(extractPath, "Temp"); - } - - foreach (var entry in entries) - { - if (_cancelled) - { - return; - } - - _rarCurrentEntry = entry; - - entry.WriteToDirectory(extractPath, - new ExtractionOptions - { - ExtractFullPath = true, - Overwrite = true - }); - } + extractPath = Path.Combine(_destinationPath, _torrent.RdName!); } - await FileHelper.Delete(filePath); + if (archiveEntries.Any(m => m.Contains(".r00"))) + { + extractPathTemp = Path.Combine(extractPath, Guid.NewGuid().ToString()); + + if (!Directory.Exists(extractPathTemp)) + { + Directory.CreateDirectory(extractPathTemp); + } + } + + if (extractPathTemp != null) + { + Extract(filePath, extractPathTemp); + + await FileHelper.Delete(filePath); + + var rarFiles = Directory.GetFiles(extractPathTemp, "*.r00", SearchOption.TopDirectoryOnly); + + foreach (var rarFile in rarFiles) + { + var mainRarFile = Path.ChangeExtension(rarFile, ".rar"); + + if (File.Exists(mainRarFile)) + { + Extract(mainRarFile, extractPath); + } + + await FileHelper.DeleteDirectory(extractPathTemp); + } + } + else + { + Extract(filePath, extractPath); + + await FileHelper.Delete(filePath); + } } catch (Exception ex) { @@ -129,6 +131,58 @@ public class UnpackClient } } + private async Task> GetArchiveFiles(String filePath) + { + await using Stream stream = File.OpenRead(filePath); + + using var archive = RarArchive.Open(stream); + + BytesTotal = archive.TotalSize; + + var entries = archive.Entries + .Where(entry => !entry.IsDirectory) + .Select(m => m.Key) + .ToList(); + + return entries; + } + + private void Extract(String filePath, String extractPath) + { + var parts = ArchiveFactory.GetFileParts(filePath); + + using var archive = RarArchive.Open(parts.Select(m => new FileInfo(m))); + + if (archive.IsComplete) + { + BytesTotal = archive.TotalSize; + } + + var entries = archive.Entries.Where(entry => !entry.IsDirectory) + .ToList(); + + _rarfileStatus = entries.ToDictionary(entry => entry.Key, _ => 0L); + _rarCurrentEntry = null; + archive.CompressedBytesRead += ArchiveOnCompressedBytesRead; + + foreach (var entry in entries) + { + if (_cancelled) + { + throw new Exception("Task was cancelled"); + } + + _rarCurrentEntry = entry; + + entry.WriteToDirectory(extractPath, + new ExtractionOptions + { + ExtractFullPath = true, + Overwrite = true + }); + } + } + private void ArchiveOnCompressedBytesRead(Object? sender, CompressedBytesReadEventArgs e) { if (_rarCurrentEntry == null)