Export topic as markdown

I found this UI: Topic and Category Export/Import but that does not cover what I was thinking about:

  • A means to export an entire public or DM topic as a single markdown document where the export action is UI-accessible to all the participants in said topic.

And maybe (but for me not required) to have this feature available for anyone on public topics.


I interact with many Discourse forums publicly and DM’ingly and have a need to archive discussions there in a personal markdown-based knowledge base. This is not only very time-consuming, but I can’t get the raw markdown of other people’s posts in forums where I’m not mod or admin (logically), so I have to recreate it manually.

7 curtidas

You can already access the raw markdown to topics:
Https://meta.discourse.org/raw/152185

2 curtidas

Thanks, that would be so cool. But it only returns the first post in the topic and not the entire conversation thread.

Edit: More doable, by iterating over each post in the thread in raw mode, but for a thread with 60 posts still a lot of work. Furthermore it contains only the body of the post and there is no information on who posted, and when.

You can use the print function on a topic and save the output to a pdf. It is not markdown but it is easy!

1 curtida

Thank you, yes, I sometimes use that, but the content becomes ‘locked in’. It does not fit well with my knowledge base (create cross-links, etc.). Markdown is so simple and easy to work with, that I select all my tools around it. It is a great timesaver if you can just move MD snippets around all over the place.

2 curtidas

I was just asked that question yesterday. Are you referring to the print function of the browser? Or is there a Discourse feature to print the entire topic thread that I am not seeing?

https://meta.discourse.org/t/print-long-topic-to-pdf-redux-again/44639/37?u=falco

2 curtidas

Funny, I too would like something like this! So just another vote of support, I guess…

Olá,

Acabei de criar uma conta aqui para dar minha opinião e dizer que também acho esse tipo de funcionalidade muito importante!

A impressão (para PDF) atualmente não funciona bem com threads que contêm blocos de código, pois eles não quebram ou se expandem, resultando em cortes.

Acho que uma maneira confiável e relativamente fácil de extrair conteúdo do Discourse, por exemplo, para fins de arquivamento, é realmente importante.

Outro ponto a considerar: participo de um fórum que acabou de consolidar muitos usuários de uma lista de e-mails que foi encerrada – durante as discussões de transição sobre manter a lista de e-mails ativa ou mudar totalmente para o fórum, um membro cego disse que não conseguiria participar no fórum devido à falta de suporte para navegadores baseados em texto. Acho que um modo “raw” adequado, com atribuição de autor e todas as threads, contribuiria para uma maior inclusão.

2 curtidas

Vamos ver. Incluirei um bloco de código aqui com bastante código e verei como ele fica impresso:

import java.util.Scanner;

/**
 * Jogo de AceyDucey
 * <p>
 * Baseado no jogo básico de AceyDucey aqui
 * https://github.com/coding-horror/basic-computer-games/blob/main/01%20Acey%20Ducey/aceyducey.bas
 * Nota: A ideia era criar uma versão do jogo Basic dos anos 1970 em Java, sem introduzir
 * novos recursos - nenhum texto adicional, verificação de erros, etc. foi adicionado.
 */
public class AceyDucey {

    // Quantidade atual de dinheiro do jogador
    private int playerAmount;

    // Primeira carta do dealer sorteada
    private Card firstCard;

    // Segunda carta do dealer sorteada
    private Card secondCard;

    // Carta sorteada do jogador
    private Card playersCard;

    // Usado para exibir introdução/instruções do jogo
    private boolean firstTimePlaying = true;

    // estado do jogo para determinar se o jogo acabou
    private boolean gameOver = false;

    // Usado para entrada do teclado
    private final Scanner kbScanner;

    // Valor constante para cartas de um baralho - 2 mais baixo, 14 (Ás) mais alto
    public static final int LOW_CARD_RANGE = 2;
    public static final int HIGH_CARD_RANGE = 14;

    public AceyDucey() {
        // Inicializa o dinheiro do jogador
        playerAmount = 100;

        // Inicializa o scanner do teclado
        kbScanner = new Scanner(System.in);
    }

    // Método para jogar novamente - método público chamado da classe que invoca o jogo
    // Se o jogador digitar SIM, o jogo pode ser jogado novamente (retorna true)
    // caso contrário, não (retorna false)
    public boolean playAgain() {
        System.out.println();
        System.out.println("DESCULPE, AMIGO, MAS VOCÊ GASTOU TODO O SEU DINHEIRO.");
        System.out.println();
        System.out.println();
        System.out.print("TENTAR NOVAMENTE (SIM OU NÃO) ");
        String playAgain = kbScanner.next().toUpperCase();
        System.out.println();
        System.out.println();
        if (playAgain.equals("SIM")) {
            return true;
        } else {
            System.out.println("OK, ESPERO QUE TENHA SE DIVERTIDO!");
            return false;
        }
    }

    // método do loop do jogo

    public void play() {

        // Continua jogando mãos até o jogador ficar sem dinheiro
        do {
            if (firstTimePlaying) {
                intro();
                firstTimePlaying = false;
            }
            displayBalance();
            drawCards();
            displayCards();
            int betAmount = getBet();
            playersCard = randomCard();
            displayPlayerCard();
            if (playerWon()) {
                System.out.println("VOCÊ GANHOU!!");
                playerAmount += betAmount;
            } else {
                System.out.println("DESCULPE, VOCÊ PERDEU");
                playerAmount -= betAmount;
                // Jogador ficou sem dinheiro?
                if (playerAmount <= 0) {
                    gameOver = true;
                }
            }

        } while (!gameOver); // Continua jogando até o jogador ficar sem dinheiro
    }

    // Método para determinar se o jogador ganhou (retorna true) ou perdeu (retorna false)
    // para ganhar, a carta do jogador deve estar no intervalo da primeira e segunda carta do dealer
    // incluindo a primeira e a segunda carta.
    private boolean playerWon() {
        // vencedor
        return (playersCard.getValue() >= firstCard.getValue())
                && playersCard.getValue() <= secondCard.getValue();

    }

    private void displayPlayerCard() {
        System.out.println(playersCard.getName());
    }

    // Obtém a aposta do jogador e retorna o valor
    // 0 é considerado uma aposta válida, mas mais do que o jogador tem disponível não é
    // o método irá repetir até que uma aposta válida seja inserida.
    private int getBet() {
        boolean validBet = false;
        int amount;
        do {
            System.out.print("QUAL É A SUA APOSTA ");
            amount = kbScanner.nextInt();
            if (amount == 0) {
                System.out.println("MEDROSO!!");
                validBet = true;
            } else if (amount > playerAmount) {
                System.out.println("DESCULPE, MEU AMIGO, MAS VOCÊ APOSTOU DEMAIS.");
                System.out.println("VOCÊ TEM APENAS " + playerAmount + " DÓLARES PARA APOSTAR.");
            } else {
                validBet = true;
            }
        } while (!validBet);

        return amount;
    }

    private void displayBalance() {
        System.out.println("VOCÊ AGORA TEM " + playerAmount + " DÓLARES.");
    }

    private void displayCards() {
        System.out.println("AQUI ESTÃO SUAS PRÓXIMAS DUAS CARTAS: ");
        System.out.println(firstCard.getName());
        System.out.println(secondCard.getName());
    }

    // Sorteia duas cartas do dealer e as salva para uso posterior.
    // garante que a primeira carta tenha um valor menor que a segunda
    private void drawCards() {

        do {
            firstCard = randomCard();
            secondCard = randomCard();
        } while (firstCard.getValue() >= secondCard.getValue());
    }

    // Cria uma carta aleatória
    private Card randomCard() {
        return new Card((int) (Math.random()
                * (HIGH_CARD_RANGE - LOW_CARD_RANGE + 1) + LOW_CARD_RANGE));
    }

    public void intro() {
        System.out.println("JOGO DE CARTAS ACEY DUCEY");
        System.out.println("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
        System.out.println();
        System.out.println();
        System.out.println("ACEY-DUCEY É JOGADO DA SEGUINTE MANEIRA");
        System.out.println("O DEALER (COMPUTADOR) DISTRIBUI DUAS CARTAS VIRADAS PARA CIMA");
        System.out.println("VOCÊ TEM A OPÇÃO DE APOSTAR OU NÃO APOSTAR DEPENDENDO");
        System.out.println("SE A CARTA TERÁ OU NÃO");
        System.out.println("UM VALOR ENTRE AS DUAS PRIMEIRAS.");
        System.out.println("SE VOCÊ NÃO QUISER APOSTAR, INSIRA: 0");
    }
}

Note que temos suporte de acessibilidade bastante completo, então eu estaria interessado em saber especificamente o que não está funcionando para seu usuário cego @thresholdpeople.

Além disso, o bloco de código acima parece bom na versão impressa para mim. Acabei de pressionar “imprimir” no Chrome e depois “salvar como PDF” para gerar uma versão em PDF deste tópico:

Export topic as markdown - feature - Discourse Meta.pdf (249,9 KB)

Não estou vendo um problema. Por favor, aponte áreas específicas no PDF que não estão corretas, se você vir um problema. Obrigado!

Obrigado por investigar isso.

Estou usando o Vivaldi, mas também usei o Chrome, em vários computadores, nem todos com configurações de navegador sincronizadas, mas quando uso a impressão, seu bloco de código é cortado em:

     // Players drawn card
     private Card playersCard;

que é também tudo o que consigo ver até ver sua postagem inline (tenho que rolar para baixo dentro do quadro de código para ver mais). Eu postaria minha versão, mas não tenho posts suficientes para fazer upload de arquivos, mas você tem a ideia.

Sua versão impressa certamente parece melhor, não tenho certeza por que é diferente, para ser honesto, mas também não é perfeita. As linhas de código não quebram e, portanto, são cortadas, e todas as páginas têm um retângulo azul flutuante no canto inferior esquerdo que também obscurece parte do texto. Infelizmente, nesse estado, também não é realmente utilizável.

Alguém no fórum SuperCollider forneceu a solução de inserir o seguinte bloco CSS no inspetor do navegador, ou ao usar um plugin do navegador (atualmente tenho a extensão do Chrome Stylish, e ela adiciona automaticamente quando estou naquele fórum):

pre code {
    white-space: 	pre-wrap;
    max-height: 	none;
    background: 	#fafafa;
}

Usar isso faz com que a impressão funcione bem para mim. E com a extensão do navegador, não preciso entrar e me preocupar em adicioná-la toda vez que quero salvar algo, o que é a solução real… caso contrário, é muito trabalho.

Ainda assim, gostaria que houvesse uma maneira mais fácil de arquivar threads, ou melhor, gostaria que houvesse uma maneira de não precisar dessas etapas adicionais.

Especialmente porque a maior parte da funcionalidade já existe: seja visualizando uma postagem bruta ou podendo imprimir. Mas sim, não é possível ver o thread inteiro em formato bruto, apenas uma única postagem, e a impressão não funciona muito bem.

Dito isso, os marcadores são um recurso incrível do fórum e eu os uso o tempo todo, mas isso ainda mantém tudo contido dentro do discourse.

1 curtida

Poderíamos adicionar uma rota que retorne o tópico inteiro como @falco bruto? Isso pode ser útil, embora precisemos ter cuidado com megatopicos..

Nós certamente já temos isso para posts individuais, por exemplo

https://meta.discourse.org/raw/152185/12

3 curtidas

Isso é certamente possível, embora seja um caso de uso meio específico.

O formato seria algo como:

username | timestamp | post_number

corpo da postagem

---

username | timestamp | post_number

corpo da postagem

---

username | timestamp | post_number

corpo da postagem

?

2 curtidas

Sim, eu apoio isso. Se temos uma rota /raw/ para posts, por que não ter uma para um tópico?

2 curtidas

Atualmente, a rota https://meta.discourse.org/raw/152185 retorna apenas o OP. Tudo bem alterar o comportamento dessa rota? As pessoas precisarão chamar explicitamente https://meta.discourse.org/raw/152185/1 para obter apenas o OP.

2 curtidas

O que você achar melhor está bom para mim.

2 curtidas

Isso está ativo agora: https://meta.discourse.org/raw/152185

Me avise se é isso que você tinha em mente @here

8 curtidas

Adorei! Parece bom para mim! :heart_eyes:

3 curtidas

Isso é muito bom. Obrigado :pray:

3 curtidas

Muito obrigado! e mais personagens!

2 curtidas