Add support for Tiny Tiny Rss (#27)
* Add support for Tiny Tiny Rss * Fix copyright notice in ttrssfetcher files * Fix json format for bulk set as read in ttrss * Correctly report errors when sending actions for ttrss * Disable the slow/liked view mode for ttrss * Systematically clear json data before sending a new command * Remove debug messages
This commit is contained in:
parent
d9bd6035ca
commit
5fdd9270e1
12 changed files with 1132 additions and 10 deletions
|
|
@ -1,6 +1,6 @@
|
|||
# Kaktus
|
||||
|
||||
Multi services mobile feed reader, specially designed to work offline. Supports [Netvibes](http://www.netvibes.com/) and [The Old Reader](https://theoldreader.com/) as a feed aggregators. Works on Sailfish OS & BlackBerry 10 devices.
|
||||
Multi services mobile feed reader, specially designed to work offline. Supports [Netvibes](http://www.netvibes.com/), [The Old Reader](https://theoldreader.com/) and [Tiny Tiny Rss](https://tt-rss.org) as a feed aggregators. Works on Sailfish OS & BlackBerry 10 devices.
|
||||
|
||||
Kaktus is working in sync mode, so network connectivity is not
|
||||
required all the time. The significant feature is possibility
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ SOURCES += \
|
|||
src/oldreaderfetcher.cpp \
|
||||
src/nvfetcher.cpp \
|
||||
src/feedlyfetcher.cpp \
|
||||
src/ttrssfetcher.cpp \
|
||||
src/networkaccessmanagerfactory.cpp \
|
||||
src/customnetworkaccessmanager.cpp \
|
||||
src/iconprovider.cpp
|
||||
|
|
@ -49,6 +50,7 @@ HEADERS += \
|
|||
src/oldreaderfetcher.h \
|
||||
src/nvfetcher.h \
|
||||
src/feedlyfetcher.h \
|
||||
src/ttrssfetcher.h \
|
||||
src/networkaccessmanagerfactory.h \
|
||||
src/customnetworkaccessmanager.h \
|
||||
feedly.h \
|
||||
|
|
@ -85,4 +87,5 @@ INSTALLS += translations images
|
|||
DISTFILES += \
|
||||
qml/*.qml \
|
||||
qml/ScalableIconButton.qml \
|
||||
qml/MenuIconItem.qml
|
||||
qml/MenuIconItem.qml \
|
||||
qml/TTRssSignInDialog.qml
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ Page {
|
|||
ListElement { name: "Netvibes"; iconSource: "nv.png"; type: 1}
|
||||
ListElement { name: "Old Reader"; iconSource: "oldreader.png"; type: 2}
|
||||
/*ListElement { name: "Feedly (comming soon)"; iconSource: "feedly.png"; type: 3}*/
|
||||
ListElement { name: "Tiny Tiny Rss"; iconSource: "ttrss.png"; type: 4}
|
||||
}
|
||||
|
||||
header: PageHeader {
|
||||
|
|
@ -107,6 +108,10 @@ Page {
|
|||
fetcher.getConnectUrl(20);
|
||||
//pageStack.replaceAbove(pageStack.previousPage(),Qt.resolvedUrl("FeedlySignInDialog.qml"),{"code": 400});
|
||||
}
|
||||
if (type == 4) {
|
||||
app.reconnectFetcher(4);
|
||||
pageStack.replaceAbove(pageStack.previousPage(), Qt.resolvedUrl("TTRssSignInDialog.qml"), {"code": 400});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,9 @@ Page {
|
|||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
source: app.isNetvibes ? "nv.png" :
|
||||
app.isOldReader ? "oldreader.png" : "feedly.png"
|
||||
app.isOldReader ? "oldreader.png" :
|
||||
app.isFeedly ? "feedly.png" :
|
||||
app.isTTRss ? "ttrss.png" : null
|
||||
width: Theme.iconSizeMedium
|
||||
height: Theme.iconSizeMedium
|
||||
|
||||
|
|
@ -87,7 +89,9 @@ Page {
|
|||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
text: app.isNetvibes ? "Netvibes":
|
||||
app.isOldReader ? "Old Reader" : "Feedly"
|
||||
app.isOldReader ? "Old Reader" :
|
||||
app.isFeedly ? "Feedly" :
|
||||
app.isTTRss ? "Tiny Tiny Rss" : null
|
||||
wrapMode: Text.WordWrap
|
||||
horizontalAlignment: Text.AlignRight
|
||||
color: Theme.highlightColor
|
||||
|
|
@ -119,11 +123,12 @@ Page {
|
|||
color: Theme.highlightColor
|
||||
visible: settings.signedIn
|
||||
text: settings.signedIn ?
|
||||
settings.signinType==0 ? settings.getUsername() :
|
||||
settings.signinType==1 ? "Twitter" :
|
||||
settings.signinType==2 ? "Facebook" :
|
||||
settings.signinType==10 ? settings.getUsername() :
|
||||
settings.signinType==20 ? settings.getProvider() : "" : ""
|
||||
(settings.signinType==0 ? settings.getUsername() :
|
||||
settings.signinType==1 ? "Twitter" :
|
||||
settings.signinType==2 ? "Facebook" :
|
||||
settings.signinType==10 ? settings.getUsername() :
|
||||
settings.signinType==20 ? settings.getProvider() :
|
||||
settings.signinType==30 ? settings.getUsername() : "") : ""
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -676,6 +681,7 @@ Page {
|
|||
iconSource: "image://icons/icon-m-vm4"
|
||||
}
|
||||
MenuIconItem {
|
||||
visible: !app.isTTRss
|
||||
enabled: app.isNetvibes || (app.isOldReader && settings.showBroadcast)
|
||||
text: app.isNetvibes ? qsTr("Slow") : qsTr("Liked")
|
||||
iconSource: app.isNetvibes ? "image://icons/icon-m-vm5" : "image://icons/icon-m-vm6"
|
||||
|
|
|
|||
198
sailfish/qml/TTRssSignInDialog.qml
Normal file
198
sailfish/qml/TTRssSignInDialog.qml
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
Copyright (C) 2014 Michal Kosciesza <michal@mkiol.net>
|
||||
|
||||
This file is part of Kaktus.
|
||||
|
||||
Kaktus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kaktus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kaktus. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
|
||||
|
||||
Dialog {
|
||||
id: root
|
||||
|
||||
property bool showBar: false
|
||||
property int code
|
||||
|
||||
canAccept: url.text != "" && user.text != "" && password.text != ""
|
||||
|
||||
allowedOrientations: {
|
||||
switch (settings.allowedOrientations) {
|
||||
case 1:
|
||||
return Orientation.Portrait;
|
||||
case 2:
|
||||
return Orientation.Landscape;
|
||||
}
|
||||
return Orientation.Landscape | Orientation.Portrait;
|
||||
}
|
||||
|
||||
ActiveDetector {}
|
||||
|
||||
SilicaFlickable {
|
||||
anchors {left: parent.left; right: parent.right }
|
||||
anchors {top: parent.top}
|
||||
height: app.flickHeight
|
||||
clip: true
|
||||
contentHeight: content.height
|
||||
|
||||
Column {
|
||||
id: content
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
|
||||
spacing: Theme.paddingSmall
|
||||
|
||||
DialogHeader {
|
||||
acceptText : qsTr("Sign in")
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors { left: parent.left; right: parent.right}
|
||||
height: Math.max(icon.height, label.height)
|
||||
|
||||
Image {
|
||||
id: icon
|
||||
anchors { right: label.left; rightMargin: Theme.paddingMedium }
|
||||
source: "ttrss.png"
|
||||
width: Theme.iconSizeMedium
|
||||
height: Theme.iconSizeMedium
|
||||
}
|
||||
|
||||
Label {
|
||||
id: label
|
||||
anchors { right: parent.right; rightMargin: Theme.paddingLarge}
|
||||
text: qsTr("Tiny Tiny Rss")
|
||||
wrapMode: Text.WordWrap
|
||||
horizontalAlignment: Text.AlignRight
|
||||
color: Theme.highlightColor
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
y: Theme.paddingSmall/2
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
height: Theme.paddingMedium
|
||||
width: Theme.paddingMedium
|
||||
}
|
||||
|
||||
PaddedLabel {
|
||||
text: qsTr("Enter server url and credentials below.")
|
||||
}
|
||||
|
||||
Item {
|
||||
height: Theme.paddingMedium
|
||||
width: Theme.paddingMedium
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: url
|
||||
anchors.left:parent.left; anchors.right: parent.right
|
||||
|
||||
inputMethodHints: Qt.ImhEmailCharactersOnly | Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText
|
||||
placeholderText: qsTr("Enter the url of your server here!")
|
||||
label: qsTr("Server Url")
|
||||
|
||||
Component.onCompleted: {
|
||||
text = settings.getUrl();
|
||||
}
|
||||
|
||||
EnterKey.iconSource: "image://theme/icon-m-enter-close"
|
||||
EnterKey.onClicked: {
|
||||
Qt.inputMethod.hide();
|
||||
}
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: user
|
||||
anchors.left: parent.left; anchors.right: parent.right
|
||||
|
||||
inputMethodHints: Qt.ImhEmailCharactersOnly| Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText
|
||||
placeholderText: qsTr("Enter username here!")
|
||||
label: qsTr("Username")
|
||||
|
||||
Component.onCompleted: {
|
||||
text = settings.getUsername();
|
||||
}
|
||||
|
||||
EnterKey.iconSource: "image://theme/icon-m-enter-close"
|
||||
EnterKey.onClicked: {
|
||||
Qt.inputMethod.hide();
|
||||
}
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: password
|
||||
anchors.left: parent.left; anchors.right: parent.right
|
||||
inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText | Qt.ImhSensitiveData
|
||||
echoMode: TextInput.Password
|
||||
placeholderText: qsTr("Enter password here!")
|
||||
label: qsTr("Password")
|
||||
|
||||
EnterKey.iconSource: url.text!=="" && user.text!=="" ? "image://theme/icon-m-enter-accept" : "image://theme/icon-m-enter-close"
|
||||
EnterKey.onClicked: {
|
||||
Qt.inputMethod.hide();
|
||||
if (url.text!=="" && user.text!=="")
|
||||
root.accept();
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
height: Theme.itemSizeLarge
|
||||
width: Theme.itemSizeLarge
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function validateEmail(email) {
|
||||
var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||
return re.test(email);
|
||||
}
|
||||
|
||||
onAccepted: {
|
||||
settings.setUrl(url.text);
|
||||
settings.setUsername(user.text);
|
||||
settings.setPassword(password.text);
|
||||
|
||||
m.doInit = settings.signinType != 30;
|
||||
settings.signinType = 30;
|
||||
|
||||
if (code == 0) {
|
||||
fetcher.checkCredentials();
|
||||
} else {
|
||||
if (! dm.busy)
|
||||
dm.cancel();
|
||||
m.doUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
// trick!
|
||||
QtObject {
|
||||
id: m
|
||||
property bool doUpdate: false
|
||||
property bool doInit: false
|
||||
}
|
||||
Component.onDestruction: {
|
||||
if (m.doUpdate) {
|
||||
if (m.doInit)
|
||||
fetcher.init();
|
||||
else
|
||||
fetcher.update();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -31,6 +31,7 @@ ApplicationWindow {
|
|||
readonly property bool isNetvibes: settings.signinType >= 0 && settings.signinType < 10
|
||||
readonly property bool isOldReader: settings.signinType >= 10 && settings.signinType < 20
|
||||
readonly property bool isFeedly: settings.signinType >= 20 && settings.signinType < 30
|
||||
readonly property bool isTTRss: settings.signinType >= 30 && settings.signinType < 40
|
||||
readonly property variant _cache: cache
|
||||
readonly property int stdHeight: orientation==Orientation.Portrait ? Theme.itemSizeMedium : 0.8 * Theme.itemSizeMedium
|
||||
|
||||
|
|
@ -76,6 +77,8 @@ ApplicationWindow {
|
|||
reconnectFetcher(2);
|
||||
else if (type < 30)
|
||||
reconnectFetcher(3);
|
||||
else if (type < 40)
|
||||
reconnectFetcher(4);
|
||||
}
|
||||
|
||||
utils.setRootModel();
|
||||
|
|
@ -326,6 +329,10 @@ ApplicationWindow {
|
|||
pageStack.push(Qt.resolvedUrl("FeedlySignInDialog.qml"),{"code": code});
|
||||
return;
|
||||
}
|
||||
if (type < 40) {
|
||||
pageStack.push(Qt.resolvedUrl("TTRssSignInDialog.qml"),{"code": code});
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Unknown error
|
||||
|
|
|
|||
BIN
sailfish/qml/ttrss.png
Normal file
BIN
sailfish/qml/ttrss.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4 KiB |
|
|
@ -415,6 +415,16 @@ bool Settings::getAutoDownloadOnUpdate()
|
|||
return settings.value("autodownloadonupdate", true).toBool();
|
||||
}
|
||||
|
||||
void Settings::setUrl(const QString &value)
|
||||
{
|
||||
settings.setValue("url", value);
|
||||
}
|
||||
|
||||
QString Settings::getUrl()
|
||||
{
|
||||
return settings.value("url", "").toString();
|
||||
}
|
||||
|
||||
void Settings::setUsername(const QString &value)
|
||||
{
|
||||
settings.setValue("username", value);
|
||||
|
|
|
|||
|
|
@ -212,6 +212,7 @@ public:
|
|||
// 10 - Oldreader
|
||||
// 20 - Feedly
|
||||
// 22 - Feedly with FB
|
||||
// 30 - Tiny Tiny Rss
|
||||
void setSigninType(int);
|
||||
int getSigninType();
|
||||
|
||||
|
|
@ -226,7 +227,9 @@ public:
|
|||
Q_INVOKABLE void setRefreshCookie(const QString &value);
|
||||
Q_INVOKABLE QString getRefreshCookie();
|
||||
|
||||
// Username & Password
|
||||
// Url & Username & Password
|
||||
Q_INVOKABLE void setUrl(const QString &value);
|
||||
Q_INVOKABLE QString getUrl();
|
||||
Q_INVOKABLE void setUsername(const QString &value);
|
||||
Q_INVOKABLE QString getUsername();
|
||||
Q_INVOKABLE void setPassword(const QString &value);
|
||||
|
|
|
|||
750
sailfish/src/ttrssfetcher.cpp
Normal file
750
sailfish/src/ttrssfetcher.cpp
Normal file
|
|
@ -0,0 +1,750 @@
|
|||
/*
|
||||
Copyright (C) 2019 Michal Kosciesza <michal@mkiol.net>
|
||||
Copyright (C) 2019 Renaud Casenave-Péré <renaud@casenave-pere.fr>
|
||||
|
||||
This file is part of Kaktus.
|
||||
|
||||
Kaktus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kaktus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kaktus. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <QRegExp>
|
||||
#include <QtCore/qmath.h>
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
#include <QJsonDocument>
|
||||
#endif
|
||||
|
||||
#include "ttrssfetcher.h"
|
||||
#include "settings.h"
|
||||
#include "downloadmanager.h"
|
||||
#include "utils.h"
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
#define FETCHER_SLOT(callback) &TTRssFetcher::callback
|
||||
#else
|
||||
#define FETCHER_SLOT(callback) SLOT(callback)
|
||||
#endif
|
||||
|
||||
TTRssFetcher::TTRssFetcher(QObject *parent) :
|
||||
Fetcher(parent),
|
||||
currentCommand(NULL),
|
||||
currentJob(Idle)
|
||||
{
|
||||
}
|
||||
|
||||
TTRssFetcher::~TTRssFetcher()
|
||||
{
|
||||
}
|
||||
|
||||
void TTRssFetcher::signIn()
|
||||
{
|
||||
Settings *s = Settings::instance();
|
||||
|
||||
if (sessionId != "") {
|
||||
prepareUploadActions();
|
||||
return;
|
||||
}
|
||||
|
||||
QString url = s->getUrl();
|
||||
QString password = s->getPassword();
|
||||
QString username = s->getUsername();
|
||||
int type = s->getSigninType();
|
||||
|
||||
switch (type) {
|
||||
case 30:
|
||||
{
|
||||
if (password == "" || username == "" || url == "") {
|
||||
qWarning() << "TTRss credentials are invalid!";
|
||||
if (busyType == Fetcher::CheckingCredentials)
|
||||
emit errorCheckingCredentials(400);
|
||||
else
|
||||
emit error(400);
|
||||
setBusy(false);
|
||||
return;
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
QJsonObject params;
|
||||
params["user"] = username;
|
||||
params["password"] = password;
|
||||
#else
|
||||
QString params = "\"user\":\"" + username + "\",\"password\":\"" + password.replace("\\", "\\\\").replace("\"", "\\\"") + "\"";
|
||||
#endif
|
||||
|
||||
sendApiCall("login", params, FETCHER_SLOT(finishedSignIn));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
qWarning() << "Invalid sign in type!";
|
||||
emit error(500);
|
||||
setBusy(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void TTRssFetcher::finishedSignIn()
|
||||
{
|
||||
Settings *s = Settings::instance();
|
||||
if (!processResponse()) {
|
||||
s->setSignedIn(false);
|
||||
sessionId = "";
|
||||
apiLevel = 0;
|
||||
return;
|
||||
} else {
|
||||
s->setSignedIn(true);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
sessionId = jsonObj["content"].toObject()["session_id"].toString();
|
||||
apiLevel = jsonObj["content"].toObject()["api_level"].toInt();
|
||||
#else
|
||||
sessionId = jsonObj["content"].toMap()["session_id"].toString();
|
||||
apiLevel = jsonObj["content"].toMap()["api_level"].toInt();
|
||||
#endif
|
||||
if (busyType == Fetcher::CheckingCredentials) {
|
||||
emit credentialsValid();
|
||||
setBusy(false);
|
||||
} else {
|
||||
sendApiCall("getConfig", FETCHER_SLOT(finishedConfig));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TTRssFetcher::finishedConfig()
|
||||
{
|
||||
if (!processResponse()) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
iconsUrl = jsonObj["content"].toObject()["icons_url"].toString();
|
||||
#else
|
||||
iconsUrl = jsonObj["content"].toMap()["icons_url"].toString();
|
||||
#endif
|
||||
|
||||
prepareUploadActions();
|
||||
}
|
||||
|
||||
void TTRssFetcher::startFetching()
|
||||
{
|
||||
Settings *s = Settings::instance();
|
||||
|
||||
if (!s->db->makeBackup ()) {
|
||||
qWarning() << "Unable to make DB backup!";
|
||||
emit error(506);
|
||||
setBusy(false);
|
||||
return;
|
||||
}
|
||||
|
||||
s->db->cleanDashboards();
|
||||
|
||||
DatabaseManager::Dashboard d;
|
||||
d.id = "ttrss";
|
||||
d.name = "Default";
|
||||
d.title = "Default";
|
||||
d.description = "Tiny Tiny Rss default dashboard";
|
||||
s->db->writeDashboard(d);
|
||||
s->setDashboardInUse(d.id);
|
||||
|
||||
s->db->cleanTabs();
|
||||
s->db->cleanStreams();
|
||||
s->db->cleanModules();
|
||||
|
||||
if(busyType == Fetcher::Initiating) {
|
||||
s->db->cleanCache();
|
||||
s->db->cleanEntries();
|
||||
}
|
||||
|
||||
commandList.clear();
|
||||
commandList.append(&TTRssFetcher::fetchCategories);
|
||||
commandList.append(&TTRssFetcher::fetchFeeds);
|
||||
commandList.append(&TTRssFetcher::fetchStream);
|
||||
commandList.append(&TTRssFetcher::fetchStarredStream);
|
||||
commandList.append(&TTRssFetcher::fetchPublishedStream);
|
||||
commandList.append(&TTRssFetcher::pruneOld);
|
||||
|
||||
proggressTotal = commandList.size() + s->getRetentionDays();
|
||||
proggress = 0;
|
||||
lastDate = 0;
|
||||
offset = 0;
|
||||
|
||||
callNextCmd();
|
||||
}
|
||||
|
||||
void TTRssFetcher::fetchCategories()
|
||||
{
|
||||
sendApiCall("getCategories", FETCHER_SLOT(finishedCategories));
|
||||
}
|
||||
|
||||
void TTRssFetcher::finishedCategories()
|
||||
{
|
||||
if (!processResponse()) {
|
||||
return;
|
||||
}
|
||||
|
||||
startJob(StoreCategories);
|
||||
}
|
||||
|
||||
void TTRssFetcher::fetchFeeds()
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
QJsonObject params;
|
||||
params["cat_id"] = -3;
|
||||
#else
|
||||
QString params = "\"cat_id\":-3";
|
||||
#endif
|
||||
|
||||
sendApiCall("getFeeds", params, FETCHER_SLOT(finishedFeeds));
|
||||
}
|
||||
|
||||
void TTRssFetcher::finishedFeeds()
|
||||
{
|
||||
if (!processResponse()) {
|
||||
return;
|
||||
}
|
||||
|
||||
startJob(StoreFeeds);
|
||||
}
|
||||
|
||||
void TTRssFetcher::fetchStream()
|
||||
{
|
||||
Settings *s = Settings::instance();
|
||||
|
||||
if (offset == 0) {
|
||||
s->db->updateEntriesFlag(1);
|
||||
}
|
||||
|
||||
getHeadlines(AllArticles, true, !s->getSyncRead(), offset, FETCHER_SLOT(finishedStream));
|
||||
}
|
||||
|
||||
void TTRssFetcher::finishedStream()
|
||||
{
|
||||
if (!processResponse()) {
|
||||
return;
|
||||
}
|
||||
|
||||
startJob(StoreStream);
|
||||
}
|
||||
|
||||
void TTRssFetcher::finishedStream2()
|
||||
{
|
||||
Settings *s = Settings::instance();
|
||||
if ((s->getRetentionDays() > 0 && lastDate > s->getRetentionDays()) ||
|
||||
lastCount < streamLimit) {
|
||||
offset = 0;
|
||||
lastDate = s->getRetentionDays();
|
||||
} else {
|
||||
offset += lastCount;
|
||||
commandList.prepend(currentCommand);
|
||||
}
|
||||
|
||||
callNextCmd();
|
||||
}
|
||||
|
||||
void TTRssFetcher::fetchStarredStream()
|
||||
{
|
||||
getHeadlines(Starred, true, false, offset, FETCHER_SLOT(finishedStream));
|
||||
}
|
||||
|
||||
void TTRssFetcher::fetchPublishedStream()
|
||||
{
|
||||
getHeadlines(Published, true, false, offset, FETCHER_SLOT(finishedStream));
|
||||
}
|
||||
|
||||
void TTRssFetcher::pruneOld()
|
||||
{
|
||||
Settings::instance()->db->removeEntriesByFlag(1);
|
||||
callNextCmd();
|
||||
}
|
||||
|
||||
void TTRssFetcher::startJob(Job job)
|
||||
{
|
||||
if (isRunning()) {
|
||||
qWarning() << "Job is running";
|
||||
return;
|
||||
}
|
||||
|
||||
disconnect(this, SIGNAL(finished()), 0, 0);
|
||||
currentJob = job;
|
||||
|
||||
switch (job) {
|
||||
case StoreCategories:
|
||||
case StoreFeeds:
|
||||
connect(this, SIGNAL(finished()), this, SLOT(callNextCmd()));
|
||||
break;
|
||||
case StoreStream:
|
||||
connect(this, SIGNAL(finished()), this, SLOT(finishedStream2()));
|
||||
break;
|
||||
default:
|
||||
qWarning() << "Unknown Job!";
|
||||
emit error(502);
|
||||
setBusy(false);
|
||||
return;
|
||||
}
|
||||
|
||||
start(QThread::LowPriority);
|
||||
}
|
||||
|
||||
void TTRssFetcher::run()
|
||||
{
|
||||
switch (currentJob) {
|
||||
case StoreCategories:
|
||||
storeCategories();
|
||||
break;
|
||||
case StoreFeeds:
|
||||
storeFeeds();
|
||||
break;
|
||||
case StoreStream:
|
||||
storeStream();
|
||||
break;
|
||||
default:
|
||||
qWarning() << "Unknown Job!";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TTRssFetcher::storeCategories()
|
||||
{
|
||||
Settings *s = Settings::instance();
|
||||
QString dashboardId = "ttrss";
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
if (jsonObj["content"].isArray()) {
|
||||
QJsonArray arr = jsonObj["content"].toArray();
|
||||
int end = arr.count();
|
||||
#else
|
||||
if (jsonObj["content"].type()==QVariant::List) {
|
||||
QVariantList::const_iterator i = jsonObj["content"].toList().constBegin();
|
||||
QVariantList::const_iterator end = jsonObj["content"].toList().constEnd();
|
||||
#endif
|
||||
for (int i = 0; i < end; ++i) {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
QJsonObject obj = arr.at(i).toObject();
|
||||
#else
|
||||
QVariantMap obj = (*i).toMap();
|
||||
#endif
|
||||
if (obj["id"].toInt() >= 0) {
|
||||
DatabaseManager::Tab t;
|
||||
t.id = QString::number(obj["id"].toInt());
|
||||
t.dashboardId = dashboardId;
|
||||
t.title = obj["title"].toString();
|
||||
s->db->writeTab(t);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qWarning() << "No categories found!";
|
||||
}
|
||||
}
|
||||
|
||||
void TTRssFetcher::storeFeeds()
|
||||
{
|
||||
Settings *s = Settings::instance();
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
if (jsonObj["content"].isArray()) {
|
||||
QJsonArray arr = jsonObj["content"].toArray();
|
||||
int end = arr.count();
|
||||
#else
|
||||
if (jsonObj["content"].type()==QVariant::List) {
|
||||
QVariantList::const_iterator i = jsonObj["content"].toList().constBegin();
|
||||
QVariantList::const_iterator end = jsonObj["content"].toList().constEnd();
|
||||
#endif
|
||||
for (int i = 0; i < end; ++i) {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
QJsonObject obj = arr.at(i).toObject();
|
||||
#else
|
||||
QVariantMap obj = (*i).toMap();
|
||||
#endif
|
||||
DatabaseManager::Stream st;
|
||||
st.id = QString::number(obj["id"].toInt());
|
||||
st.title = obj["title"].toString();
|
||||
st.link = obj["feed_url"].toString();
|
||||
st.query = st.link;
|
||||
st.content = "";
|
||||
st.type = "";
|
||||
st.unread = 0;
|
||||
st.saved = 0;
|
||||
st.read = 0;
|
||||
st.slow = 0;
|
||||
st.newestItemAddedAt = obj["last_updated"].toInt();
|
||||
st.updateAt = st.newestItemAddedAt;
|
||||
st.lastUpdate = QDateTime::currentDateTimeUtc().toTime_t();
|
||||
if (obj["has_icon"].toBool()) {
|
||||
st.icon = s->getUrl() + "/" + iconsUrl + "/" + st.id + ".ico";
|
||||
DatabaseManager::CacheItem item;
|
||||
item.origUrl = st.icon;
|
||||
item.finalUrl = st.icon;
|
||||
item.type = "icon";
|
||||
emit addDownload(item);
|
||||
}
|
||||
|
||||
s->db->writeStream(st);
|
||||
|
||||
DatabaseManager::Module m;
|
||||
m.id = st.id;
|
||||
m.name = st.title;
|
||||
m.title = st.title;
|
||||
m.status = "";
|
||||
m.widgetId = "";
|
||||
m.pageId = "";
|
||||
m.tabId = QString::number(obj["cat_id"].toInt());
|
||||
m.streamList.append(st.id);
|
||||
s->db->writeModule(m);
|
||||
}
|
||||
} else {
|
||||
qWarning() << "No feeds found!";
|
||||
}
|
||||
}
|
||||
|
||||
void TTRssFetcher::storeStream()
|
||||
{
|
||||
Settings *s = Settings::instance();
|
||||
int count = 0;
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
if (jsonObj["content"].isArray()) {
|
||||
QJsonArray arr = jsonObj["content"].toArray();
|
||||
int end = arr.count();
|
||||
count = end;
|
||||
#else
|
||||
if (jsonObj["content"].type()==QVariant::List) {
|
||||
QVariantList::const_iterator i = jsonObj["content"].toList().constBegin();
|
||||
QVariantList::const_iterator end = jsonObj["content"].toList().constEnd();
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < arr.count(); ++i) {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
QJsonObject obj = arr.at(i).toObject();
|
||||
#else
|
||||
QVariantMap obj = (*i).toMap();
|
||||
++count;
|
||||
#endif
|
||||
|
||||
DatabaseManager::Entry e;
|
||||
e.id = QString::number(obj["id"].toInt());
|
||||
e.streamId = QString::number(obj["feed_id"].toInt());
|
||||
e.title =obj["title"].toString();
|
||||
e.author = obj["author"].toString();
|
||||
|
||||
if (obj["content"].isString())
|
||||
e.content = obj["content"].toString();
|
||||
|
||||
e.link = obj["link"].toString();
|
||||
e.read = obj["unread"].toBool() ? 0 : 1;
|
||||
e.saved = obj["marked"].toBool() ? 1 : 0;
|
||||
e.publishedAt = obj["updated"].toInt();
|
||||
e.createdAt = obj["updated"].toInt();
|
||||
e.cached = 0;
|
||||
e.fresh = 1;
|
||||
e.broadcast = obj["published"].toBool() ? 1 : 0;
|
||||
e.timestamp = obj["updated"].toInt();
|
||||
|
||||
QRegExp rx("<img\\s[^>]*src\\s*=\\s*(\"[^\"]*\"|'[^']*')", Qt::CaseInsensitive);
|
||||
if (rx.indexIn(e.content)!=-1) {
|
||||
QString imgSrc = rx.cap(1); imgSrc = imgSrc.mid(1,imgSrc.length()-2);
|
||||
if (imgSrc!="") {
|
||||
if (s->getCachingMode() == 2 || (s->getCachingMode() == 1 && s->dm->isWLANConnected())) {
|
||||
if (!s->db->isCacheExistsByFinalUrl(Utils::hash(imgSrc))) {
|
||||
DatabaseManager::CacheItem item;
|
||||
item.origUrl = imgSrc;
|
||||
item.finalUrl = imgSrc;
|
||||
item.type = "entry-image";
|
||||
emit addDownload(item);
|
||||
}
|
||||
}
|
||||
e.image = imgSrc;
|
||||
}
|
||||
}
|
||||
|
||||
s->db->writeEntry(e);
|
||||
if (!e.saved && !e.broadcast && s->getRetentionDays() > 0) {
|
||||
int date = QDateTime::fromTime_t(e.timestamp).daysTo(QDateTime::currentDateTimeUtc());
|
||||
if (date > lastDate)
|
||||
lastDate = date;
|
||||
}
|
||||
}
|
||||
|
||||
lastCount = count;
|
||||
}
|
||||
}
|
||||
|
||||
void TTRssFetcher::uploadActions()
|
||||
{
|
||||
if (!actionsList.isEmpty()) {
|
||||
emit uploading();
|
||||
setAction();
|
||||
}
|
||||
}
|
||||
|
||||
void TTRssFetcher::setAction()
|
||||
{
|
||||
Settings *s = Settings::instance();
|
||||
DatabaseManager::Action action = actionsList.first();
|
||||
|
||||
QString ids;
|
||||
int mode, field;
|
||||
|
||||
switch (action.type)
|
||||
{
|
||||
case DatabaseManager::SetRead:
|
||||
case DatabaseManager::UnSetRead:
|
||||
{
|
||||
ids = action.id1.replace('&', ',');
|
||||
mode = action.type == DatabaseManager::SetRead ? 0 : 1;
|
||||
field = 2;
|
||||
break;
|
||||
}
|
||||
case DatabaseManager::SetSaved:
|
||||
case DatabaseManager::UnSetSaved:
|
||||
{
|
||||
ids = action.id1.replace('&', ',');
|
||||
mode = action.type == DatabaseManager::SetSaved ? 1 : 0;
|
||||
field = 0;
|
||||
break;
|
||||
}
|
||||
case DatabaseManager::SetBroadcast:
|
||||
case DatabaseManager::UnSetBroadcast:
|
||||
{
|
||||
ids = action.id1.replace('&', ',');
|
||||
mode = action.type == DatabaseManager::SetBroadcast ? 1 : 0;
|
||||
field = 1;
|
||||
break;
|
||||
}
|
||||
case DatabaseManager::SetStreamReadAll:
|
||||
case DatabaseManager::UnSetStreamReadAll:
|
||||
{
|
||||
ids = mergeEntryIds(s->db->readEntriesByStream(action.id1, 0, s->db->countEntriesByStream(action.id1)),
|
||||
action.type == DatabaseManager::SetStreamReadAll);
|
||||
mode = action.type == DatabaseManager::SetStreamReadAll ? 0 : 1;
|
||||
field = 2;
|
||||
break;
|
||||
}
|
||||
case DatabaseManager::SetTabReadAll:
|
||||
case DatabaseManager::UnSetTabReadAll:
|
||||
{
|
||||
QList<QString> streams = s->db->readStreamIdsByTab(action.id1);
|
||||
for (int i = 0; i < streams.count(); ++i) {
|
||||
if (!ids.isEmpty())
|
||||
ids += ",";
|
||||
ids += mergeEntryIds(s->db->readEntriesByStream(streams[i], 0, s->db->countEntriesByStream(streams[i])),
|
||||
action.type == DatabaseManager::SetTabReadAll);
|
||||
}
|
||||
|
||||
mode = action.type == DatabaseManager::SetTabReadAll ? 0 : 1;
|
||||
field = 2;
|
||||
break;
|
||||
}
|
||||
case DatabaseManager::SetAllRead:
|
||||
case DatabaseManager::UnSetAllRead:
|
||||
{
|
||||
QList<DatabaseManager::Stream> streams = s->db->readStreamsByDashboard(action.id1);
|
||||
for (int i = 0; i < streams.count(); ++i) {
|
||||
if (!ids.isEmpty())
|
||||
ids += ",";
|
||||
ids += mergeEntryIds(s->db->readEntriesByStream(streams[i].id, 0, s->db->countEntriesByStream(streams[i].id)),
|
||||
action.type == DatabaseManager::SetAllRead);
|
||||
}
|
||||
|
||||
mode = action.type == DatabaseManager::SetAllRead ? 0 : 1;
|
||||
field = 2;
|
||||
break;
|
||||
}
|
||||
case DatabaseManager::SetListRead:
|
||||
case DatabaseManager::UnSetListRead:
|
||||
{
|
||||
ids = action.id1.replace('&', ',');
|
||||
mode = action.type == DatabaseManager::SetListRead ? 0 : 1;
|
||||
field = 2;
|
||||
break;
|
||||
}
|
||||
case DatabaseManager::SetListSaved:
|
||||
case DatabaseManager::UnSetListSaved:
|
||||
{
|
||||
ids = action.id1.replace('&', ',');
|
||||
mode = action.type == DatabaseManager::SetListSaved ? 1 : 0;
|
||||
field = 1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
qWarning() << "Unknown action type: " << action.type;
|
||||
finishedSetAction();
|
||||
return;
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
QJsonObject params;
|
||||
params["article_ids"] = ids;
|
||||
params["mode"] = mode;
|
||||
params["field"] = field;
|
||||
#else
|
||||
QString params = "\"article_ids\":\"" + ids + "\",\"mode\":" + QString::number(mode) +
|
||||
",\"field\":" + QString::number(field);
|
||||
#endif
|
||||
|
||||
sendApiCall("updateArticle", params, FETCHER_SLOT(finishedSetAction));
|
||||
}
|
||||
|
||||
void TTRssFetcher::finishedSetAction()
|
||||
{
|
||||
if (!processResponse()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Settings *s = Settings::instance();
|
||||
|
||||
DatabaseManager::Action action = actionsList.takeFirst();
|
||||
s->db->removeActionsByIdAndType(action.id1, action.type);
|
||||
|
||||
emit uploadProgress(uploadProggressTotal - actionsList.size(), uploadProggressTotal);
|
||||
|
||||
if (actionsList.isEmpty()) {
|
||||
startFetching();
|
||||
} else {
|
||||
setAction();
|
||||
}
|
||||
}
|
||||
|
||||
void TTRssFetcher::callNextCmd()
|
||||
{
|
||||
if (!commandList.isEmpty()) {
|
||||
proggress = proggressTotal - commandList.size() - Settings::instance()->getRetentionDays() + lastDate;
|
||||
emit progress(proggress, proggressTotal);
|
||||
currentCommand = commandList.takeFirst();
|
||||
(this->*currentCommand)();
|
||||
} else {
|
||||
taskEnd();
|
||||
}
|
||||
}
|
||||
|
||||
QString TTRssFetcher::mergeEntryIds(const QList<DatabaseManager::Entry>& entries, bool read)
|
||||
{
|
||||
QString ids;
|
||||
|
||||
for (int i = 0; i < entries.count(); ++i) {
|
||||
if (entries[i].read == read) {
|
||||
if (!ids.isEmpty())
|
||||
ids += ",";
|
||||
ids += entries[i].id;
|
||||
}
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
void TTRssFetcher::getHeadlines(int feedId, bool getContent, bool unreadOnly, int offset, ReplyCallback callback)
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
QJsonObject params;
|
||||
params["feed_id"] = feedId;
|
||||
params["show_content"] = getContent;
|
||||
params["view_mode"] = unreadOnly ? "unread" : "all_articles";
|
||||
params["include_attachments"] = getContent;
|
||||
params["order_by"] = "feed_dates";
|
||||
params["skip"] = offset;
|
||||
params["limit"] = streamLimit;
|
||||
#else
|
||||
QString params = "\"feed_id\":" + QString::number(feedId) + "," +
|
||||
"\"show_content\":" + (getContent ? "true," : "false,") +
|
||||
"\"show_excerpt\":false," +
|
||||
"\"view_mode\":" + (unreadOnly ? "\"unread\"," : "\"all_articles\",") +
|
||||
"\"include_attachments\":" + (getContent ? "true," : "false,") +
|
||||
"\"order_by\":\"feed_dates\"," +
|
||||
"\"skip\":" + QString::number(offset) + "," +
|
||||
"\"limit\":" + QString::number(streamLimit);
|
||||
#endif
|
||||
|
||||
sendApiCall("getHeadlines", params, callback);
|
||||
}
|
||||
|
||||
void TTRssFetcher::sendApiCall(const QString& op, ReplyCallback callback)
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
QJsonObject params;
|
||||
#else
|
||||
QString params;
|
||||
#endif
|
||||
sendApiCall(op, params, callback);
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
void TTRssFetcher::sendApiCall(const QString& op, const QJsonObject& params, ReplyCallback callback)
|
||||
#else
|
||||
void TTRssFetcher::sendApiCall(const QString& op, const QString& params, ReplyCallback callback);
|
||||
#endif
|
||||
{
|
||||
data.clear();
|
||||
|
||||
if (currentReply != NULL) {
|
||||
currentReply->disconnect();
|
||||
currentReply->deleteLater();
|
||||
currentReply = NULL;
|
||||
}
|
||||
|
||||
QNetworkRequest request(QUrl(Settings::instance()->getUrl() + "/api/"));
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json; charset=UTF-8");
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
QJsonObject obj (params);
|
||||
if (!sessionId.isEmpty()) {
|
||||
obj["sid"] = sessionId;
|
||||
}
|
||||
obj["op"] = op;
|
||||
|
||||
QString body = QJsonDocument(obj).toJson(QJsonDocument::Compact);
|
||||
#else
|
||||
QString body = "{\"op\":\"" + op + "\"" + (!params.isEmpty() ? params : "") + "}";
|
||||
#endif
|
||||
|
||||
currentReply = nam.post(request, body.toUtf8());
|
||||
connect(currentReply, &QNetworkReply::finished, this, callback);
|
||||
connect(currentReply, SIGNAL(readyRead()), this, SLOT(readyRead()));
|
||||
connect(currentReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(networkError(QNetworkReply::NetworkError)));
|
||||
}
|
||||
|
||||
bool TTRssFetcher::processResponse()
|
||||
{
|
||||
if (currentReply->error() && currentReply->error() != QNetworkReply::OperationCanceledError) {
|
||||
emit error(500);
|
||||
setBusy(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse()) {
|
||||
qWarning() << "Error parsing Json!";
|
||||
emit error(600);
|
||||
setBusy(false);
|
||||
return false;
|
||||
} else if (jsonObj["status"].toInt() != 0) {
|
||||
QString err;
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
err = jsonObj["content"].toObject()["error"].toString();
|
||||
#else
|
||||
err = jsonObj["content"].toMap()["error"].toString();
|
||||
#endif
|
||||
qWarning() << "Error: " << err;
|
||||
if (err == "LOGIN_ERROR") {
|
||||
if (busyType == Fetcher::CheckingCredentials) {
|
||||
emit errorCheckingCredentials(501);
|
||||
} else {
|
||||
emit error(402);
|
||||
}
|
||||
} else if (err == "NOT_LOGGED_IN") {
|
||||
emit error(401);
|
||||
} else {
|
||||
emit error(601);
|
||||
}
|
||||
setBusy(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
134
sailfish/src/ttrssfetcher.h
Normal file
134
sailfish/src/ttrssfetcher.h
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
Copyright (C) 2019 Michal Kosciesza <michal@mkiol.net>
|
||||
Copyright (C) 2019 Renaud Casenave-Péré <renaud@casenave-pere.fr>
|
||||
|
||||
This file is part of Kaktus.
|
||||
|
||||
Kaktus is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kaktus is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kaktus. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TTRSSFETCHER_H
|
||||
#define TTRSSFETCHER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QList>
|
||||
#include <QVariantMap>
|
||||
#include <QNetworkRequest>
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
#include <QJsonArray>
|
||||
#else
|
||||
#include <QVariantList>
|
||||
#endif
|
||||
|
||||
#include "fetcher.h"
|
||||
#include "databasemanager.h"
|
||||
|
||||
class TTRssFetcher : public Fetcher
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
typedef void (TTRssFetcher::*ReplyCallback)();
|
||||
#else
|
||||
typedef QString ReplyCallback;
|
||||
#endif
|
||||
|
||||
typedef void (TTRssFetcher::*ChainCommand)();
|
||||
|
||||
enum Job {
|
||||
Idle,
|
||||
StoreCategories,
|
||||
StoreFeeds,
|
||||
StoreStream
|
||||
};
|
||||
|
||||
enum SpecialFeed {
|
||||
AllArticles = -4,
|
||||
Fresh = -3,
|
||||
Published = -2,
|
||||
Starred = -1
|
||||
};
|
||||
|
||||
public:
|
||||
explicit TTRssFetcher(QObject *parent = 0);
|
||||
virtual ~TTRssFetcher();
|
||||
|
||||
Q_INVOKABLE virtual void getConnectUrl(int) {}
|
||||
Q_INVOKABLE virtual bool setConnectUrl(const QString &) { return true; }
|
||||
|
||||
protected:
|
||||
void run();
|
||||
|
||||
private Q_SLOTS:
|
||||
void finishedSignIn();
|
||||
void finishedConfig();
|
||||
void finishedCategories();
|
||||
void finishedFeeds();
|
||||
void finishedStream();
|
||||
void finishedStream2();
|
||||
void finishedSetAction();
|
||||
|
||||
void callNextCmd();
|
||||
|
||||
private:
|
||||
virtual void signIn();
|
||||
virtual void startFetching();
|
||||
virtual void uploadActions();
|
||||
|
||||
void fetchCategories();
|
||||
void fetchFeeds();
|
||||
void fetchStream();
|
||||
void fetchStarredStream();
|
||||
void fetchPublishedStream();
|
||||
void pruneOld();
|
||||
void setAction();
|
||||
|
||||
void startJob(Job job);
|
||||
|
||||
void storeCategories();
|
||||
void storeFeeds();
|
||||
void storeStream();
|
||||
|
||||
QString mergeEntryIds(const QList<DatabaseManager::Entry>& entries, bool read);
|
||||
|
||||
void getHeadlines(int feedId, bool getContent, bool unreadOnly, int offset, ReplyCallback callback);
|
||||
|
||||
void sendApiCall(const QString& op, ReplyCallback callback);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
void sendApiCall(const QString& op, const QJsonObject& params, ReplyCallback callback);
|
||||
#else
|
||||
void sendApiCall(const QString& op, const QString& params, ReplyCallback callback);
|
||||
#endif
|
||||
|
||||
bool processResponse();
|
||||
|
||||
private:
|
||||
static const int streamLimit = 100;
|
||||
|
||||
QString sessionId;
|
||||
int apiLevel;
|
||||
QString iconsUrl;
|
||||
|
||||
QList<int> processedActionList;
|
||||
QList<ChainCommand> commandList;
|
||||
ChainCommand currentCommand;
|
||||
Job currentJob;
|
||||
int lastDate;
|
||||
int lastCount;
|
||||
int offset;
|
||||
};
|
||||
|
||||
#endif // TTRSSFETCHER_H
|
||||
|
|
@ -68,6 +68,7 @@
|
|||
#include "oldreaderfetcher.h"
|
||||
#include "nvfetcher.h"
|
||||
#include "feedlyfetcher.h"
|
||||
#include "ttrssfetcher.h"
|
||||
|
||||
Utils::Utils(QObject *parent) :
|
||||
QObject(parent)//, ncm(new QNetworkConfigurationManager(parent))
|
||||
|
|
@ -813,6 +814,11 @@ void Utils::resetFetcher(int type)
|
|||
s->fetcher = new FeedlyFetcher();
|
||||
}
|
||||
|
||||
if (type == 4) {
|
||||
// Tiny Tiny Rss fetcher
|
||||
s->fetcher = new TTRssFetcher();
|
||||
}
|
||||
|
||||
if (s->fetcher != NULL)
|
||||
#ifdef BB10
|
||||
s->qml->setContextProperty("fetcher", s->fetcher);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue