public async void ExportChannels() { var token = _settingsService.LastToken; if (token == null || SelectedGuild == null || SelectedChannels == null || !SelectedChannels.Any()) { return; } var dialog = _viewModelFactory.CreateExportSetupViewModel(SelectedGuild, SelectedChannels); if (await _dialogManager.ShowDialogAsync(dialog) != true) { return; } var exporter = new ChannelExporter(token); var operations = ProgressManager.CreateOperations(dialog.Channels !.Count); var successfulExportCount = 0; await dialog.Channels.Zip(operations).ParallelForEachAsync(async tuple => { var(channel, operation) = tuple; try { var request = new ExportRequest( dialog.Guild !, channel !, dialog.OutputPath !, dialog.SelectedFormat, dialog.After?.Pipe(Snowflake.FromDate), dialog.Before?.Pipe(Snowflake.FromDate), dialog.PartitionLimit, dialog.ShouldDownloadMedia, _settingsService.ShouldReuseMedia, _settingsService.DateFormat ); await exporter.ExportChannelAsync(request, operation); Interlocked.Increment(ref successfulExportCount); } catch (DiscordChatExporterException ex) when(!ex.IsCritical) { Notifications.Enqueue(ex.Message.TrimEnd('.')); } finally { operation.Dispose(); } }, _settingsService.ParallelLimit.ClampMin(1)); // Notify of overall completion if (successfulExportCount > 0) { Notifications.Enqueue($"Successfully exported {successfulExportCount} channel(s)"); } }
public async Task <Stream> Post(ExportOptionsv1 options) { var parsed = Snowflake.TryParse(options.ChannelId); var channelId = parsed ?? Snowflake.Zero; var client = new DiscordClient(options.Token); Channel channel; try { channel = await client.GetChannelAsync(channelId); } catch (DiscordChatExporterException e) { var isUnauthorized = e.Message.Contains("Authentication"); var content = isUnauthorized ? "Invalid Discord token provided." : "Please provide a valid channel"; Response.ContentType = "application/json"; Response.StatusCode = isUnauthorized ? 401 : 409; return(GenerateStreamFromString("{ \"error\": \"" + content + "\" }")); } var guild = await client.GetGuildAsync(channel.GuildId); var res = await client.GetJsonResponseAsync("users/@me"); var me = DiscordChatExporter.Core.Discord.Data.User.Parse(res); _logger.LogInformation($"[{me.FullName} ({me.Id})] Exporting #{channel.Name} ({channel.Id}) within {guild.Name} ({guild.Id})"); var path = GetPath(channel.Id.ToString()); var request = new ExportRequest( guild, channel, path, ExportFormat.HtmlDark, null, null, null, MessageFilter.Null, false, false, "dd-MMM-yy hh:mm tt" ); var exporter = new ChannelExporter(client); await exporter.ExportChannelAsync(request); var stream = new FileStream(path, FileMode.Open); Response.ContentType = "text/html; charset=UTF-8"; Response.StatusCode = 200; deleteFile(path); return(stream); }
internal static async Task ExecuteAsync(ulong channelID, uint ticketID) { DiscordClient discordClient = new DiscordClient(new AuthToken(AuthTokenKind.Bot, Config.token)); ChannelExporter Exporter = new ChannelExporter(discordClient); if (!Directory.Exists("./transcripts")) { Directory.CreateDirectory("./transcripts"); } string dateFormat = "yyyy-MMM-dd HH:mm"; // Configure settings if (Config.timestampFormat != "") { dateFormat = Config.timestampFormat; } Channel channel = await discordClient.GetChannelAsync(new Snowflake(channelID)); Guild guild = await discordClient.GetGuildAsync(channel.GuildId); ExportRequest request = new ExportRequest( guild: guild, channel: channel, outputPath: GetPath(ticketID), format: ExportFormat.HtmlDark, after: null, before: null, partitionLimit: PartitionLimit.Null, messageFilter: MessageFilter.Null, shouldDownloadMedia: false, shouldReuseMedia: false, dateFormat: dateFormat ); await Exporter.ExportChannelAsync(request); }
public async Task <Stream> Post(ExportOptions options) { Stream SendJsonError(string error, int status) { Response.ContentType = "application/json"; Response.StatusCode = status; return(GenerateStreamFromString("{ \"error\": \"" + error + "\" }")); } if (!Enum.IsDefined(typeof(ExportFormat), options.export_format)) { return(SendJsonError($"An export format with the id '{options.export_format}' was not found.", 400)); } var parsed = Snowflake.TryParse(options.channel_id); var channelId = parsed ?? Snowflake.Zero; var client = new DiscordClient(options.token); client._tokenKind = TokenKind.Bot; Channel channel; try { channel = await client.GetChannelAsync(channelId); } catch (DiscordChatExporterException e) { if (e.Message.Contains("Authentication")) { return(SendJsonError("An invalid Discord token was provided.", 401)); } if (e.Message.Contains("Requested resource does not exist")) { return(SendJsonError("A channel with the provided ID was not found.", 404)); } return(SendJsonError($"An unknown error occurred: {e.Message}", 500)); } var guild = await client.GetGuildAsync(channel.GuildId); var res = await client.GetJsonResponseAsync("users/@me"); var me = DiscordChatExporter.Core.Discord.Data.User.Parse(res); var path = GetPath(channel.Id.ToString(), options.export_format); _logger.LogInformation($"[{me.FullName} ({me.Id})] Exporting #{channel.Name} ({channel.Id}) within {guild.Name} ({guild.Id}) to {path}"); var request = new ExportRequest( guild, channel, path, options.export_format, Snowflake.TryParse(options.after), Snowflake.TryParse(options.before), PartitionLimit.Null, MessageFilter.Null, false, false, options.date_format ); var exporter = new ChannelExporter(client); _logger.LogInformation("Starting export"); var messageCount = await exporter.ExportChannelAsync(request); _logger.LogInformation("Finished exporting"); var stream = new FileStream(path, FileMode.Open); var ext = options.export_format.GetFileExtension(); if (ext == "txt") { ext = "plain"; } Response.ContentType = $"text/{ext}; charset=UTF-8"; Response.Headers.Add("X-Message-Count", messageCount.ToString()); Response.StatusCode = 200; deleteFile(path); return(stream); }
public ArchiveModule(DiscordSocketClient client, IConfigurationRoot config) { _client = client; _config = config; _exporter = new ChannelExporter(new AuthToken(AuthTokenKind.Bot, _config["tokens:dev"].ToString())); }
public override async Task CreateExport(CreateExportRequest options, IServerStreamWriter <CreateExportResponse> responseStream, ServerCallContext context) { var ef = options.ExportFormat; var exportFormat = (DiscordChatExporter.Core.Exporting.ExportFormat)ef; var parsed = Snowflake.TryParse(options.ChannelId); var channelId = parsed ?? Snowflake.Zero; var client = new DiscordClient(options.Token); client._tokenKind = TokenKind.Bot; Channel channel; try { channel = await client.GetChannelAsync(channelId); } catch (DiscordChatExporterException e) { if (e.Message.Contains("Authentication")) { throw new RpcException(new Status(StatusCode.PermissionDenied, "An invalid Discord token was provided.")); } if (e.Message.Contains("Requested resource does not exist")) { throw new RpcException(new Status(StatusCode.NotFound, "A channel with the provided ID was not found.")); } throw new RpcException(new Status(StatusCode.Unknown, $"An unknown error occurred: {e.Message}")); } var guild = await client.GetGuildAsync(channel.GuildId); var res = await client.GetJsonResponseAsync("users/@me"); var me = DiscordChatExporter.Core.Discord.Data.User.Parse(res); var path = GetPath(channel.Id.ToString(), exportFormat); _logger.LogInformation($"[{me.FullName} ({me.Id})] Exporting #{channel.Name} ({channel.Id}) within {guild.Name} ({guild.Id}) to {path}"); var request = new ExportRequest( guild, channel, path, exportFormat, Snowflake.TryParse(options.After), Snowflake.TryParse(options.Before), PartitionLimit.Null, MessageFilter.Null, false, false, options.DateFormat ); var exporter = new ChannelExporter(client); _logger.LogInformation("Starting export"); var progress = new Progress <double>(p => responseStream.WriteAsync(new CreateExportResponse { Progress = p })); var messageCount = await exporter.ExportChannelAsync(request, progress); _logger.LogInformation("Finished exporting"); var buffer = new byte[ChunkSize]; await using var readStream = File.OpenRead(path); while (true) { var count = await readStream.ReadAsync(buffer); if (count == 0) { break; } Console.WriteLine("Sending file data chunk of length " + count); await responseStream.WriteAsync(new CreateExportResponse { Data = new ExportComplete { MessageCount = messageCount, Data = UnsafeByteOperations.UnsafeWrap(buffer.AsMemory(0, count)) } }); } deleteFile(path); }
public async Task <Stream> Post(ExportOptions options) { var parsed = Snowflake.TryParse(options.ChannelId); var channelId = parsed ?? Snowflake.Zero; var token = new AuthToken(AuthTokenType.Bot, options.Token); var client = new DiscordClient(token); Channel channel; try { channel = await client.GetChannelAsync(channelId); } catch (DiscordChatExporterException e) { _logger.LogError($"{e}"); var isUnauthorized = e.Message.Contains("Authentication"); var content = isUnauthorized ? "Invalid Discord token provided." : "Please provide a valid channel"; Response.ContentType = "application/json"; Response.StatusCode = isUnauthorized ? 401 : 409; return(GenerateStreamFromString("{ \"error\": \"" + content + "\" }")); } var guild = await client.GetGuildAsync(channel.GuildId); using var req = new HttpRequestMessage(HttpMethod.Get, new Uri("https://discord.com/api/v8/users/@me")); req.Headers.Authorization = token.GetAuthorizationHeader(); var res = await _httpclient.SendAsync(req, HttpCompletionOption.ResponseHeadersRead); var text = await res.Content.ReadAsStringAsync(); var me = DiscordChatExporter.Domain.Discord.Models.User.Parse(JsonDocument.Parse(text).RootElement.Clone()); _logger.LogInformation($"[{me.FullName} ({me.Id})] Exporting #{channel.Name} ({channel.Id}) within {guild.Name} ({guild.Id})"); var path = GetPath(channel.Id.ToString()); var request = new ExportRequest( guild, channel, path, ExportFormat.HtmlDark, null, null, null, false, false, "dd-MMM-yy hh:mm tt" ); var exporter = new ChannelExporter(client); await exporter.ExportChannelAsync(request); var stream = new FileStream(path, FileMode.Open); Response.ContentType = "text/html; charset=UTF-8"; Response.StatusCode = 200; deleteFile(path); return(stream); }