Fix media downloading

pull/352/head
Alexey Golub 4 years ago
parent e26a0660d1
commit 752003abc3

@ -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…
Cancel
Save