2025-02-01 11:33:18 +01:00
|
|
|
/*
|
|
|
|
|
* This file is part of the Flowee project
|
|
|
|
|
* Copyright (C) 2025 Tom Zander <tom@flowee.org>
|
|
|
|
|
*
|
|
|
|
|
* This program 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.
|
|
|
|
|
*
|
|
|
|
|
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
#include "FeedDataProvider.h"
|
|
|
|
|
#include <utils/Logger.h>
|
|
|
|
|
|
|
|
|
|
#include <FloweePay.h>
|
|
|
|
|
#include <QFile>
|
|
|
|
|
#include <QFileInfo>
|
|
|
|
|
#include <QJsonArray>
|
|
|
|
|
#include <QJsonObject>
|
|
|
|
|
#include <QJsonDocument>
|
|
|
|
|
#include <QTimer>
|
|
|
|
|
#include <QUrl>
|
2025-02-03 13:09:59 +01:00
|
|
|
#include <QCoreApplication>
|
2025-02-01 11:33:18 +01:00
|
|
|
|
2025-11-17 11:57:50 +01:00
|
|
|
constexpr const char *FEED = "/v/index.json";
|
2025-02-03 13:09:59 +01:00
|
|
|
constexpr const char *FLOWEE_JSON = "social-feed-flowee.json";
|
2025-02-01 11:33:18 +01:00
|
|
|
|
|
|
|
|
FeedDataProvider::FeedDataProvider(QObject *parent)
|
|
|
|
|
: QObject(parent)
|
|
|
|
|
{
|
|
|
|
|
QFileInfo info(FLOWEE_JSON);
|
|
|
|
|
bool useOld = info.exists();
|
|
|
|
|
if (useOld) {
|
|
|
|
|
m_lastCheck = info.lastModified();
|
|
|
|
|
readFeed();
|
|
|
|
|
}
|
2025-02-03 13:09:59 +01:00
|
|
|
if (m_lastCheck.isNull()
|
2025-02-01 11:33:18 +01:00
|
|
|
|| m_lastCheck.msecsTo(QDateTime::currentDateTime()) > 4 * 60 * 60 * 1000) {
|
|
|
|
|
QTimer::singleShot(10, this, SLOT(start()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FeedDataProvider::start()
|
|
|
|
|
{
|
2025-11-17 11:57:50 +01:00
|
|
|
if (m_httpClient)
|
|
|
|
|
return;
|
2025-02-01 11:33:18 +01:00
|
|
|
|
2025-11-17 11:57:50 +01:00
|
|
|
// Prepare the HTTP request
|
|
|
|
|
boost::beast::http::request<boost::beast::http::vector_body<char>> request;
|
|
|
|
|
request.version(11);
|
2025-02-01 11:33:18 +01:00
|
|
|
if (m_lastCheck.isNull())
|
2025-11-17 11:57:50 +01:00
|
|
|
request.method(boost::beast::http::verb::get);
|
2025-02-01 11:33:18 +01:00
|
|
|
else
|
2025-11-17 11:57:50 +01:00
|
|
|
request.method(boost::beast::http::verb::head);
|
|
|
|
|
request.target(FEED);
|
|
|
|
|
request.set(boost::beast::http::field::host, "flowee.org");
|
|
|
|
|
auto *fp = FloweePay::instance();
|
|
|
|
|
m_httpClient = SimpleHttpClient::create(fp->ioContext(), fp->sslContext(), request);
|
|
|
|
|
connect(m_httpClient.get(), SIGNAL(finished()), this, SLOT(downloadFinished()));
|
|
|
|
|
connect(m_httpClient.get(), SIGNAL(errored(SimpleHttpClient::ErrorType)),
|
|
|
|
|
this, SLOT(errored(SimpleHttpClient::ErrorType)));
|
2025-02-01 11:33:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FeedDataProvider::downloadFinished()
|
|
|
|
|
{
|
2025-11-17 11:57:50 +01:00
|
|
|
if (m_httpClient->request().method() == boost::beast::http::verb::head) {
|
|
|
|
|
const auto lastModified = m_httpClient->headerDate(boost::beast::http::field::last_modified);
|
|
|
|
|
m_httpClient.reset();
|
2025-02-01 11:33:18 +01:00
|
|
|
// check if the server has a newer one.
|
2025-11-17 11:57:50 +01:00
|
|
|
if (lastModified > m_lastCheck) {
|
2025-02-01 11:33:18 +01:00
|
|
|
m_lastCheck = QDateTime();
|
|
|
|
|
assert(m_lastCheck.isNull());
|
|
|
|
|
start(); // this will now do a download of the actual data.
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-11-17 11:57:50 +01:00
|
|
|
if (m_httpClient->httpErrorCode() == 200) {
|
|
|
|
|
auto data = m_httpClient->responseBody();
|
|
|
|
|
QFile feed(FLOWEE_JSON);
|
|
|
|
|
if (feed.open(QIODevice::WriteOnly)) {
|
|
|
|
|
feed.write(data.begin(), data.size());
|
|
|
|
|
feed.close();
|
|
|
|
|
}
|
|
|
|
|
readFeed();
|
2025-02-01 11:33:18 +01:00
|
|
|
}
|
2025-11-17 11:57:50 +01:00
|
|
|
m_httpClient.reset();
|
2025-02-01 11:33:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FeedDataProvider::readFeed()
|
|
|
|
|
{
|
|
|
|
|
QFile feed(FLOWEE_JSON);
|
|
|
|
|
if (!feed.open(QIODevice::ReadOnly))
|
|
|
|
|
return;
|
|
|
|
|
auto data = feed.readAll();
|
|
|
|
|
feed.close();
|
|
|
|
|
QJsonDocument doc = QJsonDocument::fromJson(data);
|
|
|
|
|
if (doc.isNull()) {
|
|
|
|
|
logWarning() << "Parsing error of social json";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
m_listItems.clear();
|
|
|
|
|
QJsonArray list = doc.array();
|
|
|
|
|
for (auto i = list.begin(); i != list.end(); ++i) {
|
|
|
|
|
auto obj = i->toObject();
|
|
|
|
|
auto text = obj["text"];
|
|
|
|
|
if (!text.isString()) {
|
|
|
|
|
logWarning() << "Skipping item in JSON, missing text attribute";
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
auto *item = new ListItem(this);
|
|
|
|
|
item->m_text = text.toString();
|
|
|
|
|
item->m_url = obj["url"].toString();
|
|
|
|
|
item->m_videoLength = obj["length"].toString();
|
|
|
|
|
item->m_title = obj["title"].toString();
|
|
|
|
|
auto date = obj["date"].toString();
|
|
|
|
|
item->m_date = QDate::fromString(date, Qt::ISODate);
|
|
|
|
|
|
|
|
|
|
m_listItems.append(item);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
emit listItemsChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QList<ListItem *> FeedDataProvider::listItems() const
|
|
|
|
|
{
|
|
|
|
|
return m_listItems;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-17 11:57:50 +01:00
|
|
|
void FeedDataProvider::errored(SimpleHttpClient::ErrorType e)
|
2025-02-01 11:33:18 +01:00
|
|
|
{
|
2025-11-17 11:57:50 +01:00
|
|
|
logDebug() << "got error on downloading the feed:" << e;
|
|
|
|
|
if (m_httpClient.get())
|
|
|
|
|
logDebug() << " http error code:" << m_httpClient->httpErrorCode();
|
2025-02-01 11:33:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ------------------------------------
|
|
|
|
|
|
|
|
|
|
ListItem::ListItem(QObject *parent)
|
|
|
|
|
: QObject(parent)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QDate ListItem::date() const
|
|
|
|
|
{
|
|
|
|
|
return m_date;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString ListItem::videoLength() const
|
|
|
|
|
{
|
|
|
|
|
return m_videoLength;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString ListItem::text() const
|
|
|
|
|
{
|
|
|
|
|
return m_text;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString ListItem::title() const
|
|
|
|
|
{
|
|
|
|
|
return m_title;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString ListItem::url() const
|
|
|
|
|
{
|
|
|
|
|
return m_url;
|
|
|
|
|
}
|