diff --git a/DiscordChatExporter.Cli/Program.cs b/DiscordChatExporter.Cli/Program.cs index 923ad05..af44822 100644 --- a/DiscordChatExporter.Cli/Program.cs +++ b/DiscordChatExporter.Cli/Program.cs @@ -38,6 +38,7 @@ namespace DiscordChatExporter.Cli var verbTypes = new[] { typeof(ExportChatOptions), + typeof(ExportGuildOptions), typeof(GetChannelsOptions), typeof(GetDirectMessageChannelsOptions), typeof(GetGuildsOptions) @@ -48,6 +49,7 @@ namespace DiscordChatExporter.Cli // Execute commands parsedArgs.WithParsed(o => new ExportChatVerb(o).Execute()); + parsedArgs.WithParsed(o => new ExportGuildVerb(o).Execute()); parsedArgs.WithParsed(o => new GetChannelsVerb(o).Execute()); parsedArgs.WithParsed(o => new GetDirectMessageChannelsVerb(o).Execute()); parsedArgs.WithParsed(o => new GetGuildsVerb(o).Execute()); diff --git a/DiscordChatExporter.Cli/Verbs/ExportGuildVerb.cs b/DiscordChatExporter.Cli/Verbs/ExportGuildVerb.cs new file mode 100644 index 0000000..95daf9d --- /dev/null +++ b/DiscordChatExporter.Cli/Verbs/ExportGuildVerb.cs @@ -0,0 +1,79 @@ +using System; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using DiscordChatExporter.Cli.Verbs.Options; +using DiscordChatExporter.Core.Exceptions; +using DiscordChatExporter.Core.Helpers; +using DiscordChatExporter.Core.Models; +using DiscordChatExporter.Core.Services; +using Tyrrrz.Extensions; + +namespace DiscordChatExporter.Cli.Verbs +{ + public class ExportGuildVerb : Verb + { + public ExportGuildVerb(ExportGuildOptions options) + : base(options) + { + } + + public override async Task ExecuteAsync() + { + // Get services + var settingsService = Container.Instance.Get(); + var dataService = Container.Instance.Get(); + var exportService = Container.Instance.Get(); + + // Configure settings + if (Options.DateFormat.IsNotBlank()) + settingsService.DateFormat = Options.DateFormat; + if (Options.MessageGroupLimit > 0) + settingsService.MessageGroupLimit = Options.MessageGroupLimit; + + // Get channels + var channels = await dataService.GetGuildChannelsAsync(Options.GetToken(), Options.GuildId); + + // Loop through channels + foreach (var channel in channels.Where(c => c.Type.IsEither(ChannelType.GuildTextChat)) + .OrderBy(c => c.Name)) + { + try + { + // Print current channel name + Console.WriteLine($"Exporting chat from [{channel.Name}]..."); + + // Get chat log + var chatLog = await dataService.GetChatLogAsync(Options.GetToken(), channel, + Options.After, Options.Before); + + // Generate file path if not set or is a directory + var filePath = Options.FilePath; + if (filePath == null || filePath.EndsWith("/") || filePath.EndsWith("\\")) + { + // Generate default file name + var defaultFileName = ExportHelper.GetDefaultExportFileName(Options.ExportFormat, chatLog.Guild, + chatLog.Channel, Options.After, Options.Before); + + // Append the file name to the file path + filePath += defaultFileName; + } + + // Export + exportService.ExportChatLog(chatLog, filePath, Options.ExportFormat, Options.PartitionLimit); + + // Print result + Console.WriteLine($"Exported chat to [{filePath}]"); + } + catch (HttpErrorStatusCodeException ex) when (ex.StatusCode == HttpStatusCode.Forbidden) + { + Console.Error.WriteLine("You don't have access to this channel"); + } + catch (HttpErrorStatusCodeException ex) when (ex.StatusCode == HttpStatusCode.NotFound) + { + Console.Error.WriteLine("This channel doesn't exist"); + } + } + } + } +} \ No newline at end of file diff --git a/DiscordChatExporter.Cli/Verbs/Options/ExportChatOptions.cs b/DiscordChatExporter.Cli/Verbs/Options/ExportChatOptions.cs index bb40366..132d834 100644 --- a/DiscordChatExporter.Cli/Verbs/Options/ExportChatOptions.cs +++ b/DiscordChatExporter.Cli/Verbs/Options/ExportChatOptions.cs @@ -1,34 +1,11 @@ -using System; -using CommandLine; -using DiscordChatExporter.Core.Models; +using CommandLine; namespace DiscordChatExporter.Cli.Verbs.Options { [Verb("export", HelpText = "Export channel chat log to a file.")] - public class ExportChatOptions : TokenOptions + public class ExportChatOptions : ExportOptions { [Option('c', "channel", Required = true, HelpText = "Channel ID.")] public string ChannelId { get; set; } - - [Option('f', "format", Default = ExportFormat.HtmlDark, HelpText = "Output file format.")] - public ExportFormat ExportFormat { get; set; } - - [Option('o', "output", Default = null, HelpText = "Output file path.")] - public string FilePath { get; set; } - - [Option("after", Default = null, HelpText = "Limit to messages sent after this date.")] - public DateTime? After { get; set; } - - [Option("before", Default = null, HelpText = "Limit to messages sent before this date.")] - public DateTime? Before { get; set; } - - [Option('p', "partition", Default = null, HelpText = "Split output into partitions limited to this number of messages.")] - public int? PartitionLimit { get; set; } - - [Option("dateformat", Default = null, HelpText = "Date format used in output.")] - public string DateFormat { get; set; } - - [Option("grouplimit", Default = 0, HelpText = "Message group limit.")] - public int MessageGroupLimit { get; set; } } } \ No newline at end of file diff --git a/DiscordChatExporter.Cli/Verbs/Options/ExportGuildOptions.cs b/DiscordChatExporter.Cli/Verbs/Options/ExportGuildOptions.cs new file mode 100644 index 0000000..3d51a75 --- /dev/null +++ b/DiscordChatExporter.Cli/Verbs/Options/ExportGuildOptions.cs @@ -0,0 +1,11 @@ +using CommandLine; + +namespace DiscordChatExporter.Cli.Verbs.Options +{ + [Verb("exportguild", HelpText = "Export all available channels within a given guild.")] + public class ExportGuildOptions : ExportOptions + { + [Option('g', "guild", Required = true, HelpText = "Guild ID.")] + public string GuildId { get; set; } + } +} \ No newline at end of file diff --git a/DiscordChatExporter.Cli/Verbs/Options/ExportOptions.cs b/DiscordChatExporter.Cli/Verbs/Options/ExportOptions.cs new file mode 100644 index 0000000..cab470b --- /dev/null +++ b/DiscordChatExporter.Cli/Verbs/Options/ExportOptions.cs @@ -0,0 +1,30 @@ +using System; +using CommandLine; +using DiscordChatExporter.Core.Models; + +namespace DiscordChatExporter.Cli.Verbs.Options +{ + public class ExportOptions : TokenOptions + { + [Option('f', "format", Default = ExportFormat.HtmlDark, HelpText = "Output file format.")] + public ExportFormat ExportFormat { get; set; } + + [Option('o', "output", Default = null, HelpText = "Output file path.")] + public string FilePath { get; set; } + + [Option("after", Default = null, HelpText = "Limit to messages sent after this date.")] + public DateTime? After { get; set; } + + [Option("before", Default = null, HelpText = "Limit to messages sent before this date.")] + public DateTime? Before { get; set; } + + [Option('p', "partition", Default = null, HelpText = "Split output into partitions limited to this number of messages.")] + public int? PartitionLimit { get; set; } + + [Option("dateformat", Default = null, HelpText = "Date format used in output.")] + public string DateFormat { get; set; } + + [Option("grouplimit", Default = 0, HelpText = "Message group limit.")] + public int MessageGroupLimit { get; set; } + } +} \ No newline at end of file diff --git a/DiscordChatExporter.Core/Services/DataService.cs b/DiscordChatExporter.Core/Services/DataService.cs index 5b1f668..eb2668e 100644 --- a/DiscordChatExporter.Core/Services/DataService.cs +++ b/DiscordChatExporter.Core/Services/DataService.cs @@ -226,12 +226,9 @@ namespace DiscordChatExporter.Core.Services return new ChatLog(guild, channel, from, to, messages, mentionables); } - public async Task GetChatLogAsync(AuthToken token, string channelId, + public async Task GetChatLogAsync(AuthToken token, Channel channel, DateTime? from = null, DateTime? to = null, IProgress progress = null) { - // Get channel - var channel = await GetChannelAsync(token, channelId); - // Get guild var guild = channel.GuildId == Guild.DirectMessages.Id ? Guild.DirectMessages @@ -241,6 +238,16 @@ namespace DiscordChatExporter.Core.Services return await GetChatLogAsync(token, guild, channel, from, to, progress); } + public async Task GetChatLogAsync(AuthToken token, string channelId, + DateTime? from = null, DateTime? to = null, IProgress progress = null) + { + // Get channel + var channel = await GetChannelAsync(token, channelId); + + // Get the chat log + return await GetChatLogAsync(token, channel, from, to, progress); + } + public void Dispose() { _httpClient.Dispose();