토픽을 마크다운으로 내보내기

이 UI: Topic and Category Export/Import를 찾았지만, 제가 생각했던 내용은 포함되지 않았습니다:

  • 특정 토픽의 모든 참여자가 UI에서 접근할 수 있는 내보내기 작업을 통해, 공개 또는 DM 토픽 전체를 단일 마크다운 문서로 내보내는 방법.

그리고 아마도(제 경우엔 필수 사항은 아니지만) 공개 토픽의 모든 사용자에게도 이 기능을 사용할 수 있게 하는 것.


저는 공개적으로 그리고 DM을 통해 수많은 Discourse 포럼에서 활동하고 있으며, 그곳의 토론을 개인적인 마크다운 기반 지식 베이스에 아카이브할 필요가 있습니다. 이 작업은 매우 시간이 많이 소요될 뿐만 아니라, 제가 모더레이터나 관리자가 아닌 포럼에서는 다른 사람들의 게시글 원본 마크다운을 가져올 수 없기 때문에(당연히) 수동으로 재현해야 합니다.

7개의 좋아요

토픽의 원시 마크다운에 이미 접근할 수 있습니다:
Https://meta.discourse.org/raw/152185

3개의 좋아요

감사합니다. 정말 멋질 것 같습니다. 하지만 현재는 해당 토픽의 첫 번째 게시글만 반환되고, 전체 대화 스레드는 반환되지 않습니다.

수정: 원시(raw) 모드에서 스레드의 각 게시글을 반복 처리하는 방식도 가능하지만, 60개의 게시글이 있는 스레드의 경우 여전히 많은 작업이 필요합니다. 또한 게시글 본문만 포함되어 있으며, 누가 언제 게시했는지에 대한 정보는 없습니다.

토픽에 대해 print 기능을 사용해 출력을 PDF로 저장할 수 있습니다. 마크다운은 아니지만 사용법이 매우 쉽습니다!

1개의 좋아요

네, 감사합니다. 가끔은 그렇게 사용하지만, 그렇게 하면 콘텐츠가 '고정’되는 느낌이 듭니다. 제 지식 베이스(크로스링크 생성 등)와 잘 맞지 않아요. 마크다운은 정말 단순하고 다루기 쉬워서, 모든 도구를 마크다운 중심으로 선택합니다. MD 스니펫을 여기저기 자유롭게 이동할 수 있으면 정말 시간을 절약할 수 있거든요.

2개의 좋아요

어제 바로 그 질문을 받았어요. 브라우저의 인쇄 기능을 말씀하시는 건가요? 아니면 제가 못 보고 있는, 전체 주제 스레드를 인쇄할 수 있는 Discourse 기능이 따로 있나요?

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

2개의 좋아요

재미있게도 저도 이런 기능이 있었으면 좋겠습니다! 그래서 또 한 표를 던지는 셈이네요…

안녕하세요,

여기에 계정을 만들고 이 기능의 중요성에 대해 한마디 덧붙이고 싶었습니다. 저도 이 유형의 기능이 매우 중요하다고 생각합니다!

현재 PDF로 인쇄하는 기능이 코드 블록이 포함된 스레드와 잘 작동하지 않습니다. 코드 블록이 줄바꿈되거나 확장되지 않아 내용이 잘려 나가는 문제가 발생합니다.

예를 들어 아카이빙 목적으로 Discourse에서 콘텐츠를 안정적이고 비교적 쉽게 가져오는 방법은 정말 중요하다고 생각합니다.

또 하나의 고려 사항: 저는 최근 폐쇄된 메일링 리스트에서 많은 사용자가 통합된 포럼에 참여하고 있습니다. 메일링 리스트를 유지할지, 아니면 포럼으로 완전히 전환할지에 대한 논의가 이루어졌을 때, 시각 장애가 있는 한 회원은 텍스트 기반 브라우저에 대한 지원이 부족하여 포럼에 참여할 수 없다고 말했습니다. 저자 정보와 모든 스레드가 포함된 적절한 원본(raw) 모드는 포용성을 높이는 데 도움이 될 것이라고 생각합니다.

2개의 좋아요

한번 살펴볼게요. 여기 코드 블록을 하나 포함해서, 인쇄본에서 어떻게 보이는지 확인해 보겠습니다:

import java.util.Scanner;

/**
 * AceyDucey 게임
 * <p>
 * 여기 있는 AceyDucey Basic 게임에 기반함
 * https://github.com/coding-horror/basic-computer-games/blob/main/01%20Acey%20Ducey/aceyducey.bas
 * 참고: 1970년대 Basic 게임을 Java 버전으로 만드는 것이 목표였으며, 새로운 기능을 도입하지 않았습니다 - 추가 텍스트, 오류 검사 등은 추가하지 않았습니다.
 */
public class AceyDucey {

    // 현재 플레이어의 현금
    private int playerAmount;

    // 딜러가 뽑은 첫 번째 카드
    private Card firstCard;

    // 딜러가 뽑은 두 번째 카드
    private Card secondCard;

    // 플레이어가 뽑은 카드
    private Card playersCard;

    // 게임 소개/방법을 표시할 사용자를 위한 플래그
    private boolean firstTimePlaying = true;

    // 게임 종료 여부를 결정하기 위한 게임 상태
    private boolean gameOver = false;

    // 키보드 입력에 사용
    private final Scanner kbScanner;

    // 덱의 카드에 대한 상수 값 - 2가 가장 낮고, 14(에이스)가 가장 높음
    public static final int LOW_CARD_RANGE = 2;
    public static final int HIGH_CARD_RANGE = 14;

    public AceyDucey() {
        // 플레이어 현금 초기화
        playerAmount = 100;

        // 키보드 스캐너 초기화
        kbScanner = new Scanner(System.in);
    }

    // 다시 플레이하는 메서드 - 게임을 호출하는 클래스에서 호출되는 공개 메서드
    // 플레이어가 YES를 입력하면 게임을 다시 플레이할 수 있음 (true 반환)
    // 그렇지 않으면 안 됨 (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;
        }
    }

    // 게임 루프 메서드

    public void play() {

        // 플레이어가 현금을 다 쓸 때까지 계속 핸드를 플레이
        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;
                // 플레이어의 돈이 떨어졌나요?
                if (playerAmount <= 0) {
                    gameOver = true;
                }
            }

        } while (!gameOver); // 플레이어가 현금을 다 쓸 때까지 계속 플레이
    }

    // 플레이어가 이겼는지(true 반환) 졌는지(false 반환)를 결정하는 메서드
    // 이기기 위해서는 플레이어의 카드가 딜러가 뽑은 첫 번째와 두 번째 카드의 범위 안에 있어야 하며,
    // 첫 번째와 두 번째 카드를 포함합니다.
    private boolean playerWon() {
        // 승자
        return (playersCard.getValue() >= firstCard.getValue())
                && playersCard.getValue() <= secondCard.getValue();

    }

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

    // 플레이어의 베팅 금액을 가져와서 반환
    // 0은 유효한 베팅으로 간주하지만, 플레이어가 가진 금액보다 더 많은 금액은 유효하지 않음
    // 유효한 베팅이 입력될 때까지 메서드가 루프를 돌림.
    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());
    }

    // 딜러 카드 두 장을 뽑고 나중에 사용하기 위해 저장.
    // 첫 번째 카드가 두 번째 카드보다 값이 작도록 보장
    private void drawCards() {

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

    // 랜덤 카드를 생성
    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");
    }
}

상당한 수준의 접근성 지원을 갖추고 있으므로, @thresholdpeople 님의 시각 장애 사용자가 구체적으로 어떤 부분이 작동하지 않는지 듣고 싶습니다.

또한, 위 코드 블록은 인쇄본에서 저에게는 정상적으로 보입니다. Chrome에서 "인쇄"를 누른 다음 "PDF로 저장"을 눌러 이 주제 자체의 PDF 버전을 생성해 보았습니다:

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

문제를 발견하지 못했습니다. 만약 문제를 보신다면, PDF에서 정확히 어떤 부분이 올바르지 않은지 지적해 주십시오. 감사합니다!

확인해 주셔서 감사합니다.

저는 Vivaldi 브라우저를 사용 중이지만, Chrome도 사용해 봤고, 여러 컴퓨터를 사용했는데, 모두 브라우저 설정이 동기화되어 있지는 않습니다. 하지만 인쇄를 시도하면 코드 블록이 다음 위치에서 잘립니다:

     // Players drawn card
     private Card playersCard;

인라인으로 게시물을 볼 때도 이 부분까지밖에 보이지 않습니다(코드 프레임 안을 아래로 스크롤해야 더 많은 내용을 볼 수 있습니다). 제 버전을 올리고 싶지만, 파일 업로드를 위한 게시 글 수가 부족해서 올리지는 못하겠습니다. 하지만 의도는 이해하실 거라고 생각합니다.

인쇄된 버전은 확실히 더 잘 보이는데, 왜 차이가 나는지는 솔직히 잘 모르겠습니다. 하지만 이것도 완벽하지는 않습니다. 코드 줄이 줄바꿈되지 않아서 잘리는 문제가 있고, 모든 페이지의 왼쪽 아래에 떠 있는 파란색 사각형이 일부 텍스트를 가립니다. 이런 상태에서는 사실상 사용할 수 없습니다.

SuperCollider 포럼에서 누군가가 브라우저 검사도구(inspector)에 다음 CSS 블록을 붙여넣거나, 브라우저 플러그인을 사용하는 경우(현재 저는 Chrome 확장 프로그램인 Stylish를 사용 중이며, 해당 포럼에 있을 때 자동으로 추가해 줍니다) 적용하라는 해결책을 제시했습니다:

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

이것을 사용하면 인쇄가 제게는 정상적으로 작동합니다. 그리고 브라우저 확장 프로그램을 사용하면 매번 저장할 때마다 직접 들어가서 추가할 필요가 없는데, 이것이 진정한 해결책입니다… 그렇지 않으면 너무 번거롭습니다.

그래도 스레드를 아카이브하는 더 쉬운 방법이 있었으면 좋겠습니다. 혹은, 그런 추가 단계가 필요하지 않은 방법이 있었으면 좋겠습니다.

특히 대부분의 기능이 이미 존재하기 때문입니다: 게시물을 원본(raw)으로 보거나, 인쇄할 수 있는 기능이 있죠. 하지만 그렇다고 해도, 원본으로 볼 때는 전체 스레드가 아니라 단일 게시물만 볼 수 있고, 인쇄 기능도 완벽하지 않습니다.

그럼에도 불구하고, 북마크는 훌륭한 포럼 기능이며 저는 항상 사용하고 있습니다. 하지만 여전히 모든 것이 discourse 내부에 갇혀 있는 상태입니다.

1개의 좋아요

전체 토픽을 원본(raw)으로 반환하는 라우트를 추가할 수 있을까요? @falco, 메가토픽에 주의해야 하지만 유용할 것 같습니다.

개별 게시물의 경우 이미 이러한 기능이 있습니다. 예를 들어:

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

3개의 좋아요

그건 물론 가능하지만, 다소 니치한 사용 사례긴 합니다.

형식은 다음과 같은 식이 될 것 같습니다:

username | timestamp | post_number

post body

---

username | timestamp | post_number

post body

---

username | timestamp | post_number

post body

?

2개의 좋아요

그래도 나는 찬성해. 게시글에 /raw/ 라우트가 있는 주제, 왜 토론 주제에도 하나 없을까?

2개의 좋아요

현재 라우트 https://meta.discourse.org/raw/152185 는 첫 번째 게시글(OP)만 반환합니다. 해당 라우트의 동작 방식을 변경해도 괜찮을까요? 이제 첫 번째 게시글만 가져오려면 https://meta.discourse.org/raw/152185/1 을 명시적으로 호출해야 합니다.

2개의 좋아요

당신이 가장 좋다고 생각하는 대로 하면 됩니다.

2개의 좋아요

지금 라이브로 공개되었습니다: https://meta.discourse.org/raw/152185

@here, 이게 원하시는 내용인지 알려주세요.

8개의 좋아요

좋아요! 나쁘지 않네요! :heart_eyes:

3개의 좋아요

정말 최고네요. 감사합니다 :pray:

3개의 좋아요

정말 감사합니다! 그리고 캐릭터도 더 많았어요!

2개의 좋아요