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.

4 Likes

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

2 Likes

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 Like

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 Likes

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?

2 Likes

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

Hello,

I just made an account on here to chime in and say that I also think this type of feature is very important!

The print (to PDF) doesn’t currently work well with threads that contain code blocks as they don’t wrap or extend, so things end up cropped.

I think a reliable and fairly easy way to get content out from discourse, for instance for archiving purposes, is really important.

Another point of consideration: I participate on a forum that has just consolidated many users from a mailing list that closed down – during the transition discussions of whether to keep the mailing list active or switch over entirely to the forum, a member who is blind said that they wouldn’t be able to participate
on the forum due to a lack of support for text-based browsers. I think a proper raw mode, with author attribution and all threads would work toward greater inclusion.

2 Likes

Let’s see. I’ll include a code block here with a fair bit of code and see what it looks like in print:

import java.util.Scanner;

/**
 * Game of AceyDucey
 * <p>
 * Based on the Basic game of AceyDucey here
 * https://github.com/coding-horror/basic-computer-games/blob/main/01%20Acey%20Ducey/aceyducey.bas
 * Note:  The idea was to create a version of the 1970's Basic game in Java, without introducing
 * new features - no additional text, error checking, etc has been added.
 */
public class AceyDucey {

    // Current amount of players cash
    private int playerAmount;

    // First drawn dealer card
    private Card firstCard;

    // Second drawn dealer card
    private Card secondCard;

    // Players drawn card
    private Card playersCard;

    // User to display game intro/instructions
    private boolean firstTimePlaying = true;

    // game state to determine if game over
    private boolean gameOver = false;

    // Used for keyboard input
    private final Scanner kbScanner;

    // Constant value for cards from a deck - 2 lowest, 14 (Ace) highest
    public static final int LOW_CARD_RANGE = 2;
    public static final int HIGH_CARD_RANGE = 14;

    public AceyDucey() {
        // Initialise players cash
        playerAmount = 100;

        // Initialise kb scanner
        kbScanner = new Scanner(System.in);
    }

    // Play again method - public method called from class invoking game
    // If player enters YES then the game can be played again (true returned)
    // otherwise not (false)
    public boolean playAgain() {
        System.out.println();
        System.out.println("SORRY, FRIEND, BUT YOU BLEW YOUR WAD.");
        System.out.println();
        System.out.println();
        System.out.print("TRY AGAIN (YES OR NO) ");
        String playAgain = kbScanner.next().toUpperCase();
        System.out.println();
        System.out.println();
        if (playAgain.equals("YES")) {
            return true;
        } else {
            System.out.println("O.K., HOPE YOU HAD FUN!");
            return false;
        }
    }

    // game loop method

    public void play() {

        // Keep playing hands until player runs out of cash
        do {
            if (firstTimePlaying) {
                intro();
                firstTimePlaying = false;
            }
            displayBalance();
            drawCards();
            displayCards();
            int betAmount = getBet();
            playersCard = randomCard();
            displayPlayerCard();
            if (playerWon()) {
                System.out.println("YOU WIN!!");
                playerAmount += betAmount;
            } else {
                System.out.println("SORRY, YOU LOSE");
                playerAmount -= betAmount;
                // Player run out of money?
                if (playerAmount <= 0) {
                    gameOver = true;
                }
            }

        } while (!gameOver); // Keep playing until player runs out of cash
    }

    // Method to determine if player won (true returned) or lost (false returned)
    // to win a players card has to be in the range of the first and second dealer
    // drawn cards inclusive of first and second cards.
    private boolean playerWon() {
        // winner
        return (playersCard.getValue() >= firstCard.getValue())
                && playersCard.getValue() <= secondCard.getValue();

    }

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

    // Get the players bet, and return the amount
    // 0 is considered a valid bet, but better more than the player has available is not
    // method will loop until a valid bet is entered.
    private int getBet() {
        boolean validBet = false;
        int amount;
        do {
            System.out.print("WHAT IS YOUR BET ");
            amount = kbScanner.nextInt();
            if (amount == 0) {
                System.out.println("CHICKEN!!");
                validBet = true;
            } else if (amount > playerAmount) {
                System.out.println("SORRY, MY FRIEND, BUT YOU BET TOO MUCH.");
                System.out.println("YOU HAVE ONLY " + playerAmount + " DOLLARS TO BET.");
            } else {
                validBet = true;
            }
        } while (!validBet);

        return amount;
    }

    private void displayBalance() {
        System.out.println("YOU NOW HAVE " + playerAmount + " DOLLARS.");
    }

    private void displayCards() {
        System.out.println("HERE ARE YOUR NEXT TWO CARDS: ");
        System.out.println(firstCard.getName());
        System.out.println(secondCard.getName());
    }

    // Draw two dealer cards, and save them for later use.
    // ensure that the first card is a smaller value card than the second one
    private void drawCards() {

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

    // Creates a random card
    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("ACEY DUCEY CARD GAME");
        System.out.println("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
        System.out.println();
        System.out.println();
        System.out.println("ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER");
        System.out.println("THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP");
        System.out.println("YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING");
        System.out.println("ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE");
        System.out.println("A VALUE BETWEEN THE FIRST TWO.");
        System.out.println("IF YOU DO NOT WANT TO BET, INPUT: 0");
    }
}

Note that we have fairly complete accessibility support, so I’d be interested to hear specifically what is not working for your blind user @thresholdpeople .

Also the above code block looks fine in the printed version to me. I just pressed “print” in Chrome then “save as PDF” to generate a PDF version of this very topic:

Export topic as markdown - feature - Discourse Meta.pdf (249.9 KB)

I am not seeing a problem. Please point to specific areas in the PDF that aren’t correct if you do see a problem. Thanks!

Thanks for looking into this.

I’m using Vivaldi, but I’ve used chrome as well, various computers, not all of them with synced browser settings, but when I use print your code block gets cropped at:

     // Players drawn card
     private Card playersCard;

which is also all I’m able to see up to when viewing your post inline (I have to scroll down inside of the code frame to see more). I’d post my version, but don’t have enough posts to upload files, but you get the idea.

Your printed version certainly looks better, not sure why it’s any different tbh, but it’s not perfect either. Code lines do not wrap and are thus cropped, and all the pages have a floating blue rectangle on the bottom left which also obscures some text. Unfortunately in that state, it’s not really usable either.

Someone on the SuperCollider forum provided the solution of sticking the following CSS block into either the browser’s inspector, or when using a browser plugin (currently I have the chrome extension Stylish, and it’s auto-adding it when I’m on that forum):

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

Using this makes printing work just fine for me. And with the browser extension not needing to go in and fuss with adding it every I want to save something is the actual fix… otherwise it’s too much work.

Still I do wish there was an easier way to archive threads, or rather, I wish there was a way to not have needed those additional steps.

Especially as most of the functionality already exists: either viewing a post raw or being able to print. But yeah, it’s not possible to see the entire thread in raw, just a single post, and printing doesn’t work great.

That being said, bookmarks are an awesome forum feature and I use them all the time, but it still keeps everything contained inside of discourse.

1 Like

We could add a route that returns the entire topic as raw @falco? That might be useful, though we need to be careful of megatopics…

We certainly already have this for individual posts, e.g.

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

3 Likes

That’s certainly doable, albeit it’s kinda of a niche use case.

Format would be something like:

username | timestamp | post_number

post body

---

username | timestamp | post_number

post body

---

username | timestamp | post_number

post body

?

2 Likes

Yeah I support it though. If we have a /raw/ route for posts, why not have one for a topic?

2 Likes

Currently the route https://meta.discourse.org/raw/152185 return only the OP. Is it okay to change the behavior of that route? People will need to explicitly call https://meta.discourse.org/raw/152185/1 to get only the OP.

2 Likes

Whatever you think is best is fine with me.

2 Likes

This is live now: https://meta.discourse.org/raw/152185

Let me know if this is what you had in mind @here

6 Likes

Love it! Looks good to me! :heart_eyes:

3 Likes

This is really great. Thank you :pray:

3 Likes

Thanks so much! and more characters!

2 Likes