mirror of
https://github.com/Tyrrrz/DiscordChatExporter.git
synced 2025-06-05 01:03:44 -04:00
Fix media downloading
This commit is contained in:
parent
e26a0660d1
commit
752003abc3
4 changed files with 52 additions and 22 deletions
|
@ -8,6 +8,7 @@ using System.Net.Http;
|
|||
using System.Threading.Tasks;
|
||||
using DiscordChatExporter.Domain.Discord.Models;
|
||||
using DiscordChatExporter.Domain.Internal.Extensions;
|
||||
using Tyrrrz.Extensions;
|
||||
|
||||
namespace DiscordChatExporter.Domain.Exporting
|
||||
{
|
||||
|
@ -72,7 +73,13 @@ namespace DiscordChatExporter.Domain.Exporting
|
|||
// We want relative path so that the output files can be copied around without breaking
|
||||
var relativeFilePath = Path.GetRelativePath(Request.OutputBaseDirPath, filePath);
|
||||
|
||||
return $"file:///./{Uri.EscapeDataString(relativeFilePath)}";
|
||||
// Need to properly escape each path segment while keeping the slashes
|
||||
var escapedRelativeFilePath = relativeFilePath
|
||||
.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
|
||||
.Select(Uri.EscapeDataString)
|
||||
.JoinToString(Path.AltDirectorySeparatorChar.ToString());
|
||||
|
||||
return escapedRelativeFilePath;
|
||||
}
|
||||
catch (HttpRequestException)
|
||||
{
|
||||
|
|
|
@ -9,7 +9,7 @@ using DiscordChatExporter.Domain.Internal.Extensions;
|
|||
|
||||
namespace DiscordChatExporter.Domain.Exporting
|
||||
{
|
||||
internal class MediaDownloader
|
||||
internal partial class MediaDownloader
|
||||
{
|
||||
private readonly HttpClient _httpClient = Singleton.HttpClient;
|
||||
private readonly string _workingDirPath;
|
||||
|
@ -21,33 +21,35 @@ namespace DiscordChatExporter.Domain.Exporting
|
|||
_workingDirPath = workingDirPath;
|
||||
}
|
||||
|
||||
private string GetRandomSuffix() => Guid.NewGuid().ToString().Replace("-", "").Substring(0, 8);
|
||||
|
||||
private string GetFileNameFromUrl(string url)
|
||||
{
|
||||
var originalFileName = Regex.Match(url, @".+/([^?]*)").Groups[1].Value;
|
||||
|
||||
var fileName = !string.IsNullOrWhiteSpace(originalFileName) ?
|
||||
$"{Path.GetFileNameWithoutExtension(originalFileName)}-{GetRandomSuffix()}{Path.GetExtension(originalFileName)}" :
|
||||
GetRandomSuffix();
|
||||
|
||||
return PathEx.EscapePath(fileName);
|
||||
}
|
||||
|
||||
// HACK: ConfigureAwait() is crucial here to enable sync-over-async in HtmlMessageWriter
|
||||
public async ValueTask<string> DownloadAsync(string url)
|
||||
{
|
||||
if (_pathMap.TryGetValue(url, out var cachedFilePath))
|
||||
return cachedFilePath;
|
||||
|
||||
var fileName = GetFileNameFromUrl(url);
|
||||
var filePath = Path.Combine(_workingDirPath, fileName);
|
||||
var filePath = PathEx.MakeUniqueFilePath(Path.Combine(_workingDirPath, fileName));
|
||||
|
||||
Directory.CreateDirectory(_workingDirPath);
|
||||
|
||||
await _httpClient.DownloadAsync(url, filePath).ConfigureAwait(false);
|
||||
await _httpClient.DownloadAsync(url, filePath);
|
||||
|
||||
return _pathMap[url] = filePath;
|
||||
}
|
||||
}
|
||||
|
||||
internal partial class MediaDownloader
|
||||
{
|
||||
private static string GetRandomFileName() => Guid.NewGuid().ToString().Replace("-", "").Substring(0, 16);
|
||||
|
||||
private static string GetFileNameFromUrl(string url)
|
||||
{
|
||||
var originalFileName = Regex.Match(url, @".+/([^?]*)").Groups[1].Value;
|
||||
|
||||
var fileName = !string.IsNullOrWhiteSpace(originalFileName)
|
||||
? originalFileName
|
||||
: GetRandomFileName();
|
||||
|
||||
return PathEx.EscapePath(fileName);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,14 +7,13 @@ namespace DiscordChatExporter.Domain.Internal.Extensions
|
|||
{
|
||||
internal static class HttpClientExtensions
|
||||
{
|
||||
// HACK: ConfigureAwait() is crucial here to enable sync-over-async in HtmlMessageWriter
|
||||
public static async ValueTask DownloadAsync(this HttpClient httpClient, string uri, string outputFilePath)
|
||||
{
|
||||
await using var input = await httpClient.GetStreamAsync(uri).ConfigureAwait(false);
|
||||
await using var input = await httpClient.GetStreamAsync(uri);
|
||||
var output = File.Create(outputFilePath);
|
||||
|
||||
await input.CopyToAsync(output).ConfigureAwait(false);
|
||||
await output.DisposeAsync().ConfigureAwait(false);
|
||||
await input.CopyToAsync(output);
|
||||
await output.DisposeAsync();
|
||||
}
|
||||
|
||||
public static async ValueTask<JsonElement> ReadAsJsonAsync(this HttpContent content)
|
||||
|
|
|
@ -14,5 +14,27 @@ namespace DiscordChatExporter.Domain.Internal
|
|||
}
|
||||
|
||||
public static string EscapePath(string path) => EscapePath(new StringBuilder(path)).ToString();
|
||||
|
||||
public static string MakeUniqueFilePath(string baseFilePath, int maxAttempts = 100)
|
||||
{
|
||||
if (!File.Exists(baseFilePath))
|
||||
return baseFilePath;
|
||||
|
||||
var baseDirPath = Path.GetDirectoryName(baseFilePath);
|
||||
var baseFileNameWithoutExtension = Path.GetFileNameWithoutExtension(baseFilePath);
|
||||
var baseFileExtension = Path.GetExtension(baseFilePath);
|
||||
|
||||
for (var i = 1; i <= maxAttempts; i++)
|
||||
{
|
||||
var filePath = $"{baseFileNameWithoutExtension} ({i}){baseFileExtension}";
|
||||
if (!string.IsNullOrWhiteSpace(baseDirPath))
|
||||
filePath = Path.Combine(baseDirPath, filePath);
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
return filePath;
|
||||
}
|
||||
|
||||
return baseFilePath;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue