From a352b7551e0f15d9ccbf1540dd00b70645047dea Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 20 Dec 2024 12:43:10 +0100 Subject: [PATCH] better format for gemini articles in WebEngine version --- resources/rssguard.qrc | 1 + resources/scripts/gemini/style.css | 60 +++++++++++++++++++ src/librssguard/network-web/downloader.cpp | 12 ++-- src/librssguard/network-web/downloader.h | 2 + .../network-web/gemini/geminiparser.cpp | 37 ++++++++---- .../network-web/gemini/geminiparser.h | 3 + .../gemini/geminischemehandler.cpp | 11 +++- .../network-web/gemini/geminischemehandler.h | 2 + 8 files changed, 106 insertions(+), 22 deletions(-) create mode 100644 resources/scripts/gemini/style.css diff --git a/resources/rssguard.qrc b/resources/rssguard.qrc index d73ac7411..447a7cd7d 100644 --- a/resources/rssguard.qrc +++ b/resources/rssguard.qrc @@ -11,6 +11,7 @@ scripts/builtin_js/observer.js scripts/web_ui/rssguard.html + scripts/gemini/style.css sounds/boing.wav sounds/rooster.wav diff --git a/resources/scripts/gemini/style.css b/resources/scripts/gemini/style.css new file mode 100644 index 000000000..8060317a8 --- /dev/null +++ b/resources/scripts/gemini/style.css @@ -0,0 +1,60 @@ +p { + min-height: 0.1em; + margin: 6px 0px; +} + +h1, h2, h3, h4, h5, h6, ul, ol, pre { + margin: 9px 0px; +} + +pre { + font-family: "Consolas", "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace; + white-space: pre-wrap; + overflow-x: auto; + padding: 8px; + border-radius: 2px; +} + +a:link { + text-decoration-line: none; +} + +a:hover { + text-decoration-line: underline; +} + +blockquote { + font-size: 1.2em; + width: 80%; + margin: 14px auto; + font-family: "Open Sans"; + font-style: italic; + color: #555555; + padding: 1em 16px 1em 30px; + border-left: 4px solid #75bff7; + line-height: 1.1; + position: relative; + background: #EDEDED; +} + +blockquote::before { + font-family: Arial; + content: "\201C"; + color: #7598f7; + font-size: 3em; + position: absolute; + left: 10px; + top: 0px; +} + +blockquote::after { + content: ''; +} + +blockquote span { + display: block; + color: #333333; + font-style: normal; + font-weight: bold; + margin-top: 1em; +} \ No newline at end of file diff --git a/src/librssguard/network-web/downloader.cpp b/src/librssguard/network-web/downloader.cpp index 663a2ef06..5eccbb0c9 100644 --- a/src/librssguard/network-web/downloader.cpp +++ b/src/librssguard/network-web/downloader.cpp @@ -15,11 +15,11 @@ #include Downloader::Downloader(QObject* parent) - : QObject(parent), m_geminiClient(new GeminiClient(this)), m_activeReply(nullptr), - m_downloadManager(new SilentNetworkAccessManager(this)), m_timer(new QTimer(this)), m_inputData(QByteArray()), - m_inputMultipartData(nullptr), m_targetProtected(false), m_targetUsername(QString()), m_targetPassword(QString()), - m_lastOutputData({}), m_lastOutputError(QNetworkReply::NetworkError::NoError), m_lastHttpStatusCode(0), - m_lastHeaders({}) { + : QObject(parent), m_geminiClient(new GeminiClient(this)), m_geminiParser(GeminiParser(false)), + m_activeReply(nullptr), m_downloadManager(new SilentNetworkAccessManager(this)), m_timer(new QTimer(this)), + m_inputData(QByteArray()), m_inputMultipartData(nullptr), m_targetProtected(false), m_targetUsername(QString()), + m_targetPassword(QString()), m_lastOutputData({}), m_lastOutputError(QNetworkReply::NetworkError::NoError), + m_lastHttpStatusCode(0), m_lastHeaders({}) { m_timer->setInterval(DOWNLOAD_TIMEOUT); m_timer->setSingleShot(true); @@ -50,7 +50,7 @@ void Downloader::geminiFinished(const QByteArray& data, const QString& mime) { m_lastOutputMultipartData = {}; if (mime.startsWith(QSL(GEMINI_MIME_TYPE))) { - m_lastOutputData = GeminiParser().geminiToHtml(data).toUtf8(); + m_lastOutputData = m_geminiParser.geminiToHtml(data).toUtf8(); } else { m_lastOutputData = data; diff --git a/src/librssguard/network-web/downloader.h b/src/librssguard/network-web/downloader.h index 80629fbd4..3cae7c49b 100644 --- a/src/librssguard/network-web/downloader.h +++ b/src/librssguard/network-web/downloader.h @@ -5,6 +5,7 @@ #include "definitions/definitions.h" #include "network-web/gemini/geminiclient.h" +#include "network-web/gemini/geminiparser.h" #include "network-web/httpresponse.h" #include @@ -105,6 +106,7 @@ class Downloader : public QObject { private: GeminiClient* m_geminiClient; + GeminiParser m_geminiParser; QNetworkReply* m_activeReply; QScopedPointer m_downloadManager; QTimer* m_timer; diff --git a/src/librssguard/network-web/gemini/geminiparser.cpp b/src/librssguard/network-web/gemini/geminiparser.cpp index 1cd663922..2942dc44b 100644 --- a/src/librssguard/network-web/gemini/geminiparser.cpp +++ b/src/librssguard/network-web/gemini/geminiparser.cpp @@ -12,12 +12,14 @@ QString GeminiParser::geminiToHtml(const QByteArray& gemini_data) { QStringList lines = gemini_hypertext.split(QL1C('\n')); mode = State::Normal; - static QRegularExpression exp_link(R"(^=>\s+([^\s]+)(?:\s+(\w.+))?$)"); + static QRegularExpression exp_link(R"(^=>\s+([^\s]+)(?:\s+(\S.+))?$)"); static QRegularExpression exp_heading(R"(^(#{1,6})\s+(.+)$)"); static QRegularExpression exp_list(R"(^\*\s(.+)$)"); static QRegularExpression exp_quote(R"((?:^>$|^>\s?(.+)$))"); static QRegularExpression exp_pre(R"(^```.*$)"); + static QString rich_style = QString::fromUtf8(IOFactory::readFile(QSL(":/scripts/gemini/style.css"))); + QRegularExpressionMatch mtch; QString title; @@ -69,13 +71,17 @@ QString GeminiParser::geminiToHtml(const QByteArray& gemini_data) { html += endBlock(State::Normal); - // IOFactory::writeFile("aa", html.toUtf8()); - - return QSL("" - "%1" + return QSL("" + "" + "" + "" + "" + "%1" + "" + "" "%2" "") - .arg(title, html); + .arg(title, html, m_richHtml ? rich_style : QString()); } QString GeminiParser::beginBlock(State new_mode) { @@ -87,11 +93,12 @@ QString GeminiParser::beginBlock(State new_mode) { return "
    \n"; case State::Quote: - return "
    \n"; + return QSL("<%1 style=\"" + "background-color: #E1E5EE;" + "font-style: italic;" + "margin-left: 20px;" + "margin-right: 20px;\">\n") + .arg(m_richHtml ? QSL("blockquote") : QSL("div")); case State::Pre: return "
    \n";
    @@ -111,7 +118,7 @@ QString GeminiParser::endBlock(State new_mode) {
             break;
     
           case State::Quote:
    -        to_return = "
    \n"; + to_return = QSL("\n").arg(m_richHtml ? QSL("blockquote") : QSL("div")); break; case State::Pre: @@ -125,6 +132,8 @@ QString GeminiParser::endBlock(State new_mode) { return to_return; } +GeminiParser::GeminiParser(bool rich_html) : m_richHtml(rich_html) {} + QString GeminiParser::parseLink(const QRegularExpressionMatch& mtch) const { QString link = mtch.captured(1); QString name = mtch.captured(2); @@ -146,8 +155,10 @@ QString GeminiParser::parseHeading(const QRegularExpressionMatch& mtch, QString* QString GeminiParser::parseQuote(const QRegularExpressionMatch& mtch) const { QString text = mtch.captured(1); + QString element = m_richHtml ? QSL("p") : QSL("div"); - return QSL("
    %1
    \n").arg(text.isEmpty() ? QString() : QSL("“%1”").arg(text)); + return QSL("<%2>%1\n") + .arg(text.simplified().isEmpty() ? QString() : (m_richHtml ? text : QSL("“%1”").arg(text)), element); } QString GeminiParser::parseList(const QRegularExpressionMatch& mtch) const { diff --git a/src/librssguard/network-web/gemini/geminiparser.h b/src/librssguard/network-web/gemini/geminiparser.h index b4f146699..8b235cb9c 100644 --- a/src/librssguard/network-web/gemini/geminiparser.h +++ b/src/librssguard/network-web/gemini/geminiparser.h @@ -8,6 +8,8 @@ class GeminiParser { public: + explicit GeminiParser(bool rich_html); + QString geminiToHtml(const QByteArray& gemini_data); private: @@ -37,6 +39,7 @@ class GeminiParser { private: State mode; + bool m_richHtml; }; #endif // GEMINIPARSER_H diff --git a/src/librssguard/network-web/gemini/geminischemehandler.cpp b/src/librssguard/network-web/gemini/geminischemehandler.cpp index 84e90fd8b..0000e7920 100644 --- a/src/librssguard/network-web/gemini/geminischemehandler.cpp +++ b/src/librssguard/network-web/gemini/geminischemehandler.cpp @@ -8,7 +8,8 @@ #include -GeminiSchemeHandler::GeminiSchemeHandler(QObject* parent) : QWebEngineUrlSchemeHandler(parent) {} +GeminiSchemeHandler::GeminiSchemeHandler(QObject* parent) + : QWebEngineUrlSchemeHandler(parent), m_geminiParser(GeminiParser(true)) {} void GeminiSchemeHandler::requestStarted(QWebEngineUrlRequestJob* request) { GeminiClient* gemini_client = new GeminiClient(this); @@ -45,9 +46,13 @@ void GeminiSchemeHandler::onCompleted(const QByteArray& data, const QString& mim buf->open(QBuffer::ReadWrite); if (mime.startsWith(QSL(GEMINI_MIME_TYPE))) { - // IOFactory::writeFile("a", data); + QString htmlized_gemini = m_geminiParser.geminiToHtml(data); + buf->write(htmlized_gemini.toUtf8()); + +#if !defined(NDEBUG) + IOFactory::writeFile("aa.html", htmlized_gemini.toUtf8()); +#endif - buf->write(GeminiParser().geminiToHtml(data).toUtf8()); target_mime = QSL("text/html"); } else { diff --git a/src/librssguard/network-web/gemini/geminischemehandler.h b/src/librssguard/network-web/gemini/geminischemehandler.h index 3ffa9aabd..e9971a250 100644 --- a/src/librssguard/network-web/gemini/geminischemehandler.h +++ b/src/librssguard/network-web/gemini/geminischemehandler.h @@ -4,6 +4,7 @@ #define GEMINISCHEMEHANDLER_H #include "network-web/gemini/geminiclient.h" +#include "network-web/gemini/geminiparser.h" #include #include @@ -23,6 +24,7 @@ class GeminiSchemeHandler : public QWebEngineUrlSchemeHandler { private: QHash m_jobs; + GeminiParser m_geminiParser; }; #endif // GEMINISCHEMEHANDLER_H