Ejemplo n.º 1
0
        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)");
            }
        }
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
        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);
        }
Ejemplo n.º 4
0
        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);
        }
Ejemplo n.º 5
0
 public ArchiveModule(DiscordSocketClient client, IConfigurationRoot config)
 {
     _client   = client;
     _config   = config;
     _exporter = new ChannelExporter(new AuthToken(AuthTokenKind.Bot, _config["tokens:dev"].ToString()));
 }
Ejemplo n.º 6
0
    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);
    }
Ejemplo n.º 7
0
        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);
        }