Экспорт темы в Markdown

Я нашел этот UI: Экспорт/импорт тем и категорий, но он не покрывает то, что я имел в виду:

  • Возможность экспортировать всю публичную тему или тему в личных сообщениях в виде одного документа Markdown, где действие экспорта доступно через интерфейс всем участникам этой темы.

И, возможно (но для меня это не обязательно), чтобы эта функция была доступна любому пользователю для публичных тем.


Я активно взаимодействую со многими форумами на платформе Discourse как публично, так и в личных сообщениях, и мне нужно архивировать обсуждения в своей персональной базе знаний на основе Markdown. Это не только очень трудоемко, но и я не могу получить исходный Markdown-код постов других людей на форумах, где я не являюсь модератором или администратором (что логично), поэтому мне приходится воссоздавать его вручную.

7 лайков

Вы уже можете получить доступ к исходному Markdown для тем:
Https://meta.discourse.org/raw/152185

2 лайка

Спасибо, это было бы здорово. Но он возвращает только первый пост в теме, а не всю цепочку сообщений.

Редактирование: Более выполнимо, если перебирать каждый пост в теме в сыром режиме, но для темы с 60 постами это всё ещё много работы. Кроме того, в ответе содержится только текст поста, без информации о том, кто и когда его опубликовал.

Вы можете использовать функцию печати на теме и сохранить вывод в PDF. Это не Markdown, но это легко!

1 лайк

Спасибо, да, я иногда использую это, но контент при этом «застревает» в фиксированном виде. Это плохо сочетается с моей базой знаний (создание перекрёстных ссылок и т. д.). Markdown настолько прост и удобен в работе, что я подбираю все свои инструменты именно под него. Это значительная экономия времени, если можно просто перемещать фрагменты Markdown по разным местам.

2 лайка

Мне задали этот вопрос вчера. Вы имеете в виду функцию печати браузера? Или в Discourse есть возможность распечатать всю тему, которую я не замечаю?

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

2 лайка

Забавно, я тоже хотел бы что-то подобное! Так что, полагаю, это ещё один голос в поддержку…

Здравствуйте,

Я только что создал(а) аккаунт здесь, чтобы присоединиться к обсуждению и сказать, что я тоже считаю такой функционал очень важным!

Функция печати (в PDF) сейчас плохо работает с темами, содержащими блоки кода, так как они не переносятся и не растягиваются, из-за чего содержимое обрезается.

По моему мнению, наличие надёжного и относительно простого способа извлечения контента из Discourse, например для целей архивирования, действительно важно.

Ещё один момент для рассмотрения: я участвую в форуме, куда перешло множество пользователей с закрытого списка рассылки. В ходе переходного обсуждения о том, сохранять ли список рассылки или полностью перейти на форум, один незрячий участник заявил, что не сможет участвовать в форуме из-за отсутствия поддержки текстовых браузеров. Я считаю, что наличие корректного «сырого» режима с указанием автора и всеми темами способствовало бы большей инклюзивности.

2 лайка

Посмотрим. Я включу сюда блок кода с довольно большим количеством кода и посмотрим, как это будет выглядеть при печати:

import java.util.Scanner;

/**
 * Игра AceyDucey
 * 
 * Основано на базовой игре AceyDucey здесь
 * https://github.com/coding-horror/basic-computer-games/blob/main/01%20Acey%20Ducey/aceyducey.bas
 * Примечание: Идея заключалась в создании версии базовой игры 1970-х годов на 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("ИЗВИНИ, ДРУГ, НО ТЫ ПРОИГРАЛ ВСЁ.");
        System.out.println();
        System.out.println();
        System.out.print("ПОПРОБОВАТЬ СНОВА (ДА ИЛИ НЕТ) ");
        String playAgain = kbScanner.next().toUpperCase();
        System.out.println();
        System.out.println();
        if (playAgain.equals("YES")) {
            return true;
        } else {
            System.out.println("ОК, НАДЕЮСЬ, ТЕБЕ БЫЛО ИНТЕРЕСНО!");
            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("ВЫ ВЫИГРАЛИ!!");
                playerAmount += betAmount;
            } else {
                System.out.println("ИЗВИНИ, ВЫ ПРОИГРАЛИ");
                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("КАКАЯ ВАША СТАВКА ");
            amount = kbScanner.nextInt();
            if (amount == 0) {
                System.out.println("ТРУС!!");
                validBet = true;
            } else if (amount > playerAmount) {
                System.out.println("ИЗВИНИ, ДРУГ, НО ТЫ СДЕЛАЛ СЛИШКОМ БОЛЬШУЮ СТАВКУ.");
                System.out.println("У ТЕБЯ ЕСТЬ ТОЛЬКО " + playerAmount + " ДОЛЛАРОВ ДЛЯ СТАВКИ.");
            } else {
                validBet = true;
            }
        } while (!validBet);

        return amount;
    }

    private void displayBalance() {
        System.out.println("У ТЕБЯ ТЕПЕРЬ " + playerAmount + " ДОЛЛАРОВ.");
    }

    private void displayCards() {
        System.out.println("ВОТ ДВЕ СЛЕДУЮЩИЕ КАРТЫ: ");
        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");
        System.out.println("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
        System.out.println();
        System.out.println();
        System.out.println("ACEY-DUCEY ИГРАЕТСЯ СЛЕДУЮЩИМ ОБРАЗОМ");
        System.out.println("ДИЛЕР (КОМПЬЮТЕР) ВЫДАЁТ ДВЕ КАРТЫ РУБАШКОЙ ВВЕРХ");
        System.out.println("У ВАС ЕСТЬ ВОЗМОЖНОСТЬ СДЕЛАТЬ СТАВКУ ИЛИ НЕ ДЕЛАТЬ ЕЁ В ЗАВИСИМОСТИ");
        System.out.println("ОТ ТОГО, СЧИТАЕТЕ ЛИ ВЫ, ЧТО КАРТА БУДЕТ ИМЕТЬ");
        System.out.println("ЗНАЧЕНИЕ МЕЖДУ ДВУМЯ ПЕРВЫМИ.");
        System.out.println("ЕСЛИ ВЫ НЕ ХОТИТЕ ДЕЛАТЬ СТАВКУ, ВВЕДИТЕ: 0");
    }
}

Обратите внимание, что у нас есть довольно полная поддержка доступности, поэтому я был бы рад услышать, что именно не работает для вашего слепого пользователя @thresholdpeople.

Кроме того, блок кода выше выглядит нормально в печатной версии для меня. Я просто нажал «Печать» в Chrome, затем «Сохранить как PDF», чтобы сгенерировать PDF-версию этой самой темы:

Экспорт темы в формате markdown - функция - Discourse Meta.pdf (249.9 KB)

Я не вижу проблемы. Если вы видите проблему, пожалуйста, укажите конкретные места в PDF, которые некорректны. Спасибо!

Спасибо, что уделили этому внимание.

Я использую Vivaldi, но также пробовал Chrome на разных компьютерах, не все из которых имели синхронизированные настройки браузера. Однако при печати мой блок кода обрезается на:

     // Players drawn card
     private Card playersCard;

что также является всем, что я вижу, просматривая ваш пост в строке (мне приходится прокручивать вниз внутри рамки кода, чтобы увидеть больше). Я бы опубликовал свою версию, но у меня недостаточно сообщений для загрузки файлов, но вы понимаете, о чём речь.

Ваша распечатанная версия, безусловно, выглядит лучше, хотя, честно говоря, не понимаю, почему она отличается, но она тоже не идеальна. Строки кода не переносятся и поэтому обрезаются, а на всех страницах в левом нижнем углу есть плавающий синий прямоугольник, который также закрывает часть текста. К сожалению, в таком состоянии это тоже не совсем удобно использовать.

Кто-то на форуме SuperCollider предложил решение: добавить следующий блок CSS либо в инспектор браузера, либо с помощью расширения браузера (сейчас у меня есть расширение Chrome Stylish, и оно автоматически добавляет его, когда я нахожусь на этом форуме):

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

Использование этого делает печать для меня полностью рабочей. А с расширением браузера, которое не требует каждый раз вручную добавлять это, когда я хочу что-то сохранить, это и есть настоящее решение… иначе это слишком много работы.

Тем не менее, я всё же хотел бы, чтобы существовал более простой способ архивирования тем, или, вернее, я хотел бы, чтобы не приходилось выполнять эти дополнительные шаги.

Особенно учитывая, что большая часть функциональности уже существует: либо просмотр поста в исходном виде, либо возможность печати. Но да, невозможно увидеть всю тему в исходном виде, только отдельный пост, а печать работает не очень хорошо.

Тем не менее, закладки — это отличная функция форума, и я использую их постоянно, но всё же они сохраняют всё внутри Discourse.

1 лайк

Мы могли бы добавить маршрут, который возвращает всю тему в виде сырых данных, @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 лайка