diff --git a/resources/desktop/com.github.rssguard.appdata.xml b/resources/desktop/com.github.rssguard.appdata.xml index c267a5089..fcee471f6 100644 --- a/resources/desktop/com.github.rssguard.appdata.xml +++ b/resources/desktop/com.github.rssguard.appdata.xml @@ -30,7 +30,7 @@ https://martinrotter.github.io/donate/ - + none diff --git a/src/librssguard/network-web/networkfactory.cpp b/src/librssguard/network-web/networkfactory.cpp index 906ea842e..ab49c3f65 100644 --- a/src/librssguard/network-web/networkfactory.cpp +++ b/src/librssguard/network-web/networkfactory.cpp @@ -137,66 +137,71 @@ QString NetworkFactory::networkErrorText(QNetworkReply::NetworkError error_code) } } -QNetworkReply::NetworkError NetworkFactory::downloadIcon(const QList& urls, int timeout, +QNetworkReply::NetworkError NetworkFactory::downloadIcon(const QList>& urls, int timeout, QIcon& output, const QNetworkProxy& custom_proxy) { QNetworkReply::NetworkError network_result = QNetworkReply::NetworkError::UnknownNetworkError; - for (const QString& url : urls) { - if (url.isEmpty()) { + for (const auto& url : urls) { + if (url.first.isEmpty()) { continue; } QByteArray icon_data; - network_result = performNetworkOperation(url, - timeout, - {}, - icon_data, - QNetworkAccessManager::Operation::GetOperation, - {}, - false, - {}, - {}, - custom_proxy).first; + if (url.second) { + // Download directly. + network_result = performNetworkOperation(url.first, + timeout, + {}, + icon_data, + QNetworkAccessManager::Operation::GetOperation, + {}, + false, + {}, + {}, + custom_proxy).first; - if (network_result == QNetworkReply::NetworkError::NoError) { - QPixmap icon_pixmap; + if (network_result == QNetworkReply::NetworkError::NoError) { + QPixmap icon_pixmap; - icon_pixmap.loadFromData(icon_data); - output = QIcon(icon_pixmap); + icon_pixmap.loadFromData(icon_data); + output = QIcon(icon_pixmap); - if (!output.isNull()) { - break; + if (!output.isNull()) { + break; + } } } + else { + // Use favicon fetching service. + QString host = QUrl(url.first).host(); - QString host = QUrl(url).host(); + if (host.startsWith(QSL("www."))) { + host = host.mid(4); + } - if (host.startsWith(QSL("www."))) { - host = host.mid(4); - } + const QString ddg_icon_service = QString("https://external-content.duckduckgo.com/ip3/%1.ico").arg(host); - const QString ddg_icon_service = QString("https://external-content.duckduckgo.com/ip3/%1.ico").arg(host); + network_result = performNetworkOperation(ddg_icon_service, + timeout, + QByteArray(), + icon_data, + QNetworkAccessManager::Operation::GetOperation, + {}, + false, + {}, + {}, + custom_proxy).first; - network_result = performNetworkOperation(ddg_icon_service, - timeout, - QByteArray(), - icon_data, - QNetworkAccessManager::Operation::GetOperation, - {}, - false, - {}, - {}, - custom_proxy).first; + if (network_result == QNetworkReply::NetworkError::NoError) { + QPixmap icon_pixmap; - if (network_result == QNetworkReply::NetworkError::NoError) { - QPixmap icon_pixmap; + icon_pixmap.loadFromData(icon_data); + output = QIcon(icon_pixmap); - icon_pixmap.loadFromData(icon_data); - output = QIcon(icon_pixmap); - - if (!output.isNull()) { - break; + if (!output.isNull()) { + break; + } } } } diff --git a/src/librssguard/network-web/networkfactory.h b/src/librssguard/network-web/networkfactory.h index 3de6cfd2b..c2496e7d6 100644 --- a/src/librssguard/network-web/networkfactory.h +++ b/src/librssguard/network-web/networkfactory.h @@ -31,7 +31,7 @@ class NetworkFactory { // Performs SYNCHRONOUS download if favicon for the site, // given URL belongs to. - static QNetworkReply::NetworkError downloadIcon(const QList& urls, + static QNetworkReply::NetworkError downloadIcon(const QList>& urls, int timeout, QIcon& output, const QNetworkProxy& custom_proxy = QNetworkProxy::ProxyType::DefaultProxy); diff --git a/src/librssguard/services/feedly/definitions.h b/src/librssguard/services/feedly/definitions.h index 5cc6c2c23..4d8fa03b9 100755 --- a/src/librssguard/services/feedly/definitions.h +++ b/src/librssguard/services/feedly/definitions.h @@ -9,7 +9,7 @@ #define FEEDLY_GENERATE_DAT "https://feedly.com/v3/auth/dev" -#define FEEDLY_API_REDIRECT_URI_PORT 8080 +#define FEEDLY_API_REDIRECT_URI_PORT 14466 #define FEEDLY_API_SCOPE "https://cloud.feedly.com/subscriptions" //#define FEEDLY_API_URL_BASE "https://sandbox7.feedly.com/v3/" diff --git a/src/librssguard/services/feedly/feedlynetwork.cpp b/src/librssguard/services/feedly/feedlynetwork.cpp index 4d632649b..4bf1dab59 100755 --- a/src/librssguard/services/feedly/feedlynetwork.cpp +++ b/src/librssguard/services/feedly/feedlynetwork.cpp @@ -359,9 +359,9 @@ RootItem* FeedlyNetwork::decodeCollections(const QByteArray& json, bool obtain_i if (obtain_icons) { QIcon icon; - auto result = NetworkFactory::downloadIcon({ fee_obj["iconUrl"].toString(), - fee_obj["logo"].toString(), - fee_obj["website"].toString() }, + auto result = NetworkFactory::downloadIcon({ { fee_obj["iconUrl"].toString(), true }, + { fee_obj["website"].toString(), false }, + { fee_obj["logo"].toString(), true } }, timeout, icon, proxy); diff --git a/src/librssguard/services/greader/greadernetwork.cpp b/src/librssguard/services/greader/greadernetwork.cpp index 845ca86ef..4f619108e 100755 --- a/src/librssguard/services/greader/greadernetwork.cpp +++ b/src/librssguard/services/greader/greadernetwork.cpp @@ -308,7 +308,7 @@ RootItem* GreaderNetwork::decodeTagsSubscriptions(const QString& categories, con QIcon icon; - if (NetworkFactory::downloadIcon({ icon_url }, + if (NetworkFactory::downloadIcon({ { icon_url, true } }, timeout, icon, proxy) == QNetworkReply::NetworkError::NoError) { diff --git a/src/librssguard/services/standard/standardfeed.cpp b/src/librssguard/services/standard/standardfeed.cpp index d35280dad..91b5be69b 100644 --- a/src/librssguard/services/standard/standardfeed.cpp +++ b/src/librssguard/services/standard/standardfeed.cpp @@ -194,7 +194,6 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type, auto timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(); QByteArray feed_contents; - QList icon_possible_locations; QString content_type; if (source_type == StandardFeed::SourceType::Url) { @@ -216,8 +215,6 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type, *result = false; return nullptr; } - - icon_possible_locations.append(source); } else { qDebugNN << LOGSEC_CORE @@ -261,6 +258,15 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type, StandardFeed* feed = nullptr; + // Now we need to obtain list of URLs of icons. + // Priority of links: + // 1. Links of "homepage" obtained from feed files which will be processed via DuckDuckGo. + // 2. Direct links of "favicon", "icon", "logo" obtained from feed files which will be downloaded directly. + // 3. Link of the feed file itself which will be processed via DuckDuckGo. + // The "bool" if true means that the URL is direct and download directly, if false then + // only use its domain and download via DuckDuckGo. + QList> icon_possible_locations; + if (content_type.contains(QSL("json"), Qt::CaseSensitivity::CaseInsensitive) || feed_contents.startsWith('{')) { feed = new StandardFeed(); @@ -274,14 +280,21 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type, feed->setTitle(json.object()["title"].toString()); feed->setDescription(json.object()["description"].toString()); - auto icon = json.object()["icon"].toString(); + auto home_page = json.object()["home_page_url"].toString(); + + if (!home_page.isEmpty()) { + icon_possible_locations.prepend({ home_page, false }); + } + + auto icon = json.object()["favicon"].toString(); if (icon.isEmpty()) { - icon = json.object()["favicon"].toString(); + icon = json.object()["icon"].toString(); } if (!icon.isEmpty()) { - icon_possible_locations.prepend(icon); + // Low priority, download directly. + icon_possible_locations.append({ icon, true }); } } else { @@ -347,10 +360,10 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type, feed->setTitle(channel_element.namedItem(QSL("title")).toElement().text()); feed->setDescription(channel_element.namedItem(QSL("description")).toElement().text()); - QString source_link = channel_element.namedItem(QSL("link")).toElement().text(); + QString home_page = channel_element.namedItem(QSL("link")).toElement().text(); - if (!source_link.isEmpty()) { - icon_possible_locations.prepend(source_link); + if (!home_page.isEmpty()) { + icon_possible_locations.prepend({ home_page, false }); } } else if (root_tag_name == QL1S("rss")) { @@ -370,19 +383,19 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type, feed->setDescription(channel_element.namedItem(QSL("description")).toElement().text()); QString icon_link = channel_element.namedItem(QSL("image")).toElement().text(); - QString icon_url_link = channel_element.namedItem(QSL("image")).namedItem(QSL("url")).toElement().text(); + QString icon_url_link = channel_element.namedItem(QSL("image")).toElement().attribute(QSL("url")); if (!icon_url_link.isEmpty()) { - icon_possible_locations.prepend(icon_url_link); + icon_possible_locations.append({ icon_url_link, true }); } else if (!icon_link.isEmpty()) { - icon_possible_locations.prepend(icon_link); + icon_possible_locations.append({ icon_link, true }); } - QString source_link = channel_element.namedItem(QSL("link")).toElement().text(); + QString home_page = channel_element.namedItem(QSL("link")).toElement().text(); - if (!source_link.isEmpty()) { - icon_possible_locations.append(source_link); + if (!home_page.isEmpty()) { + icon_possible_locations.prepend({ home_page, false }); } } else if (root_tag_name == QL1S("feed")) { @@ -394,19 +407,13 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type, QString icon_link = root_element.namedItem(QSL("icon")).toElement().text(); if (!icon_link.isEmpty()) { - icon_possible_locations.prepend(icon_link); + icon_possible_locations.append({ icon_link, true }); } - QString logo_link = root_element.namedItem(QSL("logo")).toElement().text(); + QString home_page = root_element.namedItem(QSL("link")).toElement().attribute(QSL("href")); - if (!logo_link.isEmpty()) { - icon_possible_locations.prepend(logo_link); - } - - QString source_link = root_element.namedItem(QSL("link")).toElement().text(); - - if (!source_link.isEmpty()) { - icon_possible_locations.prepend(source_link); + if (!home_page.isEmpty()) { + icon_possible_locations.prepend({ home_page, false }); } } else {