Refactor and enhance Download Manager application

- Added new services: IContentDialogService, ISnackbarService
- Replaced DashboardPage and DashboardViewModel with DownloadingPage, DownloadingPageViewModel, WaitingPage, and WaitingPageViewModel
- Introduced AddNewTaskPage and AddNewTaskViewModel
- Replaced DownloadServiceManger with DownloadManagerService
- Updated WPF-UI package to 3.0.4 and added HtmlAgilityPack 1.11.61
- Refactored DownloadWorker to use async methods and added retry logic
- Converted DownloadItemData to partial class with ObservableProperty attributes
- Changed initial navigation page to DownloadingPage
- Updated MainWindow navigation items and title
- Added new utility classes: DoubleUtilities, MD5Utilities, StringExtension
- Added new XAML pages and ViewModels for task management and display
- Removed obsolete DashboardPage and related files
This commit is contained in:
Misaki
2024-07-01 02:14:19 +09:00
parent 150cd3cb26
commit 3a59979efd
33 changed files with 1180 additions and 212 deletions

View File

@@ -1,15 +1,16 @@
using Downloader;
using DownloadManager.Models.UrlGetter;
namespace DownloadManager.Models;
public class DownloadItemData
public partial class DownloadItemData : ObservableObject
{
public DownloadItemData(string fileName, string filePath, string url, DownloadConfiguration downloadConfig)
public DownloadItemData(string filePath, string url, UrlGetterType urlGetterType, DownloadConfiguration downloadConfig)
{
Id = Guid.NewGuid();
FileName = fileName;
FilePath = filePath;
Url = url;
downloadConfiguration = downloadConfig;
UrlGetterType = urlGetterType;
DownloadConfiguration = downloadConfig;
}
public Guid Id
@@ -17,38 +18,39 @@ public class DownloadItemData
get;
}
public string FileName
{
get;
}
[ObservableProperty]
private string? fileName;
public string FilePath
{
get;
}
[ObservableProperty]
private string filePath;
public string Url
{
get;
}
[ObservableProperty]
private string url;
public DownloadConfiguration downloadConfiguration
{
get;
}
[ObservableProperty]
private double fileSize;
public long FileSize
[ObservableProperty]
private double speed;
[ObservableProperty]
private int progress;
public string? MD5
{
get; set;
}
public double Speed
public UrlGetterType UrlGetterType
{
get; set;
get;
}
public int Progress
public DownloadConfiguration DownloadConfiguration
{
get; set;
get;
}
public DownloadStatus Status
{
get; set;

View File

@@ -0,0 +1,13 @@
using DownloadManager.Utilities;
namespace DownloadManager.Models.UrlGetter
{
class DirectUrlGetter : IUrlGetter
{
public async Task<FileUrl> GetFileUrl(string taskUrl)
{
var fileName = System.IO.Path.GetFileName(taskUrl).ToUnescapedString();
return new FileUrl(taskUrl, fileName, null);
}
}
}

View File

@@ -0,0 +1,12 @@
namespace DownloadManager.Models.UrlGetter;
public struct FileUrl(string? url, string? name, string? md5)
{
public string? Url { get; } = url;
public string? Name { get; } = name;
public string? MD5 { get; } = md5;
}
public interface IUrlGetter
{
public Task<FileUrl> GetFileUrl(string taskUrl);
}

View File

@@ -0,0 +1,15 @@
namespace DownloadManager.Models.UrlGetter
{
public class UrlGetterFactory
{
public static IUrlGetter CreateUrlGetter(UrlGetterType type)
{
return type switch
{
UrlGetterType.Direct => new DirectUrlGetter(),
UrlGetterType.Yande => new YandeUrlGetter(),
_ => throw new ArgumentException("Invalid UrlGetterType"),
};
}
}
}

View File

@@ -0,0 +1,12 @@
using System.ComponentModel;
namespace DownloadManager.Models.UrlGetter
{
public enum UrlGetterType
{
[Description("Direct")]
Direct,
[Description("Yande post URL")]
Yande,
}
}

View File

@@ -0,0 +1,63 @@
using DownloadManager.Utilities;
using System.IO;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json;
namespace DownloadManager.Models.UrlGetter;
public class YandeUrlGetter : IUrlGetter
{
readonly HttpClient client = new ();
const int maxRetries = 3;
const int delayMilliseconds = 1000;
public async Task<FileUrl> GetFileUrl(string taskUrl)
{
// Get the ID of the post from the URL
var id = taskUrl.Split("https://yande.re/post/show/").Last();
for (int attempt = 0; attempt < maxRetries; attempt++)
{
try
{
var response = await client.GetAsync($"https://yande.re/post.json?tags=id:{id}");
if (response.IsSuccessStatusCode)
{
var data = await response.Content.ReadFromJsonAsync<JsonElement[]>();
if (data == null || data.Length == 0)
{
return new FileUrl(null, null, null);
}
var firstElement = data.FirstOrDefault();
if (firstElement.ValueKind != JsonValueKind.Object || !firstElement.TryGetProperty("file_url", out var fileUrlElement))
{
return new FileUrl(null, null, null);
}
if (!firstElement.TryGetProperty("md5", out var md5Element))
{
return new FileUrl(null, null, null);
}
var fileUrl = fileUrlElement.GetString();
var fileName = Path.GetFileName(fileUrl)?.ToUnescapedString();
var md5 = md5Element.GetString();
return new FileUrl(fileUrl, fileName, md5);
}
}
catch (HttpRequestException)
{
// Log the exception if needed
}
// Wait before retrying
await Task.Delay(delayMilliseconds);
}
// If all retries fail, return a FileUrl with null values
return new FileUrl(null, null, null);
}
}