freshrss experimental working

This commit is contained in:
Martin Rotter 2021-01-29 13:05:41 +01:00
parent 8cc268ca9a
commit 6dc5e016f1
5 changed files with 164 additions and 33 deletions

View file

@ -8,11 +8,19 @@
#define GREADER_API_STATE_READ "state/com.google/read"
#define GREADER_API_STATE_IMPORTANT "state/com.google/starred"
#define GREADER_API_FULL_STATE_READING_LIST "user/-/state/com.google/reading-list"
#define GREADER_API_FULL_STATE_READ "user/-/state/com.google/read"
#define GREADER_API_FULL_STATE_IMPORTANT "user/-/state/com.google/starred"
// API.
#define GREADER_API_CLIENT_LOGIN "accounts/ClientLogin?Email=%1&Passwd=%2"
#define GREADER_API_TAG_LIST "reader/api/0/tag/list?output=json"
#define GREADER_API_SUBSCRIPTION_LIST "reader/api/0/subscription/list?output=json"
#define GREADER_API_STREAM_CONTENTS "reader/api/0/stream/contents/%1?output=json&n=%2"
#define GREADER_API_EDIT_TAG "reader/api/0/edit-tag"
// Misc.
#define GREADER_API_EDIT_TAG_BATCH 200
// FreshRSS.
#define FRESHRSS_BASE_URL_PATH "api/greader.php/"

View file

@ -22,6 +22,84 @@ GreaderNetwork::GreaderNetwork(QObject* parent)
clearCredentials();
}
QNetworkReply::NetworkError GreaderNetwork::editLabels(const QString& state,
bool assign,
const QStringList& msg_custom_ids,
const QNetworkProxy& proxy) {
QString full_url = generateFullUrl(Operations::EditTag);
int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
QNetworkReply::NetworkError network_err;
if (!ensureLogin(proxy, &network_err)) {
return network_err;
}
QStringList trimmed_ids;
QRegularExpression regex_short_id(QSL("[0-9a-zA-Z]+$"));
for (const QString& id : msg_custom_ids) {
trimmed_ids.append(QString("i=") + id);
}
QStringList working_subset; working_subset.reserve(std::min(GREADER_API_EDIT_TAG_BATCH, trimmed_ids.size()));
// Now, we perform messages update in batches (max X messages per batch).
while (!trimmed_ids.isEmpty()) {
// We take X IDs.
for (int i = 0; i < GREADER_API_EDIT_TAG_BATCH && !trimmed_ids.isEmpty(); i++) {
working_subset.append(trimmed_ids.takeFirst());
}
QString args;
if (assign) {
args = QString("a=") + state + "&";
}
else {
args = QString("r=") + state + "&";
}
args += working_subset.join(QL1C('&'));
// We send this batch.
QByteArray output;
auto result_edit = NetworkFactory::performNetworkOperation(full_url,
timeout,
args.toUtf8(),
output,
QNetworkAccessManager::Operation::PostOperation,
{ authHeader(),
{ QSL("Content-Type").toLocal8Bit(),
QSL("application/x-www-form-urlencoded").toLocal8Bit() } },
false,
{},
{},
proxy);
if (result_edit.first != QNetworkReply::NetworkError::NoError) {
return result_edit.first;
}
// Cleanup for next batch.
working_subset.clear();
}
return QNetworkReply::NetworkError::NoError;
}
QNetworkReply::NetworkError GreaderNetwork::markMessagesRead(RootItem::ReadStatus status,
const QStringList& msg_custom_ids,
const QNetworkProxy& proxy) {
return editLabels(GREADER_API_FULL_STATE_READ, status == RootItem::ReadStatus::Read, msg_custom_ids, proxy);
}
QNetworkReply::NetworkError GreaderNetwork::markMessagesStarred(RootItem::Importance importance,
const QStringList& msg_custom_ids,
const QNetworkProxy& proxy) {
return editLabels(GREADER_API_FULL_STATE_IMPORTANT, importance == RootItem::Importance::Important, msg_custom_ids, proxy);
}
QList<Message> GreaderNetwork::streamContents(ServiceRoot* root, const QString& stream_id,
Feed::Status& error, const QNetworkProxy& proxy) {
QString full_url = generateFullUrl(Operations::StreamContents).arg(stream_id,
@ -307,10 +385,14 @@ QPair<QByteArray, QByteArray> GreaderNetwork::authHeader() const {
return { QSL("Authorization").toLocal8Bit(), QSL("GoogleLogin auth=%1").arg(m_authAuth).toLocal8Bit() };
}
bool GreaderNetwork::ensureLogin(const QNetworkProxy& proxy) {
bool GreaderNetwork::ensureLogin(const QNetworkProxy& proxy, QNetworkReply::NetworkError* output) {
if (m_authSid.isEmpty()) {
auto login = clientLogin(proxy);
if (output != nullptr) {
*output = login;
}
if (login != QNetworkReply::NetworkError::NoError) {
qCriticalNN << LOGSEC_GREADER
<< "Login failed with error:"
@ -440,5 +522,8 @@ QString GreaderNetwork::generateFullUrl(GreaderNetwork::Operations operation) co
case Operations::StreamContents:
return sanitizedBaseUrl() + GREADER_API_STREAM_CONTENTS;
case Operations::EditTag:
return sanitizedBaseUrl() + GREADER_API_EDIT_TAG;
}
}

View file

@ -17,11 +17,23 @@ class GreaderNetwork : public QObject {
ClientLogin,
TagList,
SubscriptionList,
StreamContents
StreamContents,
EditTag
};
explicit GreaderNetwork(QObject* parent = nullptr);
QNetworkReply::NetworkError markMessagesRead(RootItem::ReadStatus status,
const QStringList& msg_custom_ids,
const QNetworkProxy& proxy);
QNetworkReply::NetworkError markMessagesStarred(RootItem::Importance importance,
const QStringList& msg_custom_ids,
const QNetworkProxy& proxy);
// Assign/deassign tags to/from message(s).
QNetworkReply::NetworkError editLabels(const QString& state, bool assign,
const QStringList& msg_custom_ids, const QNetworkProxy& proxy);
// Stream contents for a feed/label/etc.
QList<Message> streamContents(ServiceRoot* root, const QString& stream_id,
Feed::Status& error, const QNetworkProxy& proxy);
@ -56,7 +68,7 @@ class GreaderNetwork : public QObject {
QPair<QByteArray, QByteArray> authHeader() const;
// Make sure we are logged in and if we are not, return error.
bool ensureLogin(const QNetworkProxy& proxy);
bool ensureLogin(const QNetworkProxy& proxy, QNetworkReply::NetworkError* output = nullptr);
QList<Message> decodeStreamContents(ServiceRoot* root, const QString& stream_json_data, const QString& stream_id);
RootItem* decodeTagsSubscriptions(const QString& categories, const QString& feeds, bool obtain_icons);

View file

@ -61,48 +61,75 @@ QString GreaderServiceRoot::code() const {
void GreaderServiceRoot::saveAllCachedData(bool ignore_errors) {
auto msg_cache = takeMessageCache();
QMapIterator<RootItem::ReadStatus, QStringList> i(msg_cache.m_cachedStatesRead);
/*
QMapIterator<RootItem::ReadStatus, QStringList> i(msg_cache.m_cachedStatesRead);
// Save the actual data read/unread.
while (i.hasNext()) {
i.next();
auto key = i.key();
QStringList ids = i.value();
// Save the actual data read/unread.
while (i.hasNext()) {
i.next();
auto key = i.key();
QStringList ids = i.value();
if (!ids.isEmpty()) {
auto res = network()->markMessagesRead(key, ids, networkProxy());
if (!ignore_errors && res.first != QNetworkReply::NetworkError::NoError) {
if (!ids.isEmpty()) {
if (network()->markMessagesRead(key, ids, networkProxy()) != QNetworkReply::NetworkError::NoError &&
!ignore_errors) {
addMessageStatesToCache(ids, key);
}
}
}
}
}
QMapIterator<RootItem::Importance, QList<Message>> j(msg_cache.m_cachedStatesImportant);
QMapIterator<RootItem::Importance, QList<Message>> j(msg_cache.m_cachedStatesImportant);
// Save the actual data important/not important.
while (j.hasNext()) {
j.next();
auto key = j.key();
QList<Message> messages = j.value();
// Save the actual data important/not important.
while (j.hasNext()) {
j.next();
auto key = j.key();
QList<Message> messages = j.value();
if (!messages.isEmpty()) {
QStringList feed_ids, guid_hashes;
if (!messages.isEmpty()) {
QStringList custom_ids;
for (const Message& msg : messages) {
feed_ids.append(msg.m_feedId);
guid_hashes.append(msg.m_customHash);
custom_ids.append(msg.m_customId);
}
auto res = network()->markMessagesStarred(key, feed_ids, guid_hashes, networkProxy());
if (!ignore_errors && res.first != QNetworkReply::NetworkError::NoError) {
if (network()->markMessagesStarred(key, custom_ids, networkProxy()) != QNetworkReply::NetworkError::NoError &&
!ignore_errors) {
addMessageStatesToCache(messages, key);
}
}
}*/
}
}
QMapIterator<QString, QStringList> k(msg_cache.m_cachedLabelAssignments);
// Assign label for these messages.
while (k.hasNext()) {
k.next();
auto label_custom_id = k.key();
QStringList messages = k.value();
if (!messages.isEmpty()) {
if (network()->editLabels(label_custom_id, true, messages, networkProxy()) != QNetworkReply::NetworkError::NoError &&
!ignore_errors) {
addLabelsAssignmentsToCache(messages, label_custom_id, true);
}
}
}
QMapIterator<QString, QStringList> l(msg_cache.m_cachedLabelDeassignments);
// Remove label from these messages.
while (l.hasNext()) {
l.next();
auto label_custom_id = l.key();
QStringList messages = l.value();
if (!messages.isEmpty()) {
if (network()->editLabels(label_custom_id, false, messages, networkProxy()) != QNetworkReply::NetworkError::NoError &&
!ignore_errors) {
addLabelsAssignmentsToCache(messages, label_custom_id, false);
}
}
}
}
void GreaderServiceRoot::updateTitle() {

View file

@ -222,7 +222,6 @@ QNetworkReply::NetworkError InoreaderNetworkFactory::editLabels(const QString& s
m_oauth2->bearer().toLocal8Bit()));
QStringList trimmed_ids;
QRegularExpression regex_short_id(QSL("[0-9a-zA-Z]+$"));
for (const QString& id : msg_custom_ids) {
trimmed_ids.append(QString("i=") + id);