Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Cancel option and progress for manual extraction #205

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion FoliCon/Models/Api/DArtDownloadResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ public record DArtDownloadResponse
[JsonIgnore]
public string LocalDownloadPath { get; set; }

public string GetFileSizeHumanReadable()
public string FileSizeHumanReadable => GetFileSizeHumanReadable();

private string GetFileSizeHumanReadable()
{
return ConvertHelper.ToFileSize(FileSizeBytes);
}
Expand Down
23 changes: 23 additions & 0 deletions FoliCon/Models/Data/ProgressInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace FoliCon.Models.Data;

public class ProgressInfo : BindableBase
{
private int _current;
private int _total;
private string _text;
public int Current { get => _current; set => SetProperty(ref _current, value); }
public int Total { get => _total; set => SetProperty(ref _total, value); }
public string Text { get => _text; set => SetProperty(ref _text, value); }

public double Progress => 100 * ((double)Current / Total);

public ProgressInfo(int current, int total)
{
Current = current;
Total = total;
}
public ProgressInfo(int current, int total, string text) : this(current, total)
{
Text = text;
}
}
37 changes: 37 additions & 0 deletions FoliCon/Modules/Convertor/ImageCacheConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
namespace FoliCon.Modules.Convertor;

/// <summary>
/// Converts an image path to a BitmapImage with caching to improve performance and thread safety.
/// CREDIT: https://stackoverflow.com/a/37652158/8076598
/// </summary>
public class ImageCacheConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var path = (string)value;
if (string.IsNullOrEmpty(path))
{
return null;
}

try
{
var image = new BitmapImage();
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = new Uri(path, UriKind.Absolute);
image.EndInit();
image.Freeze(); // Improve performance and thread safety
return image;
}
catch
{
return null; // Return null or a default image in case of error
}
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException("Not implemented.");
}
}
34 changes: 27 additions & 7 deletions FoliCon/Modules/DeviantArt/DArt.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using FoliCon.Models.Api;
using FoliCon.Models.Data;
using FoliCon.Modules.Configuration;
using FoliCon.Modules.Extension;
using FoliCon.Modules.utils;
Expand Down Expand Up @@ -102,24 +103,41 @@ public async Task<DArtDownloadResponse> Download(string deviationId)
{
GetClientAccessTokenAsync();
var dArtDownloadResponse = await GetDArtDownloadResponseAsync(deviationId);
await TryExtraction(deviationId, dArtDownloadResponse, CancellationToken.None, new Progress<ProgressInfo>(_ => { }));

return dArtDownloadResponse;
}

private async Task<DArtDownloadResponse> TryExtraction(string deviationId,
DArtDownloadResponse dArtDownloadResponse, CancellationToken cancellationToken,
IProgress<ProgressInfo> progressCallback)
{
progressCallback.Report(new ProgressInfo(0, 1, LangProvider.Instance.Downloading));
var targetDirectoryPath = FileUtils.CreateDirectoryInFoliConTemp(deviationId);
dArtDownloadResponse.LocalDownloadPath = targetDirectoryPath;
var downloadResponse = await Services.HttpC.GetAsync(dArtDownloadResponse.Src);
var downloadResponse = await Services.HttpC.GetAsync(dArtDownloadResponse.Src, cancellationToken);

if (FileUtils.IsCompressedArchive(dArtDownloadResponse.Filename))
{
await ProcessCompressedFiles(downloadResponse, targetDirectoryPath);
await ProcessCompressedFiles(downloadResponse, targetDirectoryPath,cancellationToken, progressCallback);
}
else
{
await FileStreamToDestination(downloadResponse, targetDirectoryPath, dArtDownloadResponse.Filename);
}

FileUtils.DeleteDirectoryIfEmpty(targetDirectoryPath);

return dArtDownloadResponse;
}


public async Task<DArtDownloadResponse> ExtractDeviation(string deviationId,
DArtDownloadResponse dArtDownloadResponse, CancellationToken cancellationToken,
IProgress<ProgressInfo> progressCallback)
{
GetClientAccessTokenAsync();
return await TryExtraction(deviationId, dArtDownloadResponse, cancellationToken, progressCallback);

}
public async Task<DArtDownloadResponse> GetDArtDownloadResponseAsync(string deviationId)
{
var url = GetDownloadApiUrl(deviationId);
Expand All @@ -128,10 +146,12 @@ public async Task<DArtDownloadResponse> GetDArtDownloadResponseAsync(string devi
return JsonConvert.DeserializeObject<DArtDownloadResponse>(jsonData);
}

private async Task ProcessCompressedFiles(HttpResponseMessage downloadResponse, string targetDirectoryPath)
private async Task ProcessCompressedFiles(HttpResponseMessage downloadResponse, string targetDirectoryPath,
CancellationToken cancellationToken,
IProgress<ProgressInfo> progressCallback)
{
await using var stream = await downloadResponse.Content.ReadAsStreamAsync();
stream.ExtractPngAndIcoToDirectory(targetDirectoryPath);
await using var stream = await downloadResponse.Content.ReadAsStreamAsync(cancellationToken);
stream.ExtractPngAndIcoToDirectory(targetDirectoryPath, cancellationToken, progressCallback);
}

private async Task FileStreamToDestination(HttpResponseMessage downloadResponse, string targetDirectoryPath,
Expand Down
58 changes: 32 additions & 26 deletions FoliCon/Modules/Extension/StreamExtension.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using FoliCon.Modules.utils;
using FoliCon.Models.Data;
using FoliCon.Modules.utils;
using SharpCompress.Archives;
using SharpCompress.Common;
using SharpCompress.Readers;

namespace FoliCon.Modules.Extension;

Expand All @@ -11,35 +12,40 @@ public static class StreamExtensions
/// </summary>
/// <param name="archiveStream">The compressed stream containing the PNG and ICO files.</param>
/// <param name="targetPath">The path of the directory where the extracted files should be written.</param>
public static void ExtractPngAndIcoToDirectory(this Stream archiveStream, string targetPath)
/// <param name="cancellationToken"></param>
/// <param name="progressCallback">A Callback which can be used to report the progress of the extraction.</param>
public static void ExtractPngAndIcoToDirectory(this Stream archiveStream, string targetPath,
CancellationToken cancellationToken,
IProgress<ProgressInfo> progressCallback)
{
using var reader = ReaderFactory.Open(archiveStream);
while (reader.MoveToNextEntry())
using var reader = ArchiveFactory.Open(archiveStream);
var pngAndIcoEntries = reader.Entries.Where(entry =>
(!entry.IsDirectory || !IsUnwantedDirectoryOrFileType(entry)) && FileUtils.IsPngOrIco(entry.Key));
var pngAndIcoFiles = pngAndIcoEntries as IArchiveEntry[] ?? pngAndIcoEntries.ToArray();
var totalCount = pngAndIcoFiles.Length;
var extractionProgress = new ProgressInfo(0, totalCount, LangProvider.Instance.Extracting);
progressCallback.Report(extractionProgress);
var extractionSettings = new ExtractionOptions
{
var entryKey = reader.Entry.Key;
if (IsUnwantedDirectoryOrFileType(entryKey, reader))
{
continue;
}

if (FileUtils.IsPngOrIco(entryKey))
{
reader.WriteEntryToDirectory(targetPath, new ExtractionOptions
{
ExtractFullPath = false,
Overwrite = true
});
}
ExtractFullPath = false,
Overwrite = true
};
foreach (var entry in pngAndIcoFiles)
{
cancellationToken.ThrowIfCancellationRequested();
entry.WriteToDirectory(targetPath, extractionSettings);
extractionProgress.Current++;
progressCallback.Report(extractionProgress);
}
}

private static bool IsUnwantedDirectoryOrFileType(string entryKey, IReader reader)
private static bool IsUnwantedDirectoryOrFileType(IEntry entry)
{
return entryKey != null && (reader.Entry.IsDirectory ||
entryKey.Contains("ResourceForks") ||
entryKey.Contains("__MACOSX") ||
entryKey.StartsWith("._") ||
entryKey.Equals(".DS_Store") ||
entryKey.Equals("Thumbs.db"));
return entry.Key != null && (entry.IsDirectory ||
entry.Key.Contains("ResourceForks") ||
entry.Key.Contains("__MACOSX") ||
entry.Key.StartsWith("._") ||
entry.Key.Equals(".DS_Store") ||
entry.Key.Equals("Thumbs.db"));
}
}
6 changes: 6 additions & 0 deletions FoliCon/Modules/LangProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ private void UpdateLangs()
OnPropertyChanged(nameof(DevelopedByDinesh));
OnPropertyChanged(nameof(DirectoryIsEmpty));
OnPropertyChanged(nameof(DownloadIt));
OnPropertyChanged(nameof(Downloading));
OnPropertyChanged(nameof(DownloadingIconWithCount));
OnPropertyChanged(nameof(DownloadingIcons));
OnPropertyChanged(nameof(EmptyDirectory));
Expand All @@ -89,6 +90,7 @@ private void UpdateLangs()
OnPropertyChanged(nameof(EnterValidRegexPlaceholder));
OnPropertyChanged(nameof(ExplorerIntegration));
OnPropertyChanged(nameof(ExtractManually));
OnPropertyChanged(nameof(Extracting));
OnPropertyChanged(nameof(FailedFileAccessAt));
OnPropertyChanged(nameof(FailedToSaveMediaInfoAt));
OnPropertyChanged(nameof(FileIsInUse));
Expand Down Expand Up @@ -250,6 +252,7 @@ private void UpdateLangs()
public string DevelopedByDinesh => Lang.DevelopedByDinesh;
public string DirectoryIsEmpty => Lang.DirectoryIsEmpty;
public string DownloadIt => Lang.DownloadIt;
public string Downloading => Lang.Downloading;
public string DownloadingIconWithCount => Lang.DownloadingIconWithCount;
public string DownloadingIcons => Lang.DownloadingIcons;
public string EmptyDirectory => Lang.EmptyDirectory;
Expand All @@ -263,6 +266,7 @@ private void UpdateLangs()
public string ExceptionOccurred => Lang.ExceptionOccurred;
public string ExplorerIntegration => Lang.ExplorerIntegration;
public string ExtractManually => Lang.ExtractManually;
public string Extracting => Lang.Extracting;
public string FailedFileAccessAt => Lang.FailedFileAccessAt;
public string FailedToSaveMediaInfoAt => Lang.FailedToSaveMediaInfoAt;
public string FileIsInUse => Lang.FileIsInUse;
Expand Down Expand Up @@ -432,6 +436,7 @@ public class LangKeys
public static string DevelopedByDinesh = nameof(DevelopedByDinesh);
public static string DirectoryIsEmpty = nameof(DirectoryIsEmpty);
public static string DownloadIt = nameof(DownloadIt);
public static string Downloading = nameof(Downloading);
public static string DownloadingIconWithCount = nameof(DownloadingIconWithCount);
public static string DownloadingIcons = nameof(DownloadingIcons);
public static string EmptyDirectory = nameof(EmptyDirectory);
Expand All @@ -445,6 +450,7 @@ public class LangKeys
public static string ExceptionOccurred = nameof(ExceptionOccurred);
public static string ExplorerIntegration = nameof(ExplorerIntegration);
public static string ExtractManually = nameof(ExtractManually);
public static string Extracting = nameof(Extracting);
public static string FailedFileAccessAt = nameof(FailedFileAccessAt);
public static string FailedToSaveMediaInfoAt = nameof(FailedToSaveMediaInfoAt);
public static string FileIsInUse = nameof(FileIsInUse);
Expand Down
10 changes: 9 additions & 1 deletion FoliCon/Modules/utils/FileUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,15 @@ public static void DeleteDirectoryIfEmpty(string targetDirectoryPath)

public static void DeleteFoliConTempDeviationDirectory()
{
Directory.Delete(FoliConTempDeviationsPath(), true);
try
{
Directory.Delete(FoliConTempDeviationsPath(), true);
}
catch (Exception e)
{
Logger.ForErrorEvent().Message("Error Occurred while Deleting FoliCon Temp Deviation Directory")
.Exception(e).Log();
}
}


Expand Down
18 changes: 18 additions & 0 deletions FoliCon/Properties/Langs/Lang.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions FoliCon/Properties/Langs/Lang.ar.resx
Original file line number Diff line number Diff line change
Expand Up @@ -651,4 +651,10 @@
<data name="ExtractManually" xml:space="preserve">
<value>استخراج يدوي</value>
</data>
<data name="Extracting" xml:space="preserve">
<value>جارٍ الاستخراج...</value>
</data>
<data name="Downloading" xml:space="preserve">
<value>جارٍ التنزيل...</value>
</data>
</root>
6 changes: 6 additions & 0 deletions FoliCon/Properties/Langs/Lang.es.resx
Original file line number Diff line number Diff line change
Expand Up @@ -651,4 +651,10 @@ Esto ayuda a folicon a identificar los medios sin tener que elegir entre título
<data name="ExtractManually" xml:space="preserve">
<value>Extraer manualmente</value>
</data>
<data name="Extracting" xml:space="preserve">
<value>Extrayendo...</value>
</data>
<data name="Downloading" xml:space="preserve">
<value>Descargando...</value>
</data>
</root>
6 changes: 6 additions & 0 deletions FoliCon/Properties/Langs/Lang.hi.resx
Original file line number Diff line number Diff line change
Expand Up @@ -651,4 +651,10 @@
<data name="ExtractManually" xml:space="preserve">
<value>एक्सट्रेक्ट करे</value>
</data>
<data name="Extracting" xml:space="preserve">
<value>एक्सट्रैक्टिंग...</value>
</data>
<data name="Downloading" xml:space="preserve">
<value>डाउनलोड हो रहा है...</value>
</data>
</root>
6 changes: 6 additions & 0 deletions FoliCon/Properties/Langs/Lang.pt.resx
Original file line number Diff line number Diff line change
Expand Up @@ -650,4 +650,10 @@ e renovar o cache dos Ícones?</value>
<data name="ExtractManually" xml:space="preserve">
<value>Extrair manualmente</value>
</data>
<data name="Extracting" xml:space="preserve">
<value>Extraindo...</value>
</data>
<data name="Downloading" xml:space="preserve">
<value>Baixando...</value>
</data>
</root>
6 changes: 6 additions & 0 deletions FoliCon/Properties/Langs/Lang.resx
Original file line number Diff line number Diff line change
Expand Up @@ -655,4 +655,10 @@ and refresh Icon Cache?</value>
<data name="ExtractManually" xml:space="preserve">
<value>Extract manually</value>
</data>
<data name="Extracting" xml:space="preserve">
<value>Extracting...</value>
</data>
<data name="Downloading" xml:space="preserve">
<value>Downloading...</value>
</data>
</root>
6 changes: 6 additions & 0 deletions FoliCon/Properties/Langs/Lang.ru.resx
Original file line number Diff line number Diff line change
Expand Up @@ -654,4 +654,10 @@
<data name="ExtractManually" xml:space="preserve">
<value>Извлечь вручную</value>
</data>
<data name="Extracting" xml:space="preserve">
<value>Извлечение...</value>
</data>
<data name="Downloading" xml:space="preserve">
<value>Загрузка...</value>
</data>
</root>
Loading