mirror of
https://github.com/Tyrrrz/DiscordChatExporter.git
synced 2026-02-15 00:03:38 -07:00
Remove Channel.ParentNameWithFallback
This commit is contained in:
parent
59344cedbe
commit
5abe74894c
|
|
@ -200,7 +200,7 @@ public abstract class ExportCommandBase : DiscordCommandBase
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await progressContext.StartTaskAsync(
|
await progressContext.StartTaskAsync(
|
||||||
$"{channel.ParentNameWithFallback} / {channel.Name}",
|
channel.GetHierarchicalName(),
|
||||||
async progress =>
|
async progress =>
|
||||||
{
|
{
|
||||||
var guild = await Discord.GetGuildAsync(
|
var guild = await Discord.GetGuildAsync(
|
||||||
|
|
@ -263,10 +263,7 @@ public abstract class ExportCommandBase : DiscordCommandBase
|
||||||
|
|
||||||
foreach (var (channel, error) in errorsByChannel)
|
foreach (var (channel, error) in errorsByChannel)
|
||||||
{
|
{
|
||||||
await console.Error.WriteAsync(
|
await console.Error.WriteAsync($"{channel.GetHierarchicalName()}: ");
|
||||||
$"{channel.ParentNameWithFallback} / {channel.Name}: "
|
|
||||||
);
|
|
||||||
|
|
||||||
using (console.WithForegroundColor(ConsoleColor.Red))
|
using (console.WithForegroundColor(ConsoleColor.Red))
|
||||||
await console.Error.WriteLineAsync(error);
|
await console.Error.WriteLineAsync(error);
|
||||||
}
|
}
|
||||||
|
|
@ -294,7 +291,7 @@ public abstract class ExportCommandBase : DiscordCommandBase
|
||||||
var channel = await Discord.GetChannelAsync(channelId, cancellationToken);
|
var channel = await Discord.GetChannelAsync(channelId, cancellationToken);
|
||||||
|
|
||||||
// Unwrap categories
|
// Unwrap categories
|
||||||
if (channel.Kind == ChannelKind.GuildCategory)
|
if (channel.IsCategory)
|
||||||
{
|
{
|
||||||
var guildChannels =
|
var guildChannels =
|
||||||
channelsByGuild.GetValueOrDefault(channel.GuildId)
|
channelsByGuild.GetValueOrDefault(channel.GuildId)
|
||||||
|
|
|
||||||
|
|
@ -60,10 +60,10 @@ public class ExportAllCommand : ExportCommandBase
|
||||||
var channel in Discord.GetGuildChannelsAsync(guild.Id, cancellationToken)
|
var channel in Discord.GetGuildChannelsAsync(guild.Id, cancellationToken)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (channel.Kind == ChannelKind.GuildCategory)
|
if (channel.IsCategory)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!IncludeVoiceChannels && channel.Kind.IsVoice())
|
if (!IncludeVoiceChannels && channel.IsVoice)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
channels.Add(channel);
|
channels.Add(channel);
|
||||||
|
|
@ -129,15 +129,15 @@ public class ExportAllCommand : ExportCommandBase
|
||||||
|
|
||||||
// Filter out unwanted channels
|
// Filter out unwanted channels
|
||||||
if (!IncludeDirectChannels)
|
if (!IncludeDirectChannels)
|
||||||
channels.RemoveAll(c => c.Kind.IsDirect());
|
channels.RemoveAll(c => c.IsDirect);
|
||||||
if (!IncludeGuildChannels)
|
if (!IncludeGuildChannels)
|
||||||
channels.RemoveAll(c => c.Kind.IsGuild());
|
channels.RemoveAll(c => c.IsGuild);
|
||||||
if (!IncludeVoiceChannels)
|
if (!IncludeVoiceChannels)
|
||||||
channels.RemoveAll(c => c.Kind.IsVoice());
|
channels.RemoveAll(c => c.IsVoice);
|
||||||
if (ThreadInclusionMode == ThreadInclusionMode.None)
|
if (ThreadInclusionMode == ThreadInclusionMode.None)
|
||||||
channels.RemoveAll(c => c.Kind.IsThread());
|
channels.RemoveAll(c => c.IsThread);
|
||||||
if (ThreadInclusionMode != ThreadInclusionMode.All)
|
if (ThreadInclusionMode != ThreadInclusionMode.All)
|
||||||
channels.RemoveAll(c => c.Kind.IsThread() && c.IsArchived);
|
channels.RemoveAll(c => c is { IsThread: true, IsArchived: true });
|
||||||
|
|
||||||
await ExportAsync(console, channels);
|
await ExportAsync(console, channels);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,10 +38,10 @@ public class ExportGuildCommand : ExportCommandBase
|
||||||
// Regular channels
|
// Regular channels
|
||||||
await foreach (var channel in Discord.GetGuildChannelsAsync(GuildId, cancellationToken))
|
await foreach (var channel in Discord.GetGuildChannelsAsync(GuildId, cancellationToken))
|
||||||
{
|
{
|
||||||
if (channel.Kind == ChannelKind.GuildCategory)
|
if (channel.IsCategory)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!IncludeVoiceChannels && channel.Kind.IsVoice())
|
if (!IncludeVoiceChannels && channel.IsVoice)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
channels.Add(channel);
|
channels.Add(channel);
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,8 @@ public class GetChannelsCommand : DiscordCommandBase
|
||||||
var cancellationToken = console.RegisterCancellationHandler();
|
var cancellationToken = console.RegisterCancellationHandler();
|
||||||
|
|
||||||
var channels = (await Discord.GetGuildChannelsAsync(GuildId, cancellationToken))
|
var channels = (await Discord.GetGuildChannelsAsync(GuildId, cancellationToken))
|
||||||
.Where(c => c.Kind != ChannelKind.GuildCategory)
|
.Where(c => !c.IsCategory)
|
||||||
.Where(c => IncludeVoiceChannels || !c.Kind.IsVoice())
|
.Where(c => IncludeVoiceChannels || !c.IsVoice)
|
||||||
.OrderBy(c => c.Parent?.Position)
|
.OrderBy(c => c.Parent?.Position)
|
||||||
.ThenBy(c => c.Name)
|
.ThenBy(c => c.Name)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
@ -72,11 +72,9 @@ public class GetChannelsCommand : DiscordCommandBase
|
||||||
using (console.WithForegroundColor(ConsoleColor.DarkGray))
|
using (console.WithForegroundColor(ConsoleColor.DarkGray))
|
||||||
await console.Output.WriteAsync(" | ");
|
await console.Output.WriteAsync(" | ");
|
||||||
|
|
||||||
// Channel category / name
|
// Channel name
|
||||||
using (console.WithForegroundColor(ConsoleColor.White))
|
using (console.WithForegroundColor(ConsoleColor.White))
|
||||||
await console.Output.WriteLineAsync(
|
await console.Output.WriteLineAsync(channel.GetHierarchicalName());
|
||||||
$"{channel.ParentNameWithFallback} / {channel.Name}"
|
|
||||||
);
|
|
||||||
|
|
||||||
var channelThreads = threads.Where(t => t.Parent?.Id == channel.Id).ToArray();
|
var channelThreads = threads.Where(t => t.Parent?.Id == channel.Id).ToArray();
|
||||||
var channelThreadIdMaxLength = channelThreads
|
var channelThreadIdMaxLength = channelThreads
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ public class GetDirectChannelsCommand : DiscordCommandBase
|
||||||
var channels = (
|
var channels = (
|
||||||
await Discord.GetGuildChannelsAsync(Guild.DirectMessages.Id, cancellationToken)
|
await Discord.GetGuildChannelsAsync(Guild.DirectMessages.Id, cancellationToken)
|
||||||
)
|
)
|
||||||
.Where(c => c.Kind != ChannelKind.GuildCategory)
|
|
||||||
.OrderByDescending(c => c.LastMessageId)
|
.OrderByDescending(c => c.LastMessageId)
|
||||||
.ThenBy(c => c.Name)
|
.ThenBy(c => c.Name)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
@ -42,11 +41,9 @@ public class GetDirectChannelsCommand : DiscordCommandBase
|
||||||
using (console.WithForegroundColor(ConsoleColor.DarkGray))
|
using (console.WithForegroundColor(ConsoleColor.DarkGray))
|
||||||
await console.Output.WriteAsync(" | ");
|
await console.Output.WriteAsync(" | ");
|
||||||
|
|
||||||
// Channel category / name
|
// Channel name
|
||||||
using (console.WithForegroundColor(ConsoleColor.White))
|
using (console.WithForegroundColor(ConsoleColor.White))
|
||||||
await console.Output.WriteLineAsync(
|
await console.Output.WriteLineAsync(channel.GetHierarchicalName());
|
||||||
$"{channel.ParentNameWithFallback} / {channel.Name}"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Linq;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using DiscordChatExporter.Core.Discord.Data.Common;
|
using DiscordChatExporter.Core.Discord.Data.Common;
|
||||||
using DiscordChatExporter.Core.Utils.Extensions;
|
using DiscordChatExporter.Core.Utils.Extensions;
|
||||||
|
|
@ -20,32 +21,36 @@ public partial record Channel(
|
||||||
Snowflake? LastMessageId
|
Snowflake? LastMessageId
|
||||||
) : IHasId
|
) : IHasId
|
||||||
{
|
{
|
||||||
// Used for visual backwards-compatibility with old exports, where
|
public bool IsDirect => Kind is ChannelKind.DirectTextChat or ChannelKind.DirectGroupTextChat;
|
||||||
// channels without a parent (i.e. mostly DM channels) or channels
|
|
||||||
// with an inaccessible parent (i.e. inside private categories) had
|
public bool IsGuild => !IsDirect;
|
||||||
// a fallback category created for them.
|
|
||||||
public string ParentNameWithFallback =>
|
public bool IsCategory => Kind == ChannelKind.GuildCategory;
|
||||||
Parent?.Name
|
|
||||||
?? Kind switch
|
public bool IsVoice => Kind is ChannelKind.GuildVoiceChat or ChannelKind.GuildStageVoice;
|
||||||
{
|
|
||||||
ChannelKind.GuildCategory => "Category",
|
public bool IsThread =>
|
||||||
ChannelKind.GuildTextChat => "Text",
|
Kind
|
||||||
ChannelKind.DirectTextChat => "Private",
|
is ChannelKind.GuildNewsThread
|
||||||
ChannelKind.DirectGroupTextChat => "Group",
|
or ChannelKind.GuildPublicThread
|
||||||
ChannelKind.GuildPrivateThread => "Private Thread",
|
or ChannelKind.GuildPrivateThread;
|
||||||
ChannelKind.GuildPublicThread => "Public Thread",
|
|
||||||
ChannelKind.GuildNews => "News",
|
|
||||||
ChannelKind.GuildNewsThread => "News Thread",
|
|
||||||
_ => "Default"
|
|
||||||
};
|
|
||||||
|
|
||||||
public bool IsEmpty => LastMessageId is null;
|
public bool IsEmpty => LastMessageId is null;
|
||||||
|
|
||||||
// Only needed for WPF data binding. Don't use anywhere else.
|
public IEnumerable<Channel> GetParents()
|
||||||
public bool IsVoice => Kind.IsVoice();
|
{
|
||||||
|
var current = Parent;
|
||||||
|
while (current is not null)
|
||||||
|
{
|
||||||
|
yield return current;
|
||||||
|
current = current.Parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Only needed for WPF data binding. Don't use anywhere else.
|
public Channel? TryGetRootParent() => GetParents().LastOrDefault();
|
||||||
public bool IsThread => Kind.IsThread();
|
|
||||||
|
public string GetHierarchicalName() =>
|
||||||
|
string.Join(" / ", GetParents().Reverse().Select(c => c.Name).Append(Name));
|
||||||
|
|
||||||
public bool MayHaveMessagesAfter(Snowflake messageId) => !IsEmpty && messageId < LastMessageId;
|
public bool MayHaveMessagesAfter(Snowflake messageId) => !IsEmpty && messageId < LastMessageId;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,20 +16,3 @@ public enum ChannelKind
|
||||||
GuildDirectory = 14,
|
GuildDirectory = 14,
|
||||||
GuildForum = 15
|
GuildForum = 15
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ChannelKindExtensions
|
|
||||||
{
|
|
||||||
public static bool IsDirect(this ChannelKind kind) =>
|
|
||||||
kind is ChannelKind.DirectTextChat or ChannelKind.DirectGroupTextChat;
|
|
||||||
|
|
||||||
public static bool IsGuild(this ChannelKind kind) => !kind.IsDirect();
|
|
||||||
|
|
||||||
public static bool IsVoice(this ChannelKind kind) =>
|
|
||||||
kind is ChannelKind.GuildVoiceChat or ChannelKind.GuildStageVoice;
|
|
||||||
|
|
||||||
public static bool IsThread(this ChannelKind kind) =>
|
|
||||||
kind
|
|
||||||
is ChannelKind.GuildNewsThread
|
|
||||||
or ChannelKind.GuildPublicThread
|
|
||||||
or ChannelKind.GuildPrivateThread;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,12 @@ using JsonExtensions.Reading;
|
||||||
namespace DiscordChatExporter.Core.Discord.Data;
|
namespace DiscordChatExporter.Core.Discord.Data;
|
||||||
|
|
||||||
// https://discord.com/developers/docs/resources/guild#guild-object
|
// https://discord.com/developers/docs/resources/guild#guild-object
|
||||||
public record Guild(Snowflake Id, string Name, string IconUrl) : IHasId
|
public partial record Guild(Snowflake Id, string Name, string IconUrl) : IHasId
|
||||||
|
{
|
||||||
|
public bool IsDirect => Id == DirectMessages.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial record Guild
|
||||||
{
|
{
|
||||||
// Direct messages are encapsulated within a special pseudo-guild for consistency
|
// Direct messages are encapsulated within a special pseudo-guild for consistency
|
||||||
public static Guild DirectMessages { get; } =
|
public static Guild DirectMessages { get; } =
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,13 @@ public partial record Message(
|
||||||
Interaction? Interaction
|
Interaction? Interaction
|
||||||
) : IHasId
|
) : IHasId
|
||||||
{
|
{
|
||||||
public bool IsReplyLike => Kind == MessageKind.Reply || Interaction is not null;
|
public bool IsSystemNotification =>
|
||||||
|
Kind is >= MessageKind.RecipientAdd and <= MessageKind.ThreadCreated;
|
||||||
|
|
||||||
|
public bool IsReply => Kind == MessageKind.Reply;
|
||||||
|
|
||||||
|
// App interactions are rendered as replies in the Discord client, but they are not actually replies
|
||||||
|
public bool IsReplyLike => IsReply || Interaction is not null;
|
||||||
|
|
||||||
public IEnumerable<User> GetReferencedUsers()
|
public IEnumerable<User> GetReferencedUsers()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,3 @@ public enum MessageKind
|
||||||
ThreadCreated = 18,
|
ThreadCreated = 18,
|
||||||
Reply = 19
|
Reply = 19
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class MessageKindExtensions
|
|
||||||
{
|
|
||||||
public static bool IsSystemNotification(this MessageKind kind) => (int)kind is >= 1 and <= 18;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -286,11 +286,12 @@ public class DiscordClient
|
||||||
yield break;
|
yield break;
|
||||||
|
|
||||||
var tokenKind = _resolvedTokenKind ??= await GetTokenKindAsync(cancellationToken);
|
var tokenKind = _resolvedTokenKind ??= await GetTokenKindAsync(cancellationToken);
|
||||||
|
|
||||||
var channels = (await GetGuildChannelsAsync(guildId, cancellationToken))
|
var channels = (await GetGuildChannelsAsync(guildId, cancellationToken))
|
||||||
// Categories cannot have threads
|
// Categories cannot have threads
|
||||||
.Where(c => c.Kind != ChannelKind.GuildCategory)
|
.Where(c => !c.IsCategory)
|
||||||
// Voice channels cannot have threads
|
// Voice channels cannot have threads
|
||||||
.Where(c => !c.Kind.IsVoice())
|
.Where(c => !c.IsVoice)
|
||||||
// Empty channels cannot have threads
|
// Empty channels cannot have threads
|
||||||
.Where(c => !c.IsEmpty)
|
.Where(c => !c.IsEmpty)
|
||||||
// If the 'before' boundary is specified, skip channels that don't have messages
|
// If the 'before' boundary is specified, skip channels that don't have messages
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ internal partial class CsvMessageWriter : MessageWriter
|
||||||
await _writer.WriteAsync(',');
|
await _writer.WriteAsync(',');
|
||||||
|
|
||||||
// Message content
|
// Message content
|
||||||
if (message.Kind.IsSystemNotification())
|
if (message.IsSystemNotification)
|
||||||
{
|
{
|
||||||
await _writer.WriteAsync(CsvEncode(message.GetFallbackContent()));
|
await _writer.WriteAsync(CsvEncode(message.GetFallbackContent()));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -99,10 +99,21 @@ public partial class ExportRequest
|
||||||
{
|
{
|
||||||
var buffer = new StringBuilder();
|
var buffer = new StringBuilder();
|
||||||
|
|
||||||
// Guild and channel names
|
// Guild name
|
||||||
buffer.Append(
|
buffer.Append(guild.Name);
|
||||||
$"{guild.Name} - {channel.ParentNameWithFallback} - {channel.Name} [{channel.Id}]"
|
|
||||||
);
|
// Parent name
|
||||||
|
if (channel.Parent is not null)
|
||||||
|
buffer.Append(" - ").Append(channel.Parent.Name);
|
||||||
|
|
||||||
|
// Channel name and ID
|
||||||
|
buffer
|
||||||
|
.Append(" - ")
|
||||||
|
.Append(channel.Name)
|
||||||
|
.Append(' ')
|
||||||
|
.Append('[')
|
||||||
|
.Append(channel.Id)
|
||||||
|
.Append(']');
|
||||||
|
|
||||||
// Date range
|
// Date range
|
||||||
if (after is not null || before is not null)
|
if (after is not null || before is not null)
|
||||||
|
|
@ -142,9 +153,8 @@ public partial class ExportRequest
|
||||||
Channel channel,
|
Channel channel,
|
||||||
Snowflake? after,
|
Snowflake? after,
|
||||||
Snowflake? before
|
Snowflake? before
|
||||||
)
|
) =>
|
||||||
{
|
Regex.Replace(
|
||||||
return Regex.Replace(
|
|
||||||
path,
|
path,
|
||||||
"%.",
|
"%.",
|
||||||
m =>
|
m =>
|
||||||
|
|
@ -153,14 +163,18 @@ public partial class ExportRequest
|
||||||
{
|
{
|
||||||
"%g" => guild.Id.ToString(),
|
"%g" => guild.Id.ToString(),
|
||||||
"%G" => guild.Name,
|
"%G" => guild.Name,
|
||||||
|
|
||||||
"%t" => channel.Parent?.Id.ToString() ?? "",
|
"%t" => channel.Parent?.Id.ToString() ?? "",
|
||||||
"%T" => channel.Parent?.Name ?? "",
|
"%T" => channel.Parent?.Name ?? "",
|
||||||
|
|
||||||
"%c" => channel.Id.ToString(),
|
"%c" => channel.Id.ToString(),
|
||||||
"%C" => channel.Name,
|
"%C" => channel.Name,
|
||||||
|
|
||||||
"%p" => channel.Position?.ToString(CultureInfo.InvariantCulture) ?? "0",
|
"%p" => channel.Position?.ToString(CultureInfo.InvariantCulture) ?? "0",
|
||||||
"%P"
|
"%P"
|
||||||
=> channel.Parent?.Position?.ToString(CultureInfo.InvariantCulture)
|
=> channel.Parent?.Position?.ToString(CultureInfo.InvariantCulture)
|
||||||
?? "0",
|
?? "0",
|
||||||
|
|
||||||
"%a"
|
"%a"
|
||||||
=> after?.ToDate().ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)
|
=> after?.ToDate().ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)
|
||||||
?? "",
|
?? "",
|
||||||
|
|
@ -172,12 +186,12 @@ public partial class ExportRequest
|
||||||
"yyyy-MM-dd",
|
"yyyy-MM-dd",
|
||||||
CultureInfo.InvariantCulture
|
CultureInfo.InvariantCulture
|
||||||
),
|
),
|
||||||
|
|
||||||
"%%" => "%",
|
"%%" => "%",
|
||||||
_ => m.Value
|
_ => m.Value
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetOutputBaseFilePath(
|
private static string GetOutputBaseFilePath(
|
||||||
Guild guild,
|
Guild guild,
|
||||||
|
|
|
||||||
|
|
@ -280,7 +280,7 @@ internal partial class HtmlMarkdownVisitor : MarkdownVisitor
|
||||||
else if (mention.Kind == MentionKind.Channel)
|
else if (mention.Kind == MentionKind.Channel)
|
||||||
{
|
{
|
||||||
var channel = mention.TargetId?.Pipe(_context.TryGetChannel);
|
var channel = mention.TargetId?.Pipe(_context.TryGetChannel);
|
||||||
var symbol = channel?.Kind.IsVoice() == true ? "🔊" : "#";
|
var symbol = channel?.IsVoice == true ? "🔊" : "#";
|
||||||
var name = channel?.Name ?? "deleted-channel";
|
var name = channel?.Name ?? "deleted-channel";
|
||||||
|
|
||||||
_buffer.Append(
|
_buffer.Append(
|
||||||
|
|
|
||||||
|
|
@ -30,22 +30,22 @@ internal class HtmlMessageWriter : MessageWriter
|
||||||
if (_messageGroup.LastOrDefault() is not { } lastMessage)
|
if (_messageGroup.LastOrDefault() is not { } lastMessage)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Reply messages cannot join existing groups because they need to appear first
|
// Reply-like messages cannot join existing groups because they need to appear first
|
||||||
if (message.Kind == MessageKind.Reply)
|
if (message.IsReplyLike)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Grouping for system notifications
|
// Grouping for system notifications
|
||||||
if (message.Kind.IsSystemNotification())
|
if (message.IsSystemNotification)
|
||||||
{
|
{
|
||||||
// Can only be grouped with other system notifications
|
// Can only be grouped with other system notifications
|
||||||
if (!lastMessage.Kind.IsSystemNotification())
|
if (!lastMessage.IsSystemNotification)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Grouping for normal messages
|
// Grouping for normal messages
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Can only be grouped with other normal messages
|
// Can only be grouped with other normal messages
|
||||||
if (lastMessage.Kind.IsSystemNotification())
|
if (lastMessage.IsSystemNotification)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Messages must be within 7 minutes of each other
|
// Messages must be within 7 minutes of each other
|
||||||
|
|
|
||||||
|
|
@ -273,8 +273,11 @@ internal class JsonMessageWriter : MessageWriter
|
||||||
_writer.WriteStartObject("channel");
|
_writer.WriteStartObject("channel");
|
||||||
_writer.WriteString("id", Context.Request.Channel.Id.ToString());
|
_writer.WriteString("id", Context.Request.Channel.Id.ToString());
|
||||||
_writer.WriteString("type", Context.Request.Channel.Kind.ToString());
|
_writer.WriteString("type", Context.Request.Channel.Kind.ToString());
|
||||||
|
|
||||||
|
// Original schema did not account for threads, so 'category' actually refers to the parent channel
|
||||||
_writer.WriteString("categoryId", Context.Request.Channel.Parent?.Id.ToString());
|
_writer.WriteString("categoryId", Context.Request.Channel.Parent?.Id.ToString());
|
||||||
_writer.WriteString("category", Context.Request.Channel.ParentNameWithFallback);
|
_writer.WriteString("category", Context.Request.Channel.Parent?.Name);
|
||||||
|
|
||||||
_writer.WriteString("name", Context.Request.Channel.Name);
|
_writer.WriteString("name", Context.Request.Channel.Name);
|
||||||
_writer.WriteString("topic", Context.Request.Channel.Topic);
|
_writer.WriteString("topic", Context.Request.Channel.Topic);
|
||||||
|
|
||||||
|
|
@ -329,7 +332,7 @@ internal class JsonMessageWriter : MessageWriter
|
||||||
_writer.WriteBoolean("isPinned", message.IsPinned);
|
_writer.WriteBoolean("isPinned", message.IsPinned);
|
||||||
|
|
||||||
// Content
|
// Content
|
||||||
if (message.Kind.IsSystemNotification())
|
if (message.IsSystemNotification)
|
||||||
{
|
{
|
||||||
_writer.WriteString("content", message.GetFallbackContent());
|
_writer.WriteString("content", message.GetFallbackContent());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@
|
||||||
<div id="chatlog__message-container-@message.Id" class="chatlog__message-container @(message.IsPinned ? "chatlog__message-container--pinned" : null)" data-message-id="@message.Id">
|
<div id="chatlog__message-container-@message.Id" class="chatlog__message-container @(message.IsPinned ? "chatlog__message-container--pinned" : null)" data-message-id="@message.Id">
|
||||||
<div class="chatlog__message">
|
<div class="chatlog__message">
|
||||||
@* System notification *@
|
@* System notification *@
|
||||||
@if (message.Kind.IsSystemNotification())
|
@if (message.IsSystemNotification)
|
||||||
{
|
{
|
||||||
<div class="chatlog__message-aside">
|
<div class="chatlog__message-aside">
|
||||||
<svg class="chatlog__system-notification-icon">
|
<svg class="chatlog__system-notification-icon">
|
||||||
|
|
@ -329,7 +329,7 @@
|
||||||
|
|
||||||
<div class="chatlog__embed">
|
<div class="chatlog__embed">
|
||||||
<div class="chatlog__embed-invite-container">
|
<div class="chatlog__embed-invite-container">
|
||||||
<div class="chatlog__embed-invite-title">@(invite.Channel?.Kind.IsDirect() == true ? "Invite to join a group DM" : "Invite to join a server")</div>
|
<div class="chatlog__embed-invite-title">@(invite.Channel?.IsDirect == true ? "Invite to join a group DM" : "Invite to join a server")</div>
|
||||||
<div class="chatlog__embed-invite">
|
<div class="chatlog__embed-invite">
|
||||||
<div class="chatlog__embed-invite-guild-icon-container">
|
<div class="chatlog__embed-invite-guild-icon-container">
|
||||||
<img class="chatlog__embed-invite-guild-icon" src="@await ResolveAssetUrlAsync(invite.Channel?.IconUrl ?? invite.Guild.IconUrl)" alt="Guild icon" loading="lazy">
|
<img class="chatlog__embed-invite-guild-icon" src="@await ResolveAssetUrlAsync(invite.Channel?.IconUrl ?? invite.Guild.IconUrl)" alt="Guild icon" loading="lazy">
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ internal partial class PlainTextMarkdownVisitor : MarkdownVisitor
|
||||||
_buffer.Append($"#{name}");
|
_buffer.Append($"#{name}");
|
||||||
|
|
||||||
// Voice channel marker
|
// Voice channel marker
|
||||||
if (channel?.Kind.IsVoice() == true)
|
if (channel?.IsVoice == true)
|
||||||
_buffer.Append(" [voice]");
|
_buffer.Append(" [voice]");
|
||||||
}
|
}
|
||||||
else if (mention.Kind == MentionKind.Role)
|
else if (mention.Kind == MentionKind.Role)
|
||||||
|
|
|
||||||
|
|
@ -200,9 +200,7 @@ internal class PlainTextMessageWriter : MessageWriter
|
||||||
{
|
{
|
||||||
await _writer.WriteLineAsync(new string('=', 62));
|
await _writer.WriteLineAsync(new string('=', 62));
|
||||||
await _writer.WriteLineAsync($"Guild: {Context.Request.Guild.Name}");
|
await _writer.WriteLineAsync($"Guild: {Context.Request.Guild.Name}");
|
||||||
await _writer.WriteLineAsync(
|
await _writer.WriteLineAsync($"Channel: {Context.Request.Channel.GetHierarchicalName()}");
|
||||||
$"Channel: {Context.Request.Channel.ParentNameWithFallback} / {Context.Request.Channel.Name}"
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(Context.Request.Channel.Topic))
|
if (!string.IsNullOrWhiteSpace(Context.Request.Channel.Topic))
|
||||||
{
|
{
|
||||||
|
|
@ -238,7 +236,7 @@ internal class PlainTextMessageWriter : MessageWriter
|
||||||
await WriteMessageHeaderAsync(message);
|
await WriteMessageHeaderAsync(message);
|
||||||
|
|
||||||
// Content
|
// Content
|
||||||
if (message.Kind.IsSystemNotification())
|
if (message.IsSystemNotification)
|
||||||
{
|
{
|
||||||
await _writer.WriteLineAsync(message.GetFallbackContent());
|
await _writer.WriteLineAsync(message.GetFallbackContent());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1004,7 +1004,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="preamble__entries-container">
|
<div class="preamble__entries-container">
|
||||||
<div class="preamble__entry">@Context.Request.Guild.Name</div>
|
<div class="preamble__entry">@Context.Request.Guild.Name</div>
|
||||||
<div class="preamble__entry">@Context.Request.Channel.ParentNameWithFallback / @Context.Request.Channel.Name</div>
|
<div class="preamble__entry">@Context.Request.Channel.GetHierarchicalName()</div>
|
||||||
|
|
||||||
@if (!string.IsNullOrWhiteSpace(Context.Request.Channel.Topic))
|
@if (!string.IsNullOrWhiteSpace(Context.Request.Channel.Topic))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,10 @@ public class ChannelToGroupKeyConverter : IValueConverter
|
||||||
public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
|
public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
|
||||||
value switch
|
value switch
|
||||||
{
|
{
|
||||||
Channel channel when channel.Kind.IsThread()
|
Channel { IsThread: true, Parent: not null } channel
|
||||||
=> $"Threads in #{channel.ParentNameWithFallback}",
|
=> $"Threads in #{channel.Parent.Name}",
|
||||||
|
|
||||||
Channel channel => channel.ParentNameWithFallback,
|
Channel channel => channel.Parent?.Name ?? "???",
|
||||||
|
|
||||||
_ => null
|
_ => null
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,6 @@ public class DashboardViewModel : PropertyChangedBase
|
||||||
|
|
||||||
public Guild? SelectedGuild { get; set; }
|
public Guild? SelectedGuild { get; set; }
|
||||||
|
|
||||||
public bool IsDirectMessageGuildSelected => SelectedGuild?.Id == Guild.DirectMessages.Id;
|
|
||||||
|
|
||||||
public IReadOnlyList<Channel>? AvailableChannels { get; private set; }
|
public IReadOnlyList<Channel>? AvailableChannels { get; private set; }
|
||||||
|
|
||||||
public IReadOnlyList<Channel>? SelectedChannels { get; set; }
|
public IReadOnlyList<Channel>? SelectedChannels { get; set; }
|
||||||
|
|
@ -164,7 +162,7 @@ public class DashboardViewModel : PropertyChangedBase
|
||||||
// Regular channels
|
// Regular channels
|
||||||
await foreach (var channel in _discord.GetGuildChannelsAsync(SelectedGuild.Id))
|
await foreach (var channel in _discord.GetGuildChannelsAsync(SelectedGuild.Id))
|
||||||
{
|
{
|
||||||
if (channel.Kind == ChannelKind.GuildCategory)
|
if (channel.IsCategory)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
channels.Add(channel);
|
channels.Add(channel);
|
||||||
|
|
|
||||||
|
|
@ -313,10 +313,10 @@
|
||||||
<ListBox.Style>
|
<ListBox.Style>
|
||||||
<Style BasedOn="{StaticResource {x:Type ListBox}}" TargetType="{x:Type ListBox}">
|
<Style BasedOn="{StaticResource {x:Type ListBox}}" TargetType="{x:Type ListBox}">
|
||||||
<Style.Triggers>
|
<Style.Triggers>
|
||||||
<DataTrigger Binding="{Binding IsDirectMessageGuildSelected}" Value="True">
|
<DataTrigger Binding="{Binding SelectedGuild.IsDirect}" Value="True">
|
||||||
<Setter Property="ItemsSource" Value="{Binding Source={StaticResource AvailableDirectChannelsViewSource}}" />
|
<Setter Property="ItemsSource" Value="{Binding Source={StaticResource AvailableDirectChannelsViewSource}}" />
|
||||||
</DataTrigger>
|
</DataTrigger>
|
||||||
<DataTrigger Binding="{Binding IsDirectMessageGuildSelected}" Value="False">
|
<DataTrigger Binding="{Binding SelectedGuild.IsDirect}" Value="False">
|
||||||
<Setter Property="ItemsSource" Value="{Binding Source={StaticResource AvailableChannelsViewSource}}" />
|
<Setter Property="ItemsSource" Value="{Binding Source={StaticResource AvailableChannelsViewSource}}" />
|
||||||
</DataTrigger>
|
</DataTrigger>
|
||||||
</Style.Triggers>
|
</Style.Triggers>
|
||||||
|
|
|
||||||
|
|
@ -60,8 +60,10 @@
|
||||||
FontWeight="Light"
|
FontWeight="Light"
|
||||||
TextTrimming="CharacterEllipsis"
|
TextTrimming="CharacterEllipsis"
|
||||||
Visibility="{Binding IsSingleChannel, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
|
Visibility="{Binding IsSingleChannel, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
|
||||||
<Run Text="{Binding Channels[0].ParentNameWithFallback, Mode=OneWay}" ToolTip="{Binding Channels[0].ParentNameWithFallback, Mode=OneWay}" />
|
<TextBlock Visibility="{Binding Channels[0].Parent, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
|
||||||
<Run Text="/" />
|
<Run Text="{Binding Channels[0].Parent.Name, Mode=OneWay}" ToolTip="{Binding Channels[0].Parent.Name, Mode=OneWay}" />
|
||||||
|
<Run Text="/" />
|
||||||
|
</TextBlock>
|
||||||
<Run
|
<Run
|
||||||
FontWeight="SemiBold"
|
FontWeight="SemiBold"
|
||||||
Text="{Binding Channels[0].Name, Mode=OneWay}"
|
Text="{Binding Channels[0].Name, Mode=OneWay}"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue