mirror of
https://github.com/Tyrrrz/DiscordChatExporter.git
synced 2025-06-06 17:41:26 -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 System.Threading.Tasks;
|
||||||
using DiscordChatExporter.Domain.Discord.Models;
|
using DiscordChatExporter.Domain.Discord.Models;
|
||||||
using DiscordChatExporter.Domain.Internal.Extensions;
|
using DiscordChatExporter.Domain.Internal.Extensions;
|
||||||
|
using Tyrrrz.Extensions;
|
||||||
|
|
||||||
namespace DiscordChatExporter.Domain.Exporting
|
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
|
// We want relative path so that the output files can be copied around without breaking
|
||||||
var relativeFilePath = Path.GetRelativePath(Request.OutputBaseDirPath, filePath);
|
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)
|
catch (HttpRequestException)
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,7 +9,7 @@ using DiscordChatExporter.Domain.Internal.Extensions;
|
||||||
|
|
||||||
namespace DiscordChatExporter.Domain.Exporting
|
namespace DiscordChatExporter.Domain.Exporting
|
||||||
{
|
{
|
||||||
internal class MediaDownloader
|
internal partial class MediaDownloader
|
||||||
{
|
{
|
||||||
private readonly HttpClient _httpClient = Singleton.HttpClient;
|
private readonly HttpClient _httpClient = Singleton.HttpClient;
|
||||||
private readonly string _workingDirPath;
|
private readonly string _workingDirPath;
|
||||||
|
@ -21,33 +21,35 @@ namespace DiscordChatExporter.Domain.Exporting
|
||||||
_workingDirPath = workingDirPath;
|
_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)
|
public async ValueTask<string> DownloadAsync(string url)
|
||||||
{
|
{
|
||||||
if (_pathMap.TryGetValue(url, out var cachedFilePath))
|
if (_pathMap.TryGetValue(url, out var cachedFilePath))
|
||||||
return cachedFilePath;
|
return cachedFilePath;
|
||||||
|
|
||||||
var fileName = GetFileNameFromUrl(url);
|
var fileName = GetFileNameFromUrl(url);
|
||||||
var filePath = Path.Combine(_workingDirPath, fileName);
|
var filePath = PathEx.MakeUniqueFilePath(Path.Combine(_workingDirPath, fileName));
|
||||||
|
|
||||||
Directory.CreateDirectory(_workingDirPath);
|
Directory.CreateDirectory(_workingDirPath);
|
||||||
|
|
||||||
await _httpClient.DownloadAsync(url, filePath).ConfigureAwait(false);
|
await _httpClient.DownloadAsync(url, filePath);
|
||||||
|
|
||||||
return _pathMap[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
|
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)
|
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);
|
var output = File.Create(outputFilePath);
|
||||||
|
|
||||||
await input.CopyToAsync(output).ConfigureAwait(false);
|
await input.CopyToAsync(output);
|
||||||
await output.DisposeAsync().ConfigureAwait(false);
|
await output.DisposeAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async ValueTask<JsonElement> ReadAsJsonAsync(this HttpContent content)
|
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 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