freshrss experimental working
This commit is contained in:
parent
8cc268ca9a
commit
6dc5e016f1
5 changed files with 164 additions and 33 deletions
|
@ -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/"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -61,8 +61,6 @@ QString GreaderServiceRoot::code() const {
|
|||
|
||||
void GreaderServiceRoot::saveAllCachedData(bool ignore_errors) {
|
||||
auto msg_cache = takeMessageCache();
|
||||
|
||||
/*
|
||||
QMapIterator<RootItem::ReadStatus, QStringList> i(msg_cache.m_cachedStatesRead);
|
||||
|
||||
// Save the actual data read/unread.
|
||||
|
@ -72,9 +70,8 @@ void GreaderServiceRoot::saveAllCachedData(bool ignore_errors) {
|
|||
QStringList ids = i.value();
|
||||
|
||||
if (!ids.isEmpty()) {
|
||||
auto res = network()->markMessagesRead(key, ids, networkProxy());
|
||||
|
||||
if (!ignore_errors && res.first != QNetworkReply::NetworkError::NoError) {
|
||||
if (network()->markMessagesRead(key, ids, networkProxy()) != QNetworkReply::NetworkError::NoError &&
|
||||
!ignore_errors) {
|
||||
addMessageStatesToCache(ids, key);
|
||||
}
|
||||
}
|
||||
|
@ -89,20 +86,50 @@ void GreaderServiceRoot::saveAllCachedData(bool ignore_errors) {
|
|||
QList<Message> messages = j.value();
|
||||
|
||||
if (!messages.isEmpty()) {
|
||||
QStringList feed_ids, guid_hashes;
|
||||
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() {
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue