public async Task HandleArchiveCommand(ITextChannel channel, [Remainder] string category) { if (string.IsNullOrEmpty(category)) { return; } category = new CultureInfo("en-GB", false).TextInfo.ToTitleCase(category); string env = HARDCODED_ARCHIVE_PATH; Guild g = new Guild(new Snowflake(Context.Guild.Id), Context.Guild.Name, Context.Guild.IconUrl); var discordCategory = channel.CategoryId.HasValue ? await channel.GetCategoryAsync() : null; ChannelCategory cc = new ChannelCategory(new Snowflake(channel.CategoryId.Value), discordCategory.Name, discordCategory.Position); Channel c = new Channel(new Snowflake(channel.Id), ChannelKind.GuildTextChat, g.Id, cc, channel.Name, channel.Position, channel.Topic); ExportRequest req = new ExportRequest(g, c, env + $"/{category}/Light/{channel.Name}.html", ExportFormat.HtmlLight, null, null, PartitionLimit.Null, MessageFilter.Null, true, true, "yyyy-MM-dd hh:mm:ss"); ExportRequest req2 = new ExportRequest(g, c, env + $"/{category}/Dark/{channel.Name}.html", ExportFormat.HtmlDark, null, null, PartitionLimit.Null, MessageFilter.Null, true, true, "yyyy-MM-dd hh:mm:ss"); bool isLight = true; string path = env + $"/{category}/{(isLight ? "Light" : "Dark")}/{channel.Name}.html_Files/"; var message = await Context.Channel.SendMessageAsync("", false, Embeds.Archiving(Context.User, channel, "Starting")).ConfigureAwait(false); //Timer _timer = new Timer(async _ => await OnTick(), null, TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(10)); try { await message.ModifyAsync(x => x.Embed = Embeds.Archiving(Context.User, channel, "Exporting Light Mode")).ConfigureAwait(false); await _exporter.ExportChannelAsync(req).ConfigureAwait(false); await message.ModifyAsync(x => x.Embed = Embeds.Archiving(Context.User, channel, "Exporting Dark Mode")).ConfigureAwait(false); isLight = false; await _exporter.ExportChannelAsync(req2).ConfigureAwait(false); await message.ModifyAsync(x => x.Embed = Embeds.Archiving(Context.User, channel, "Done")); } catch (Exception ex) { await message.ModifyAsync(x => { x.Content = $"Error occured: {ex}"; x.Embed = null; }); } //async Task OnTick() //{ // await message.ModifyAsync(x => x.Content = $"Exported: {Directory.GetFiles(path, "*.*").Length} files."); //} }
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 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); }