From 0d4b7e658376cc653afc05ec6d1fa46f3c8619ce Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 3 Jul 2024 10:24:00 +0200 Subject: [PATCH] fix some problems, also rssguard now automatically detects youtube atom feeds from youtube video URLs more properly --- .../src/parsers/atomparser.cpp | 47 +++++++++++++++++-- .../network-web/oauthhttphandler.cpp | 14 +++--- .../services/abstract/rootitem.cpp | 7 ++- 3 files changed, 55 insertions(+), 13 deletions(-) diff --git a/src/librssguard-standard/src/parsers/atomparser.cpp b/src/librssguard-standard/src/parsers/atomparser.cpp index 99c5e8a01..3397f7756 100644 --- a/src/librssguard-standard/src/parsers/atomparser.cpp +++ b/src/librssguard-standard/src/parsers/atomparser.cpp @@ -44,6 +44,7 @@ QList AtomParser::discoverFeeds(ServiceRoot* root, const QUrl& ur // https://github.com/:owner/:repo/releases.atom // https://github.com/:owner/:repo/commits.atom // https://github.com/:user/:repo/tags.atom + // 6. If URL if Youtube, find channel ID. // Download URL. int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); @@ -58,6 +59,7 @@ QList AtomParser::discoverFeeds(ServiceRoot* root, const QUrl& ur {}, {}, root->networkProxy()); + QString direct_html_data = QString::fromUtf8(data); if (res.m_networkError == QNetworkReply::NetworkError::NoError) { try { @@ -77,9 +79,10 @@ QList AtomParser::discoverFeeds(ServiceRoot* root, const QUrl& ur static QRegularExpression rx_href(QSL(ATOM_HREF_REGEX_MATCHER), QRegularExpression::PatternOption::CaseInsensitiveOption); + rx.optimize(); rx_href.optimize(); - QRegularExpressionMatchIterator it_rx = rx.globalMatch(QString::fromUtf8(data)); + QRegularExpressionMatchIterator it_rx = rx.globalMatch(direct_html_data); while (it_rx.hasNext()) { QRegularExpressionMatch mat_tx = it_rx.next(); @@ -175,12 +178,12 @@ QList AtomParser::discoverFeeds(ServiceRoot* root, const QUrl& ur // 5. my_url = url.toString(QUrl::UrlFormattingOption::StripTrailingSlash); - auto mtch = QRegularExpression(QSL(GITHUB_URL_REGEX)).match(my_url); + auto mtch_github = QRegularExpression(QSL(GITHUB_URL_REGEX)).match(my_url); - if (mtch.isValid() && mtch.hasMatch()) { + if (mtch_github.isValid() && mtch_github.hasMatch()) { QStringList github_feeds = {QSL("releases.atom"), QSL("commits.atom"), QSL("tags.atom")}; - QString gh_username = mtch.captured(1); - QString gh_repo = mtch.captured(2); + QString gh_username = mtch_github.captured(1); + QString gh_repo = mtch_github.captured(2); for (const QString& github_feed : github_feeds) { my_url = QSL("https://github.com/%1/%2/%3").arg(gh_username, gh_repo, github_feed); @@ -209,6 +212,40 @@ QList AtomParser::discoverFeeds(ServiceRoot* root, const QUrl& ur } } + // 6. + my_url = url.toString(QUrl::UrlFormattingOption::StripTrailingSlash); + + if (!direct_html_data.isEmpty() && my_url.contains(QSL("youtube"))) { + QString youtube_channel_id = + QRegularExpression(QSL("\"externalChannelId\": ?\"([^\"]+)\"")).match(direct_html_data).captured(1); + + if (!youtube_channel_id.isEmpty()) { + my_url = QSL("https://www.youtube.com/feeds/videos.xml?channel_id=%1").arg(youtube_channel_id); + res = NetworkFactory::performNetworkOperation(my_url, + timeout, + {}, + data, + QNetworkAccessManager::Operation::GetOperation, + {}, + {}, + {}, + {}, + root->networkProxy()); + + if (res.m_networkError == QNetworkReply::NetworkError::NoError) { + try { + auto guessed_feed = guessFeed(data, res.m_contentType); + + guessed_feed.first->setSource(my_url); + feeds.append(guessed_feed.first); + } + catch (...) { + qDebugNN << LOGSEC_CORE << QUOTE_W_SPACE(my_url) << "is not a direct feed file."; + } + } + } + } + return feeds; } diff --git a/src/librssguard/network-web/oauthhttphandler.cpp b/src/librssguard/network-web/oauthhttphandler.cpp index ab9d964b3..c19aa6d57 100644 --- a/src/librssguard/network-web/oauthhttphandler.cpp +++ b/src/librssguard/network-web/oauthhttphandler.cpp @@ -62,13 +62,13 @@ void OAuthHttpHandler::answerClient(QTcpSocket* socket, const HttpRequest& reque const QString html = QSL("") + qApp->applicationName() + QSL("") + m_successText + QSL(""); const QByteArray html_utf = html.toUtf8(); - const QByteArray reply_message = QSL("HTTP/1.0 200 OK \r\n" - "Content-Type: text/html; charset=\"utf-8\"\r\n" - "Content-Length: %1" - "\r\n\r\n" - "%2") - .arg(QString::number(html_utf.size()), html_utf) - .toLocal8Bit(); + const QByteArray reply_message = QSL("HTTP/1.1 200 OK \r\n" + "Content-Type: text/html; charset=utf-8\r\n" + "Content-Length: %1\r\n" + "\r\n") + .arg(QString::number(html_utf.size())) + .toLocal8Bit() + .append(html_utf); socket->write(reply_message); } diff --git a/src/librssguard/services/abstract/rootitem.cpp b/src/librssguard/services/abstract/rootitem.cpp index 1528c945e..310fd9b10 100644 --- a/src/librssguard/services/abstract/rootitem.cpp +++ b/src/librssguard/services/abstract/rootitem.cpp @@ -207,7 +207,12 @@ QVariant RootItem::data(int column, int role) const { } Qt::ItemFlags RootItem::additionalFlags() const { - return Qt::ItemFlag::NoItemFlags; + if (m_kind == RootItem::Kind::Root) { + return Qt::ItemFlag::ItemIsDropEnabled; + } + else { + return Qt::ItemFlag::NoItemFlags; + } } bool RootItem::performDragDropChange(RootItem* target_item) {