diff --git a/.gitignore b/.gitignore index 20d4f315..d967f8b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # User-specific files .vs/ +.vscode/ .idea/ *.suo *.user diff --git a/DiscordChatExporter.Core/Exporting/ExportRequest.cs b/DiscordChatExporter.Core/Exporting/ExportRequest.cs index 82468bd4..7b749fb1 100644 --- a/DiscordChatExporter.Core/Exporting/ExportRequest.cs +++ b/DiscordChatExporter.Core/Exporting/ExportRequest.cs @@ -157,37 +157,51 @@ public partial class ExportRequest Channel channel, Snowflake? after, Snowflake? before - ) => - Regex.Replace( + ) + { + string preFormattedPath = Regex.Replace( path, "%.", m => Path.EscapeFileName( m.Value switch { + // On %T and %P, we have to make sure that we still get name and position of the category if the channel is a thread "%g" => guild.Id.ToString(), "%G" => guild.Name, "%t" => channel.Parent?.Id.ToString() ?? "", - "%T" => channel.Parent?.Name ?? "", + "%T" + => channel.IsThread + ? (channel.Parent?.Parent?.Name ?? "") + : channel.Parent?.Name ?? "", "%c" => channel.Id.ToString(), "%C" => channel.Name, "%p" => channel.Position?.ToString(CultureInfo.InvariantCulture) ?? "0", - "%P" => channel.Parent?.Position?.ToString(CultureInfo.InvariantCulture) - ?? "0", + "%P" + => channel.IsThread + ? ( + channel + .Parent?.Parent + ?.Position + ?.ToString(CultureInfo.InvariantCulture) ?? "" + ) + : channel.Parent?.Position?.ToString(CultureInfo.InvariantCulture) + ?? "0", - "%a" => after?.ToDate().ToString("yyyy-MM-dd", CultureInfo.InvariantCulture) - ?? "", - "%b" => before - ?.ToDate() - .ToString("yyyy-MM-dd", CultureInfo.InvariantCulture) - ?? "", - "%d" => DateTimeOffset.Now.ToString( - "yyyy-MM-dd", - CultureInfo.InvariantCulture - ), + "%a" + => after?.ToDate().ToString("yyyy-MM-dd", CultureInfo.InvariantCulture) + ?? "", + "%b" + => before?.ToDate().ToString("yyyy-MM-dd", CultureInfo.InvariantCulture) + ?? "", + "%d" + => DateTimeOffset.Now.ToString( + "yyyy-MM-dd", + CultureInfo.InvariantCulture + ), "%%" => "%", _ => m.Value, @@ -195,6 +209,32 @@ public partial class ExportRequest ) ); + // We are looking for any structure in the path which contains either %y or %z. If the channel is a thread, we can resolve the placeholders, otherwise, that whole structure needs to be removed. + string formattedPath = Regex.Replace( + preFormattedPath, + @"\\[^\\]*%[xyz][^\\]*\\", + m => + channel.IsThread + ? Regex.Replace( + m.Value, + "%[xyz]", + n => + n.Value switch + { + "%x" => channel.Parent?.Id.ToString() ?? "", + "%y" + => channel + .Parent?.Position + ?.ToString(CultureInfo.InvariantCulture) ?? "", + "%z" => channel.Parent?.Name ?? "", + _ => n.Value + } + ) + : "\\" + ); + return formattedPath; + } + private static string GetOutputBaseFilePath( Guild guild, Channel channel,