Added Pexels Media API
This commit is contained in:
25
plugin/PexelsImageMetadata.h
Normal file
25
plugin/PexelsImageMetadata.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#ifndef PEXELSIMAGEMETADATA_H
|
||||||
|
#define PEXELSIMAGEMETADATA_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QQmlEngine>
|
||||||
|
|
||||||
|
#include "Komplex_global.h"
|
||||||
|
|
||||||
|
struct KOMPLEX_EXPORT PexelsImageMetadata
|
||||||
|
{
|
||||||
|
QString alt;
|
||||||
|
QString averageColorCode;
|
||||||
|
quint64 height = 0;
|
||||||
|
quint64 id = 0;
|
||||||
|
bool liked = false;
|
||||||
|
QString photographer;
|
||||||
|
QUrl photographerUrl;
|
||||||
|
quint64 photographerId = 0;
|
||||||
|
QMap<QString,QUrl> sources;
|
||||||
|
QUrl thumbnail;
|
||||||
|
QUrl url;
|
||||||
|
quint64 width = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PEXELSIMAGEMETADATA_H
|
||||||
386
plugin/PexelsImageSearch.cpp
Normal file
386
plugin/PexelsImageSearch.cpp
Normal file
@@ -0,0 +1,386 @@
|
|||||||
|
#include "PexelsImageSearch.h"
|
||||||
|
#include "PexelsAPI.h"
|
||||||
|
|
||||||
|
PexelsImageSearchModel::PexelsImageSearchModel(QObject *parent) : QAbstractItemModel { parent }
|
||||||
|
{
|
||||||
|
m_networkManager.setAutoDeleteReplies(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
PexelsImageSearchModel::~PexelsImageSearchModel()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int PexelsImageSearchModel::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(parent)
|
||||||
|
return m_data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant PexelsImageSearchModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if(index.row() < 0 || index.row() >= m_data.count())
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
QVariant data;
|
||||||
|
|
||||||
|
switch (static_cast<DataRoles>(role)) {
|
||||||
|
case Alt:
|
||||||
|
data = QVariant::fromValue<QString>(m_data[index.row()].alt);
|
||||||
|
break;
|
||||||
|
case AverageColor:
|
||||||
|
data = QVariant::fromValue<QString>(m_data[index.row()].averageColorCode);
|
||||||
|
break;
|
||||||
|
case Height:
|
||||||
|
data = QVariant::fromValue<quint64>(m_data[index.row()].height);
|
||||||
|
break;
|
||||||
|
case Id:
|
||||||
|
data = QVariant::fromValue<quint64>(m_data[index.row()].id);
|
||||||
|
break;
|
||||||
|
case Liked:
|
||||||
|
data = QVariant::fromValue<bool>(m_data[index.row()].liked);
|
||||||
|
break;
|
||||||
|
case Photographer:
|
||||||
|
data = QVariant::fromValue<QString>(m_data[index.row()].photographer);
|
||||||
|
break;
|
||||||
|
case PhotographerUrl:
|
||||||
|
data = QVariant::fromValue<QUrl>(m_data[index.row()].photographerUrl);
|
||||||
|
break;
|
||||||
|
case PhotographerId:
|
||||||
|
data = QVariant::fromValue<quint64>(m_data[index.row()].photographerId);
|
||||||
|
break;
|
||||||
|
case Thumbnail:
|
||||||
|
data = QVariant::fromValue<QUrl>(m_data[index.row()].thumbnail);
|
||||||
|
break;
|
||||||
|
case Url:
|
||||||
|
data = QVariant::fromValue<QUrl>(m_data[index.row()].url);
|
||||||
|
break;
|
||||||
|
case Width:
|
||||||
|
data = QVariant::fromValue<quint64>(m_data[index.row()].width);
|
||||||
|
break;
|
||||||
|
case Original:
|
||||||
|
case Large2x:
|
||||||
|
case Large:
|
||||||
|
case Medium:
|
||||||
|
case Small:
|
||||||
|
case Portrait:
|
||||||
|
case Landscape:
|
||||||
|
if(m_data[index.row()].sources.contains(QString::fromUtf8(m_dataRoles[role])))
|
||||||
|
data = QVariant::fromValue<QUrl>(m_data[index.row()].sources[QString::fromUtf8(m_dataRoles[role])]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<int, QByteArray> PexelsImageSearchModel::roleNames() const
|
||||||
|
{
|
||||||
|
return m_dataRoles;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsImageSearchModel::getSearchResults(QString url)
|
||||||
|
{
|
||||||
|
setStatus(Searching);
|
||||||
|
|
||||||
|
QNetworkRequest request;
|
||||||
|
request.setRawHeader(QStringLiteral("Authorization").toLatin1(), QStringLiteral(PAK).toLatin1());
|
||||||
|
request.setUrl(QUrl(url));
|
||||||
|
|
||||||
|
QNetworkReply *reply = m_networkManager.get(request);
|
||||||
|
|
||||||
|
QObject::connect
|
||||||
|
(
|
||||||
|
reply,
|
||||||
|
&QNetworkReply::finished,
|
||||||
|
this,
|
||||||
|
[this, reply]()
|
||||||
|
{
|
||||||
|
if(reply->error())
|
||||||
|
qWarning() << reply->errorString();
|
||||||
|
|
||||||
|
QByteArray data = reply->readAll();
|
||||||
|
QJsonParseError jsonError;
|
||||||
|
|
||||||
|
QJsonDocument document = QJsonDocument::fromJson(data, &jsonError);
|
||||||
|
|
||||||
|
if(jsonError.error != QJsonParseError::NoError)
|
||||||
|
{
|
||||||
|
qWarning() << jsonError.errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject rootObject = document.object();
|
||||||
|
|
||||||
|
if(rootObject.contains(QStringLiteral("prev_page")) && rootObject[QStringLiteral("prev_page")].isString())
|
||||||
|
setPreviousPage(rootObject[QStringLiteral("prev_page")].toString());
|
||||||
|
else
|
||||||
|
setPreviousPage(QString());
|
||||||
|
|
||||||
|
if(rootObject.contains(QStringLiteral("next_page")) && rootObject[QStringLiteral("next_page")].isString())
|
||||||
|
setNextPage(rootObject[QStringLiteral("next_page")].toString());
|
||||||
|
else
|
||||||
|
setNextPage(QString());
|
||||||
|
|
||||||
|
if(rootObject.contains(QStringLiteral("page")))
|
||||||
|
setCurrentPage(rootObject[QStringLiteral("page")].toInt());
|
||||||
|
else
|
||||||
|
setCurrentPage(0);
|
||||||
|
|
||||||
|
if(rootObject.contains(QStringLiteral("total_results")))
|
||||||
|
setTotalResults(rootObject[QStringLiteral("total_results")].toInt());
|
||||||
|
else
|
||||||
|
setTotalResults(0);
|
||||||
|
|
||||||
|
beginResetModel();
|
||||||
|
m_data.clear();
|
||||||
|
endResetModel();
|
||||||
|
|
||||||
|
if(rootObject.contains(QStringLiteral("photos")) && rootObject[QStringLiteral("photos")].isArray())
|
||||||
|
{
|
||||||
|
QJsonArray photoArray = rootObject[QStringLiteral("photos")].toArray();
|
||||||
|
|
||||||
|
beginInsertRows(QModelIndex(), 0, photoArray.count() - 1);
|
||||||
|
|
||||||
|
for(const QJsonValue &photoRef : std::as_const(photoArray))
|
||||||
|
{
|
||||||
|
if(!photoRef.isObject())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
QJsonObject photoObject = photoRef.toObject();
|
||||||
|
PexelsImageMetadata photo;
|
||||||
|
|
||||||
|
photo.id = photoObject[QStringLiteral("id")].toInt();
|
||||||
|
photo.photographer = photoObject[QStringLiteral("photographer")].toString();
|
||||||
|
photo.photographerId = photoObject[QStringLiteral("photographer_id")].toInt();
|
||||||
|
photo.photographerUrl = QUrl(photoObject[QStringLiteral("photographer_url")].toString());
|
||||||
|
photo.averageColorCode = photoObject[QStringLiteral("avg_color")].toString();
|
||||||
|
photo.alt = photoObject[QStringLiteral("alt")].toString();
|
||||||
|
photo.width = photoObject[QStringLiteral("width")].toInt();
|
||||||
|
photo.height = photoObject[QStringLiteral("height")].toInt();
|
||||||
|
photo.url = QUrl(photoObject[QStringLiteral("url")].toString());
|
||||||
|
photo.liked = photoObject[QStringLiteral("liked")].toBool();
|
||||||
|
|
||||||
|
if(photoObject.contains(QStringLiteral("src")) && photoObject[QStringLiteral("src")].isObject())
|
||||||
|
{
|
||||||
|
QJsonObject sourceObject = photoObject[QStringLiteral("src")].toObject();
|
||||||
|
QStringList keys = sourceObject.keys();
|
||||||
|
|
||||||
|
for(const QString &key : std::as_const(keys))
|
||||||
|
{
|
||||||
|
if(key == QStringLiteral("tiny"))
|
||||||
|
photo.thumbnail = QUrl(sourceObject[key].toString());
|
||||||
|
|
||||||
|
photo.sources.insert(key, QUrl(sourceObject[key].toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_data.append(photo);
|
||||||
|
}
|
||||||
|
|
||||||
|
endInsertRows();
|
||||||
|
setStatus(Idle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
int PexelsImageSearchModel::status() const
|
||||||
|
{
|
||||||
|
return static_cast<int>(m_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsImageSearchModel::setStatus(const int &status)
|
||||||
|
{
|
||||||
|
if (m_status == static_cast<Status>(status))
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_status = static_cast<Status>(status);
|
||||||
|
Q_EMIT statusChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString PexelsImageSearchModel::lastSavedFile() const
|
||||||
|
{
|
||||||
|
return m_lastSavedFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsImageSearchModel::setLastSavedFile(const QString &lastSavedFile)
|
||||||
|
{
|
||||||
|
if (m_lastSavedFile == lastSavedFile)
|
||||||
|
return;
|
||||||
|
m_lastSavedFile = lastSavedFile;
|
||||||
|
Q_EMIT lastSavedFileChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal PexelsImageSearchModel::downloadProgress() const
|
||||||
|
{
|
||||||
|
return m_downloadProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsImageSearchModel::setDownloadProgress(qreal downloadProgress)
|
||||||
|
{
|
||||||
|
if (m_downloadProgress == downloadProgress)
|
||||||
|
return;
|
||||||
|
m_downloadProgress = downloadProgress;
|
||||||
|
Q_EMIT downloadProgressChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 PexelsImageSearchModel::currentPage() const
|
||||||
|
{
|
||||||
|
return m_currentPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsImageSearchModel::setCurrentPage(quint64 currentPage)
|
||||||
|
{
|
||||||
|
if (m_currentPage == currentPage)
|
||||||
|
return;
|
||||||
|
m_currentPage = currentPage;
|
||||||
|
Q_EMIT currentPageChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex PexelsImageSearchModel::index(int row, int column, const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(parent)
|
||||||
|
return createIndex(row, column, &m_data.at(row));
|
||||||
|
}
|
||||||
|
|
||||||
|
int PexelsImageSearchModel::columnCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(parent)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex PexelsImageSearchModel::parent(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(index)
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsImageSearchModel::next()
|
||||||
|
{
|
||||||
|
if(m_nextPage.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
getSearchResults(m_nextPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsImageSearchModel::back()
|
||||||
|
{
|
||||||
|
if(m_previousPage.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
getSearchResults(m_previousPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsImageSearchModel::download(QUrl url, quint64 id)
|
||||||
|
{
|
||||||
|
QNetworkRequest request(url);
|
||||||
|
QNetworkReply *reply = m_networkManager.get(request);
|
||||||
|
|
||||||
|
QObject::connect
|
||||||
|
(
|
||||||
|
reply,
|
||||||
|
&QNetworkReply::finished,
|
||||||
|
this,
|
||||||
|
[this, reply, id]()
|
||||||
|
{
|
||||||
|
if(reply->error())
|
||||||
|
qWarning() << reply->errorString();
|
||||||
|
|
||||||
|
QByteArray data = reply->readAll();
|
||||||
|
QPixmap pixmap;
|
||||||
|
pixmap.loadFromData(data);
|
||||||
|
|
||||||
|
if(pixmap.isNull())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QString fileLocation = QStringLiteral("%1/.local/share/komplex/images/%2.png").arg(QStandardPaths::writableLocation(QStandardPaths::HomeLocation), QString::number(id));
|
||||||
|
|
||||||
|
if(!pixmap.save(fileLocation, "PNG"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
setLastSavedFile(fileLocation);
|
||||||
|
|
||||||
|
Q_EMIT downloadFinished();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
QObject::connect
|
||||||
|
(
|
||||||
|
reply,
|
||||||
|
&QNetworkReply::downloadProgress,
|
||||||
|
this,
|
||||||
|
[this](qint64 received, qint64 total)
|
||||||
|
{
|
||||||
|
setDownloadProgress(static_cast<qreal>(received) / static_cast<qreal>(total));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString PexelsImageSearchModel::previousPage() const
|
||||||
|
{
|
||||||
|
return m_previousPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsImageSearchModel::setPreviousPage(const QString &previousPage)
|
||||||
|
{
|
||||||
|
if (m_previousPage == previousPage)
|
||||||
|
return;
|
||||||
|
m_previousPage = previousPage;
|
||||||
|
Q_EMIT previousPageChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString PexelsImageSearchModel::nextPage() const
|
||||||
|
{
|
||||||
|
return m_nextPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsImageSearchModel::setNextPage(const QString &nextPage)
|
||||||
|
{
|
||||||
|
if (m_nextPage == nextPage)
|
||||||
|
return;
|
||||||
|
m_nextPage = nextPage;
|
||||||
|
Q_EMIT nextPageChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 PexelsImageSearchModel::totalResults() const
|
||||||
|
{
|
||||||
|
return m_totalResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsImageSearchModel::setTotalResults(quint64 totalResults)
|
||||||
|
{
|
||||||
|
if (m_totalResults == totalResults)
|
||||||
|
return;
|
||||||
|
m_totalResults = totalResults;
|
||||||
|
Q_EMIT totalResultsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
quint16 PexelsImageSearchModel::resultsPerPage() const
|
||||||
|
{
|
||||||
|
return m_resultsPerPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsImageSearchModel::setResultsPerPage(quint16 resultsPerPage)
|
||||||
|
{
|
||||||
|
if (m_resultsPerPage == resultsPerPage)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_resultsPerPage = resultsPerPage;
|
||||||
|
Q_EMIT resultsPerPageChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString PexelsImageSearchModel::query() const
|
||||||
|
{
|
||||||
|
return m_query;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsImageSearchModel::setQuery(const QString &query)
|
||||||
|
{
|
||||||
|
if (m_query == query)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_query = query;
|
||||||
|
Q_EMIT queryChanged();
|
||||||
|
|
||||||
|
getSearchResults(QStringLiteral("https://api.pexels.com/v1/search?query=%1&per_page=%2").arg(m_query).arg(m_resultsPerPage));
|
||||||
|
}
|
||||||
216
plugin/PexelsImageSearch.h
Normal file
216
plugin/PexelsImageSearch.h
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
#ifndef PexelsImageSearch_H
|
||||||
|
#define PexelsImageSearch_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QCache>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include <QQuickImageProvider>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonParseError>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonValue>
|
||||||
|
|
||||||
|
#include "PexelsImageMetadata.h"
|
||||||
|
#include "Komplex_global.h"
|
||||||
|
|
||||||
|
class KOMPLEX_EXPORT PexelsImageSearchModel : public QAbstractItemModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum DataRoles
|
||||||
|
{
|
||||||
|
Alt = Qt::UserRole + 1,
|
||||||
|
AverageColor,
|
||||||
|
Height,
|
||||||
|
Id,
|
||||||
|
Liked,
|
||||||
|
Photographer,
|
||||||
|
PhotographerId,
|
||||||
|
PhotographerUrl,
|
||||||
|
Thumbnail,
|
||||||
|
Url,
|
||||||
|
Width,
|
||||||
|
Original,
|
||||||
|
Large2x,
|
||||||
|
Large,
|
||||||
|
Medium,
|
||||||
|
Small,
|
||||||
|
Portrait,
|
||||||
|
Landscape
|
||||||
|
};
|
||||||
|
Q_ENUM(DataRoles)
|
||||||
|
|
||||||
|
enum Status
|
||||||
|
{
|
||||||
|
Idle,
|
||||||
|
Searching
|
||||||
|
};
|
||||||
|
Q_ENUM(Status)
|
||||||
|
|
||||||
|
PexelsImageSearchModel(QObject *parent = nullptr);
|
||||||
|
~PexelsImageSearchModel();
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
QString query() const;
|
||||||
|
void setQuery(const QString &query);
|
||||||
|
|
||||||
|
quint16 resultsPerPage() const;
|
||||||
|
void setResultsPerPage(quint16 resultsPerPage);
|
||||||
|
|
||||||
|
quint64 totalResults() const;
|
||||||
|
void setTotalResults(quint64 totalResults);
|
||||||
|
|
||||||
|
QString nextPage() const;
|
||||||
|
void setNextPage(const QString &nextPage);
|
||||||
|
|
||||||
|
QString previousPage() const;
|
||||||
|
void setPreviousPage(const QString &previousPage);
|
||||||
|
|
||||||
|
quint64 currentPage() const;
|
||||||
|
void setCurrentPage(quint64 currentPage);
|
||||||
|
|
||||||
|
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
QModelIndex parent(const QModelIndex &index) const override;
|
||||||
|
|
||||||
|
Q_INVOKABLE void next();
|
||||||
|
Q_INVOKABLE void back();
|
||||||
|
Q_INVOKABLE void download(QUrl url, quint64 id);
|
||||||
|
|
||||||
|
qreal downloadProgress() const;
|
||||||
|
void setDownloadProgress(qreal downloadProgress);
|
||||||
|
|
||||||
|
QString lastSavedFile() const;
|
||||||
|
void setLastSavedFile(const QString &lastSavedFile);
|
||||||
|
|
||||||
|
int status() const;
|
||||||
|
void setStatus(const int &status);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void queryChanged();
|
||||||
|
void resultsPerPageChanged();
|
||||||
|
void totalResultsChanged();
|
||||||
|
void nextPageChanged();
|
||||||
|
void previousPageChanged();
|
||||||
|
void currentPageChanged();
|
||||||
|
void downloadProgressChanged();
|
||||||
|
void downloadFinished();
|
||||||
|
void lastSavedFileChanged();
|
||||||
|
void statusChanged();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void getSearchResults(QString url);
|
||||||
|
|
||||||
|
QNetworkAccessManager m_networkManager;
|
||||||
|
QString m_query;
|
||||||
|
|
||||||
|
quint16 m_resultsPerPage = 9;
|
||||||
|
quint64 m_totalResults = 0;
|
||||||
|
quint64 m_currentPage = 0;
|
||||||
|
qreal m_downloadProgress = 0;
|
||||||
|
QString m_nextPage;
|
||||||
|
QString m_previousPage;
|
||||||
|
QString m_lastSavedFile;
|
||||||
|
|
||||||
|
QList<PexelsImageMetadata> m_data;
|
||||||
|
Status m_status = Status::Idle;
|
||||||
|
|
||||||
|
static inline const QHash<int, QByteArray> m_dataRoles =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
static_cast<int>(Alt),
|
||||||
|
QByteArray("alt")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(AverageColor),
|
||||||
|
QByteArray("averageColor")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Height),
|
||||||
|
QByteArray("imageHeight")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Id),
|
||||||
|
QByteArray("id")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Liked),
|
||||||
|
QByteArray("liked")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Photographer),
|
||||||
|
QByteArray("photographer")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(PhotographerId),
|
||||||
|
QByteArray("photographerId")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(PhotographerUrl),
|
||||||
|
QByteArray("photographerUrl")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Thumbnail),
|
||||||
|
QByteArray("thumbnail")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Url),
|
||||||
|
QByteArray("url")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Width),
|
||||||
|
QByteArray("imageWidth")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Original),
|
||||||
|
QByteArray("original")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Large2x),
|
||||||
|
QByteArray("large2x")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Large),
|
||||||
|
QByteArray("large")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Medium),
|
||||||
|
QByteArray("medium")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Small),
|
||||||
|
QByteArray("small")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Portrait),
|
||||||
|
QByteArray("portrait")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Landscape),
|
||||||
|
QByteArray("landscape")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_PROPERTY(QString query READ query WRITE setQuery NOTIFY queryChanged FINAL)
|
||||||
|
Q_PROPERTY(quint16 resultsPerPage READ resultsPerPage WRITE setResultsPerPage NOTIFY resultsPerPageChanged FINAL)
|
||||||
|
Q_PROPERTY(quint64 totalResults READ totalResults WRITE setTotalResults NOTIFY totalResultsChanged FINAL)
|
||||||
|
Q_PROPERTY(QString nextPage READ nextPage WRITE setNextPage NOTIFY nextPageChanged FINAL)
|
||||||
|
Q_PROPERTY(QString previousPage READ previousPage WRITE setPreviousPage NOTIFY previousPageChanged FINAL)
|
||||||
|
Q_PROPERTY(quint64 currentPage READ currentPage WRITE setCurrentPage NOTIFY currentPageChanged FINAL)
|
||||||
|
Q_PROPERTY(qreal downloadProgress READ downloadProgress WRITE setDownloadProgress NOTIFY downloadProgressChanged FINAL)
|
||||||
|
Q_PROPERTY(QString lastSavedFile READ lastSavedFile WRITE setLastSavedFile NOTIFY lastSavedFileChanged FINAL)
|
||||||
|
Q_PROPERTY(int status READ status WRITE setStatus NOTIFY statusChanged FINAL)
|
||||||
|
};
|
||||||
|
Q_DECLARE_METATYPE(PexelsImageSearchModel)
|
||||||
|
#endif // PexelsImageSearch_H
|
||||||
63
plugin/PexelsVideoMetadata.h
Normal file
63
plugin/PexelsVideoMetadata.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#ifndef Metadata_H
|
||||||
|
#define Metadata_H
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "Komplex_global.h"
|
||||||
|
|
||||||
|
struct KOMPLEX_EXPORT PexelsVideoThumbnail
|
||||||
|
{
|
||||||
|
quint64 id = 0;
|
||||||
|
quint64 nr = 0;
|
||||||
|
|
||||||
|
QString image;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct KOMPLEX_EXPORT PexelsVideoMetadata
|
||||||
|
{
|
||||||
|
quint64 id = 0;
|
||||||
|
quint64 width = 0;
|
||||||
|
quint64 height = 0;
|
||||||
|
quint64 size = 0;
|
||||||
|
qreal fps;
|
||||||
|
QString quality;
|
||||||
|
QString type;
|
||||||
|
QString link;
|
||||||
|
QString sizeText;
|
||||||
|
|
||||||
|
// bool operator==(const PexelsVideoMetadata &other) const
|
||||||
|
// {
|
||||||
|
// return ((id == other.id) && (height == other.height) &&
|
||||||
|
// (fps == other.fps) && (link == other.link) &&
|
||||||
|
// (quality == other.quality) && (type == other.type) &&
|
||||||
|
// (width == other.width) && (size == other.size) &&
|
||||||
|
// (sizeText == other.sizeText));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// bool operator!=(const PexelsVideoMetadata &other) const
|
||||||
|
// {
|
||||||
|
// return !(*this == other);
|
||||||
|
// }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct KOMPLEX_EXPORT PexelsVideoUser
|
||||||
|
{
|
||||||
|
quint64 id;
|
||||||
|
QString name;
|
||||||
|
QString url;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct KOMPLEX_EXPORT PexelsVideoEntry
|
||||||
|
{
|
||||||
|
quint64 id = 0;
|
||||||
|
quint64 width = 0;
|
||||||
|
quint64 height = 0;
|
||||||
|
quint64 duration = 0;
|
||||||
|
QString url;
|
||||||
|
QString image;
|
||||||
|
QStringList tags;
|
||||||
|
PexelsVideoUser author;
|
||||||
|
QList<PexelsVideoMetadata> videos;
|
||||||
|
QList<PexelsVideoThumbnail> thumbnails;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // Metadata_H
|
||||||
293
plugin/PexelsVideoModel.cpp
Normal file
293
plugin/PexelsVideoModel.cpp
Normal file
@@ -0,0 +1,293 @@
|
|||||||
|
#include "PexelsVideoModel.h"
|
||||||
|
#include <qeventloop.h>
|
||||||
|
|
||||||
|
PexelsVideoEntryModel::PexelsVideoEntryModel(QObject *parent)
|
||||||
|
: QAbstractItemModel{parent}
|
||||||
|
{
|
||||||
|
m_networkManager.setAutoDeleteReplies(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int PexelsVideoEntryModel::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(parent)
|
||||||
|
return m_data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant PexelsVideoEntryModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if(index.row() < 0 || index.row() >= m_data.count())
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
QVariant data;
|
||||||
|
|
||||||
|
switch (static_cast<DataRoles>(role))
|
||||||
|
{
|
||||||
|
case Fps:
|
||||||
|
data = QVariant::fromValue(m_data[index.row()].fps);
|
||||||
|
break;
|
||||||
|
case Height:
|
||||||
|
data = QVariant::fromValue(m_data[index.row()].height);
|
||||||
|
break;
|
||||||
|
case Id:
|
||||||
|
data = QVariant::fromValue(m_data[index.row()].id);
|
||||||
|
break;
|
||||||
|
case Url:
|
||||||
|
data = QVariant::fromValue(m_data[index.row()].link);
|
||||||
|
break;
|
||||||
|
case Width:
|
||||||
|
data = QVariant::fromValue(m_data[index.row()].width);
|
||||||
|
break;
|
||||||
|
case Type:
|
||||||
|
data = QVariant::fromValue(m_data[index.row()].type);
|
||||||
|
break;
|
||||||
|
case Quality:
|
||||||
|
data = QVariant::fromValue(m_data[index.row()].quality);
|
||||||
|
break;
|
||||||
|
case Text:
|
||||||
|
data = QVariant::fromValue(QStringLiteral("%1 %2x%3 (%4)").arg(m_data[index.row()].quality.toUpper(),QString::number(m_data[index.row()].width),QString::number(m_data[index.row()].height),m_data[index.row()].sizeText));
|
||||||
|
break;
|
||||||
|
case Size:
|
||||||
|
data = QVariant::fromValue(m_data[index.row()].size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<int, QByteArray> PexelsVideoEntryModel::roleNames() const
|
||||||
|
{
|
||||||
|
return m_dataRoles;
|
||||||
|
}
|
||||||
|
|
||||||
|
PexelsVideoEntryModel::Status PexelsVideoEntryModel::status() const
|
||||||
|
{
|
||||||
|
return m_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsVideoEntryModel::setStatus(const Status &status)
|
||||||
|
{
|
||||||
|
if (m_status == status)
|
||||||
|
return;
|
||||||
|
m_status = status;
|
||||||
|
Q_EMIT statusChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex PexelsVideoEntryModel::index(int row, int column, const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(parent)
|
||||||
|
return createIndex(row, column, &m_data.at(row));
|
||||||
|
}
|
||||||
|
|
||||||
|
int PexelsVideoEntryModel::columnCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(parent)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex PexelsVideoEntryModel::parent(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(index)
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsVideoEntryModel::setMetadata(const QList<PexelsVideoMetadata> &data)
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
m_data.clear();
|
||||||
|
endResetModel();
|
||||||
|
|
||||||
|
beginInsertRows(QModelIndex(), 0, data.count() - 1);
|
||||||
|
m_data = data;
|
||||||
|
endInsertRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PexelsVideoEntryModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||||
|
{
|
||||||
|
if(index.row() < 0 || index.row() >= m_data.count())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
PexelsVideoMetadata entry = m_data[index.row()];
|
||||||
|
|
||||||
|
switch(static_cast<DataRoles>(role))
|
||||||
|
{
|
||||||
|
case Fps:
|
||||||
|
entry.fps = value.toDouble();
|
||||||
|
break;
|
||||||
|
case Height:
|
||||||
|
entry.height = value.toInt();
|
||||||
|
break;
|
||||||
|
case Id:
|
||||||
|
entry.id = value.toInt();
|
||||||
|
break;
|
||||||
|
case Url:
|
||||||
|
entry.link = value.toString();
|
||||||
|
break;
|
||||||
|
case Width:
|
||||||
|
entry.width = value.toInt();
|
||||||
|
break;
|
||||||
|
case Type:
|
||||||
|
entry.type = value.toString();
|
||||||
|
break;
|
||||||
|
case Quality:
|
||||||
|
entry.quality = value.toString();
|
||||||
|
break;
|
||||||
|
case Text:
|
||||||
|
break;
|
||||||
|
case Size:
|
||||||
|
entry.size = value.toInt();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
beginInsertRows(index, index.row(), index.row());
|
||||||
|
m_data.replace(index.row(), entry);
|
||||||
|
endInsertRows();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsVideoEntryModel::download(quint64 index)
|
||||||
|
{
|
||||||
|
QNetworkRequest request(QUrl(m_data[index].link));
|
||||||
|
QNetworkReply *reply = m_networkManager.get(request);
|
||||||
|
|
||||||
|
QObject::connect
|
||||||
|
(
|
||||||
|
reply,
|
||||||
|
&QNetworkReply::finished,
|
||||||
|
this,
|
||||||
|
[this, reply, index]()
|
||||||
|
{
|
||||||
|
if(reply->error())
|
||||||
|
qWarning() << reply->errorString();
|
||||||
|
|
||||||
|
QByteArray data = reply->readAll();
|
||||||
|
QString fileLocation = QStringLiteral("%1/.local/share/komplex/videos/%2.%3").arg(QStandardPaths::writableLocation(QStandardPaths::HomeLocation), QString::number(m_data[index].id), m_data[index].type.mid(m_data[index].type.lastIndexOf(QLatin1Char('/')) + 1));
|
||||||
|
QFile file(fileLocation);
|
||||||
|
|
||||||
|
if(!file.open(QFile::WriteOnly))
|
||||||
|
{
|
||||||
|
qWarning() << QStringLiteral("Could not download file");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 bytesWritten = file.write(data);
|
||||||
|
|
||||||
|
if(static_cast<qsizetype>(bytesWritten) != data.length())
|
||||||
|
qWarning() << QStringLiteral("Could not save file. %1 of %2").arg(bytesWritten).arg(data.length());
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
setLastSavedFile(fileLocation);
|
||||||
|
|
||||||
|
Q_EMIT downloadFinished();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
QObject::connect
|
||||||
|
(
|
||||||
|
reply,
|
||||||
|
&QNetworkReply::downloadProgress,
|
||||||
|
this,
|
||||||
|
[this](qint64 received, qint64 total)
|
||||||
|
{
|
||||||
|
setDownloadProgress(static_cast<qreal>(received) / static_cast<qreal>(total));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsVideoEntryModel::update()
|
||||||
|
{
|
||||||
|
setStatus(Loading);
|
||||||
|
|
||||||
|
for(int i = 0; i < m_data.count(); ++i)
|
||||||
|
{
|
||||||
|
m_data[i].size = getFileSize(QUrl(m_data[i].link));
|
||||||
|
m_data[i].sizeText = sizeText(m_data[i].size);
|
||||||
|
QThread::msleep(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
setStatus(Idle);
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal PexelsVideoEntryModel::downloadProgress() const
|
||||||
|
{
|
||||||
|
return m_downloadProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsVideoEntryModel::setDownloadProgress(qreal downloadProgress)
|
||||||
|
{
|
||||||
|
if (qFuzzyCompare(m_downloadProgress, downloadProgress))
|
||||||
|
return;
|
||||||
|
m_downloadProgress = downloadProgress;
|
||||||
|
Q_EMIT downloadProgressChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString PexelsVideoEntryModel::lastSavedFile() const
|
||||||
|
{
|
||||||
|
return m_lastSavedFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsVideoEntryModel::setLastSavedFile(const QString &lastSavedFile)
|
||||||
|
{
|
||||||
|
if (m_lastSavedFile == lastSavedFile)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_lastSavedFile = lastSavedFile;
|
||||||
|
Q_EMIT lastSavedFileChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 PexelsVideoEntryModel::getFileSize(QUrl url)
|
||||||
|
{
|
||||||
|
quint64 size = 0;
|
||||||
|
|
||||||
|
QEventLoop loop;
|
||||||
|
|
||||||
|
QNetworkRequest request;
|
||||||
|
request.setUrl(url);
|
||||||
|
|
||||||
|
QNetworkReply *reply = m_networkManager.head(request);
|
||||||
|
QObject::connect(
|
||||||
|
reply,
|
||||||
|
&QNetworkReply::finished,
|
||||||
|
this,
|
||||||
|
[reply, &loop, &size]()
|
||||||
|
{
|
||||||
|
if(reply->error())
|
||||||
|
{
|
||||||
|
qWarning() << QStringLiteral("Failed to download header for file size");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(reply->hasRawHeader(QStringLiteral("Content-Length")))
|
||||||
|
{
|
||||||
|
QByteArray headerData = reply->rawHeader(QStringLiteral("Content-Length"));
|
||||||
|
|
||||||
|
if(!headerData.isValidUtf8())
|
||||||
|
{
|
||||||
|
qWarning() << QStringLiteral("Invalid header data format");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString data = QString::fromUtf8(headerData);
|
||||||
|
size = data.toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
loop.quit();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if(!reply->isFinished())
|
||||||
|
loop.exec();
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString PexelsVideoEntryModel::sizeText(quint64 size)
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
for(;index < m_sizeSuffix.count() && size >= 1000; index++)
|
||||||
|
size /= 1000;
|
||||||
|
|
||||||
|
return QStringLiteral("%1%2").arg(QString::number(size), m_sizeSuffix[index]);
|
||||||
|
}
|
||||||
149
plugin/PexelsVideoModel.h
Normal file
149
plugin/PexelsVideoModel.h
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
#ifndef PexelsVideoEntryModel_H
|
||||||
|
#define PexelsVideoEntryModel_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include <QQuickImageProvider>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonParseError>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonValue>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
|
#include "PexelsVideoMetadata.h"
|
||||||
|
#include "Komplex_global.h"
|
||||||
|
|
||||||
|
|
||||||
|
class KOMPLEX_EXPORT PexelsVideoEntryModel : public QAbstractItemModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum DataRoles
|
||||||
|
{
|
||||||
|
Type = Qt::UserRole + 1,
|
||||||
|
Height,
|
||||||
|
Id,
|
||||||
|
Quality,
|
||||||
|
Url,
|
||||||
|
Width,
|
||||||
|
Fps,
|
||||||
|
Size,
|
||||||
|
Text
|
||||||
|
};
|
||||||
|
Q_ENUM(DataRoles)
|
||||||
|
|
||||||
|
enum Status
|
||||||
|
{
|
||||||
|
Idle,
|
||||||
|
Loading
|
||||||
|
};
|
||||||
|
Q_ENUM(Status)
|
||||||
|
|
||||||
|
PexelsVideoEntryModel(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
QModelIndex parent(const QModelIndex &index) const override;
|
||||||
|
|
||||||
|
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
|
||||||
|
void setMetadata(const QList<PexelsVideoMetadata> &data);
|
||||||
|
|
||||||
|
QString lastSavedFile() const;
|
||||||
|
void setLastSavedFile(const QString &lastSavedFile);
|
||||||
|
|
||||||
|
qreal downloadProgress() const;
|
||||||
|
void setDownloadProgress(qreal downloadProgress);
|
||||||
|
Q_INVOKABLE void download(quint64 index);
|
||||||
|
Q_INVOKABLE void update();
|
||||||
|
|
||||||
|
Status status() const;
|
||||||
|
void setStatus(const Status &status);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void downloadProgressChanged();
|
||||||
|
void downloadFinished();
|
||||||
|
void lastSavedFileChanged();
|
||||||
|
void statusChanged();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
quint64 getFileSize(QUrl url);
|
||||||
|
QString sizeText(quint64 size);
|
||||||
|
|
||||||
|
QNetworkAccessManager m_networkManager;
|
||||||
|
QString m_query;
|
||||||
|
|
||||||
|
QList<PexelsVideoMetadata> m_data;
|
||||||
|
QString m_lastSavedFile;
|
||||||
|
qreal m_downloadProgress = 0;
|
||||||
|
Status m_status = Status::Idle;
|
||||||
|
|
||||||
|
static inline const QHash<int, QByteArray> m_dataRoles =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
static_cast<int>(Height),
|
||||||
|
QByteArray("videoHeight")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Id),
|
||||||
|
QByteArray("id")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Quality),
|
||||||
|
QByteArray("quality")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Url),
|
||||||
|
QByteArray("url")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Width),
|
||||||
|
QByteArray("videoWidth")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Fps),
|
||||||
|
QByteArray("fps")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Type),
|
||||||
|
QByteArray("videoType")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Text),
|
||||||
|
QByteArray("text")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Size),
|
||||||
|
QByteArray("size")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline const QStringList m_sizeSuffix =
|
||||||
|
{
|
||||||
|
QStringLiteral("B"),
|
||||||
|
QStringLiteral("KB"),
|
||||||
|
QStringLiteral("MB"),
|
||||||
|
QStringLiteral("GB"),
|
||||||
|
QStringLiteral("TB")
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_PROPERTY(QString lastSavedFile READ lastSavedFile WRITE setLastSavedFile NOTIFY lastSavedFileChanged FINAL)
|
||||||
|
Q_PROPERTY(qreal downloadProgress READ downloadProgress WRITE setDownloadProgress NOTIFY downloadProgressChanged FINAL)
|
||||||
|
Q_PROPERTY(Status status READ status WRITE setStatus NOTIFY statusChanged FINAL)
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(PexelsVideoEntryModel)
|
||||||
|
|
||||||
|
#endif // PexelsVideoEntryModel_H
|
||||||
383
plugin/PexelsVideoSearch.cpp
Normal file
383
plugin/PexelsVideoSearch.cpp
Normal file
@@ -0,0 +1,383 @@
|
|||||||
|
#include "PexelsVideoSearch.h"
|
||||||
|
#include "PexelsAPI.h"
|
||||||
|
#include <qeventloop.h>
|
||||||
|
|
||||||
|
PexelsVideoSearchModel::PexelsVideoSearchModel(QObject *parent) : QAbstractItemModel { parent }
|
||||||
|
{
|
||||||
|
// m_cache.setMaxCost(1024);
|
||||||
|
m_videoModel = new PexelsVideoEntryModel(this);
|
||||||
|
|
||||||
|
QObject::connect(m_videoModel, &PexelsVideoEntryModel::lastSavedFileChanged, this, &PexelsVideoSearchModel::lastSavedFileChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
PexelsVideoSearchModel::~PexelsVideoSearchModel()
|
||||||
|
{
|
||||||
|
if(m_videoModel)
|
||||||
|
m_videoModel->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
int PexelsVideoSearchModel::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(parent)
|
||||||
|
return m_data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant PexelsVideoSearchModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if(index.row() < 0 || index.row() >= m_data.count())
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
QVariant data;
|
||||||
|
|
||||||
|
switch (static_cast<DataRoles>(role)) {
|
||||||
|
case Tags:
|
||||||
|
data = QVariant::fromValue(m_data[index.row()].tags);
|
||||||
|
break;
|
||||||
|
case Height:
|
||||||
|
data = QVariant::fromValue(m_data[index.row()].height);
|
||||||
|
break;
|
||||||
|
case Id:
|
||||||
|
data = QVariant::fromValue(m_data[index.row()].id);
|
||||||
|
break;
|
||||||
|
case User:
|
||||||
|
data = QVariant::fromValue(m_data[index.row()].author.name);
|
||||||
|
break;
|
||||||
|
case UserId:
|
||||||
|
data = QVariant::fromValue(m_data[index.row()].author.id);
|
||||||
|
break;
|
||||||
|
case UserUrl:
|
||||||
|
data = QVariant::fromValue(m_data[index.row()].author.url);
|
||||||
|
break;
|
||||||
|
case Thumbnail:
|
||||||
|
if(m_data[index.row()].thumbnails.count() > 0)
|
||||||
|
data = QVariant::fromValue(m_data[index.row()].thumbnails[0].image);
|
||||||
|
break;
|
||||||
|
case Url:
|
||||||
|
data = QVariant::fromValue(m_data[index.row()].url);
|
||||||
|
break;
|
||||||
|
case Width:
|
||||||
|
data = QVariant::fromValue(m_data[index.row()].width);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<int, QByteArray> PexelsVideoSearchModel::roleNames() const
|
||||||
|
{
|
||||||
|
return m_dataRoles;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsVideoSearchModel::getSearchResults(QString url)
|
||||||
|
{
|
||||||
|
setStatus(Searching);
|
||||||
|
|
||||||
|
QNetworkRequest request;
|
||||||
|
request.setRawHeader(QStringLiteral("Authorization").toLatin1(), QStringLiteral(PAK).toLatin1());
|
||||||
|
request.setUrl(QUrl(url));
|
||||||
|
|
||||||
|
QNetworkReply *reply = m_networkManager.get(request);
|
||||||
|
|
||||||
|
QObject::connect
|
||||||
|
(
|
||||||
|
reply,
|
||||||
|
&QNetworkReply::finished,
|
||||||
|
this,
|
||||||
|
[this, reply]()
|
||||||
|
{
|
||||||
|
if(reply->error())
|
||||||
|
qWarning() << reply->errorString();
|
||||||
|
|
||||||
|
QByteArray data = reply->readAll();
|
||||||
|
QJsonParseError jsonError;
|
||||||
|
|
||||||
|
QJsonDocument document = QJsonDocument::fromJson(data, &jsonError);
|
||||||
|
|
||||||
|
if(jsonError.error != QJsonParseError::NoError)
|
||||||
|
{
|
||||||
|
qWarning() << jsonError.errorString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject rootObject = document.object();
|
||||||
|
|
||||||
|
if(rootObject.contains(QStringLiteral("prev_page")) && rootObject[QStringLiteral("prev_page")].isString())
|
||||||
|
setPreviousPage(rootObject[QStringLiteral("prev_page")].toString());
|
||||||
|
else
|
||||||
|
setPreviousPage(QString());
|
||||||
|
|
||||||
|
if(rootObject.contains(QStringLiteral("next_page")) && rootObject[QStringLiteral("next_page")].isString())
|
||||||
|
setNextPage(rootObject[QStringLiteral("next_page")].toString());
|
||||||
|
else
|
||||||
|
setNextPage(QString());
|
||||||
|
|
||||||
|
if(rootObject.contains(QStringLiteral("page")))
|
||||||
|
setCurrentPage(rootObject[QStringLiteral("page")].toInt());
|
||||||
|
else
|
||||||
|
setCurrentPage(0);
|
||||||
|
|
||||||
|
if(rootObject.contains(QStringLiteral("total_results")))
|
||||||
|
setTotalResults(rootObject[QStringLiteral("total_results")].toInt());
|
||||||
|
else
|
||||||
|
setTotalResults(0);
|
||||||
|
|
||||||
|
beginResetModel();
|
||||||
|
m_data.clear();
|
||||||
|
endResetModel();
|
||||||
|
|
||||||
|
if(rootObject.contains(QStringLiteral("videos")) && rootObject[QStringLiteral("videos")].isArray())
|
||||||
|
{
|
||||||
|
QJsonArray videoArray = rootObject[QStringLiteral("videos")].toArray();
|
||||||
|
|
||||||
|
beginInsertRows(QModelIndex(), 0, videoArray.count() - 1);
|
||||||
|
|
||||||
|
for(const QJsonValue &videoRef : std::as_const(videoArray))
|
||||||
|
{
|
||||||
|
if(!videoRef.isObject())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
QJsonObject videoObject = videoRef.toObject();
|
||||||
|
PexelsVideoEntry video;
|
||||||
|
|
||||||
|
video.id = videoObject[QStringLiteral("id")].toInt();
|
||||||
|
video.url = videoObject[QStringLiteral("url")].toString();
|
||||||
|
video.image = videoObject[QStringLiteral("image")].toString();
|
||||||
|
video.width = videoObject[QStringLiteral("width")].toInt();
|
||||||
|
video.height = videoObject[QStringLiteral("height")].toInt();
|
||||||
|
video.url = videoObject[QStringLiteral("url")].toString();
|
||||||
|
video.duration = videoObject[QStringLiteral("tags")].toInt();
|
||||||
|
|
||||||
|
if(videoObject.contains(QStringLiteral("tags")) && videoObject[QStringLiteral("tags")].isArray())
|
||||||
|
{
|
||||||
|
QJsonArray tagsArray = videoObject[QStringLiteral("tags")].toArray();
|
||||||
|
|
||||||
|
for(const QJsonValue &tagRef : std::as_const(tagsArray))
|
||||||
|
video.tags.append(tagRef.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(videoObject.contains(QStringLiteral("user")) && videoObject[QStringLiteral("user")].isObject())
|
||||||
|
{
|
||||||
|
QJsonObject userObject = videoObject[QStringLiteral("user")].toObject();
|
||||||
|
video.author.name = userObject[QStringLiteral("name")].toString();
|
||||||
|
video.author.id = userObject[QStringLiteral("id")].toInt();
|
||||||
|
video.author.url = userObject[QStringLiteral("url")].toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(videoObject.contains(QStringLiteral("video_files")) && videoObject[QStringLiteral("video_files")].isArray())
|
||||||
|
{
|
||||||
|
QJsonArray sourceObject = videoObject[QStringLiteral("video_files")].toArray();
|
||||||
|
|
||||||
|
for(const QJsonValue &sourceObject : std::as_const(sourceObject))
|
||||||
|
{
|
||||||
|
QJsonObject metaObject = sourceObject.toObject();
|
||||||
|
|
||||||
|
PexelsVideoMetadata metadata;
|
||||||
|
metadata.fps = metaObject[QStringLiteral("fps")].toDouble();
|
||||||
|
metadata.height = metaObject[QStringLiteral("height")].toInt();
|
||||||
|
metadata.id = metaObject[QStringLiteral("id")].toInt();
|
||||||
|
metadata.link = metaObject[QStringLiteral("link")].toString();
|
||||||
|
metadata.quality = metaObject[QStringLiteral("quality")].toString();
|
||||||
|
metadata.type = metaObject[QStringLiteral("file_type")].toString();
|
||||||
|
metadata.width = metaObject[QStringLiteral("width")].toInt();
|
||||||
|
|
||||||
|
video.videos.append(metadata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(videoObject.contains(QStringLiteral("video_pictures")) && videoObject[QStringLiteral("video_pictures")].isArray())
|
||||||
|
{
|
||||||
|
QJsonArray sourceObject = videoObject[QStringLiteral("video_pictures")].toArray();
|
||||||
|
|
||||||
|
for(const QJsonValue &sourceObject : std::as_const(sourceObject))
|
||||||
|
{
|
||||||
|
QJsonObject metaObject = sourceObject.toObject();
|
||||||
|
|
||||||
|
struct PexelsVideoThumbnail metadata;
|
||||||
|
metadata.image = metaObject[QStringLiteral("picture")].toString();
|
||||||
|
metadata.nr = metaObject[QStringLiteral("nr")].toInt();
|
||||||
|
metadata.id = metaObject[QStringLiteral("id")].toInt();
|
||||||
|
video.thumbnails.append(metadata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_data.append(video);
|
||||||
|
}
|
||||||
|
|
||||||
|
endInsertRows();
|
||||||
|
setCurrentIndex(0);
|
||||||
|
setStatus(Idle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString PexelsVideoSearchModel::sizeText(quint64 size)
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
for(;index < m_sizeSuffix.count() && size >= 1000; index++)
|
||||||
|
size /= 1000;
|
||||||
|
|
||||||
|
return QStringLiteral("%1%2").arg(QString::number(size), m_sizeSuffix[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 PexelsVideoSearchModel::currentIndex() const
|
||||||
|
{
|
||||||
|
return m_currentIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsVideoSearchModel::setCurrentIndex(quint64 currentIndex)
|
||||||
|
{
|
||||||
|
if (currentIndex < 0 || static_cast<qsizetype>(currentIndex) >= m_data.count())
|
||||||
|
{
|
||||||
|
m_videoModel->setMetadata(QList<PexelsVideoMetadata>());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_videoModel->setMetadata(m_data[currentIndex].videos);
|
||||||
|
|
||||||
|
m_currentIndex = currentIndex;
|
||||||
|
Q_EMIT currentIndexChanged();
|
||||||
|
Q_EMIT videoModelChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
PexelsVideoEntryModel *PexelsVideoSearchModel::videoModel() const
|
||||||
|
{
|
||||||
|
return m_videoModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PexelsVideoSearchModel::status() const
|
||||||
|
{
|
||||||
|
return static_cast<int>(m_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsVideoSearchModel::setStatus(const int &status)
|
||||||
|
{
|
||||||
|
if (m_status == static_cast<Status>(status))
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_status = static_cast<Status>(status);
|
||||||
|
Q_EMIT statusChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString PexelsVideoSearchModel::lastSavedFile() const
|
||||||
|
{
|
||||||
|
return m_videoModel->lastSavedFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 PexelsVideoSearchModel::currentPage() const
|
||||||
|
{
|
||||||
|
return m_currentPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsVideoSearchModel::setCurrentPage(quint64 currentPage)
|
||||||
|
{
|
||||||
|
if (m_currentPage == currentPage)
|
||||||
|
return;
|
||||||
|
m_currentPage = currentPage;
|
||||||
|
Q_EMIT currentPageChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex PexelsVideoSearchModel::index(int row, int column, const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(parent)
|
||||||
|
return createIndex(row, column, &m_data.at(row));
|
||||||
|
}
|
||||||
|
|
||||||
|
int PexelsVideoSearchModel::columnCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(parent)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex PexelsVideoSearchModel::parent(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(index)
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsVideoSearchModel::next()
|
||||||
|
{
|
||||||
|
if(m_nextPage.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
getSearchResults(m_nextPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsVideoSearchModel::back()
|
||||||
|
{
|
||||||
|
if(m_previousPage.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
getSearchResults(m_previousPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString PexelsVideoSearchModel::previousPage() const
|
||||||
|
{
|
||||||
|
return m_previousPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsVideoSearchModel::setPreviousPage(const QString &previousPage)
|
||||||
|
{
|
||||||
|
if (m_previousPage == previousPage)
|
||||||
|
return;
|
||||||
|
m_previousPage = previousPage;
|
||||||
|
Q_EMIT previousPageChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString PexelsVideoSearchModel::nextPage() const
|
||||||
|
{
|
||||||
|
return m_nextPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsVideoSearchModel::setNextPage(const QString &nextPage)
|
||||||
|
{
|
||||||
|
if (m_nextPage == nextPage)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_nextPage = nextPage;
|
||||||
|
Q_EMIT nextPageChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 PexelsVideoSearchModel::totalResults() const
|
||||||
|
{
|
||||||
|
return m_totalResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsVideoSearchModel::setTotalResults(quint64 totalResults)
|
||||||
|
{
|
||||||
|
if (m_totalResults == totalResults)
|
||||||
|
return;
|
||||||
|
m_totalResults = totalResults;
|
||||||
|
Q_EMIT totalResultsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
quint16 PexelsVideoSearchModel::resultsPerPage() const
|
||||||
|
{
|
||||||
|
return m_resultsPerPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsVideoSearchModel::setResultsPerPage(quint16 resultsPerPage)
|
||||||
|
{
|
||||||
|
if (m_resultsPerPage == resultsPerPage)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_resultsPerPage = resultsPerPage;
|
||||||
|
Q_EMIT resultsPerPageChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString PexelsVideoSearchModel::query() const
|
||||||
|
{
|
||||||
|
return m_query;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PexelsVideoSearchModel::setQuery(const QString &query)
|
||||||
|
{
|
||||||
|
if (m_query == query)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_query = query;
|
||||||
|
Q_EMIT queryChanged();
|
||||||
|
|
||||||
|
getSearchResults(QStringLiteral("https://api.pexels.com/videos/search?query=%1&per_page=%2").arg(QUrl::toPercentEncoding(m_query)).arg(m_resultsPerPage));
|
||||||
|
}
|
||||||
196
plugin/PexelsVideoSearch.h
Normal file
196
plugin/PexelsVideoSearch.h
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
#ifndef PEXELS_VIDEO_SEARCH_MODEL_H
|
||||||
|
#define PEXELS_VIDEO_SEARCH_MODEL_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QCache>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include <QQuickImageProvider>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonParseError>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonValue>
|
||||||
|
|
||||||
|
#include "PexelsVideoModel.h"
|
||||||
|
#include "PexelsVideoMetadata.h"
|
||||||
|
#include "Komplex_global.h"
|
||||||
|
|
||||||
|
class KOMPLEX_EXPORT PexelsVideoSearchModel : public QAbstractItemModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum DataRoles
|
||||||
|
{
|
||||||
|
Tags = Qt::UserRole + 1,
|
||||||
|
Height,
|
||||||
|
Id,
|
||||||
|
User,
|
||||||
|
UserId,
|
||||||
|
UserUrl,
|
||||||
|
Thumbnail,
|
||||||
|
Url,
|
||||||
|
Width
|
||||||
|
};
|
||||||
|
Q_ENUM(DataRoles)
|
||||||
|
|
||||||
|
enum Status
|
||||||
|
{
|
||||||
|
Idle,
|
||||||
|
Searching
|
||||||
|
};
|
||||||
|
Q_ENUM(Status)
|
||||||
|
|
||||||
|
PexelsVideoSearchModel(QObject *parent = nullptr);
|
||||||
|
~PexelsVideoSearchModel();
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
QString query() const;
|
||||||
|
void setQuery(const QString &query);
|
||||||
|
|
||||||
|
quint16 resultsPerPage() const;
|
||||||
|
void setResultsPerPage(quint16 resultsPerPage);
|
||||||
|
|
||||||
|
quint64 totalResults() const;
|
||||||
|
void setTotalResults(quint64 totalResults);
|
||||||
|
|
||||||
|
QString nextPage() const;
|
||||||
|
void setNextPage(const QString &nextPage);
|
||||||
|
|
||||||
|
QString previousPage() const;
|
||||||
|
void setPreviousPage(const QString &previousPage);
|
||||||
|
|
||||||
|
quint64 currentPage() const;
|
||||||
|
void setCurrentPage(quint64 currentPage);
|
||||||
|
|
||||||
|
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
QModelIndex parent(const QModelIndex &index) const override;
|
||||||
|
|
||||||
|
Q_INVOKABLE void next();
|
||||||
|
Q_INVOKABLE void back();
|
||||||
|
|
||||||
|
qreal downloadProgress() const;
|
||||||
|
void setDownloadProgress(qreal downloadProgress);
|
||||||
|
|
||||||
|
QString lastSavedFile() const;
|
||||||
|
void setLastSavedFile(const QString &lastSavedFile);
|
||||||
|
|
||||||
|
int status() const;
|
||||||
|
void setStatus(const int &status);
|
||||||
|
|
||||||
|
PexelsVideoEntryModel *videoModel() const;
|
||||||
|
|
||||||
|
quint64 currentIndex() const;
|
||||||
|
void setCurrentIndex(quint64 currentIndex);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void queryChanged();
|
||||||
|
void resultsPerPageChanged();
|
||||||
|
void totalResultsChanged();
|
||||||
|
void nextPageChanged();
|
||||||
|
void previousPageChanged();
|
||||||
|
void currentPageChanged();
|
||||||
|
void downloadProgressChanged();
|
||||||
|
void downloadFinished();
|
||||||
|
void lastSavedFileChanged();
|
||||||
|
void statusChanged();
|
||||||
|
void videoModelChanged();
|
||||||
|
|
||||||
|
void currentIndexChanged();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void getSearchResults(QString url);
|
||||||
|
quint64 getFileSize(QUrl url);
|
||||||
|
QString sizeText(quint64 size);
|
||||||
|
|
||||||
|
QNetworkAccessManager m_networkManager;
|
||||||
|
QString m_query;
|
||||||
|
|
||||||
|
quint16 m_resultsPerPage = 9;
|
||||||
|
quint64 m_totalResults = 0;
|
||||||
|
quint64 m_currentPage = 0;
|
||||||
|
quint64 m_currentIndex = 0;
|
||||||
|
qreal m_downloadProgress = 0;
|
||||||
|
QString m_nextPage;
|
||||||
|
QString m_previousPage;
|
||||||
|
QString m_lastSavedFile;
|
||||||
|
|
||||||
|
PexelsVideoEntryModel *m_videoModel = nullptr;
|
||||||
|
|
||||||
|
QList<PexelsVideoEntry> m_data;
|
||||||
|
Status m_status = Status::Idle;
|
||||||
|
|
||||||
|
static inline const QHash<int, QByteArray> m_dataRoles =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
static_cast<int>(Tags),
|
||||||
|
QByteArray("tags")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Height),
|
||||||
|
QByteArray("videoHeight")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Id),
|
||||||
|
QByteArray("id")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(User),
|
||||||
|
QByteArray("user")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(UserId),
|
||||||
|
QByteArray("userId")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(UserUrl),
|
||||||
|
QByteArray("userUrl")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Thumbnail),
|
||||||
|
QByteArray("thumbnail")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Url),
|
||||||
|
QByteArray("videoUrl")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
static_cast<int>(Width),
|
||||||
|
QByteArray("videoWidth")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline const QStringList m_sizeSuffix =
|
||||||
|
{
|
||||||
|
QStringLiteral("B"),
|
||||||
|
QStringLiteral("KB"),
|
||||||
|
QStringLiteral("MB"),
|
||||||
|
QStringLiteral("GB"),
|
||||||
|
QStringLiteral("TB")
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_PROPERTY(QString query READ query WRITE setQuery NOTIFY queryChanged FINAL)
|
||||||
|
Q_PROPERTY(quint16 resultsPerPage READ resultsPerPage WRITE setResultsPerPage NOTIFY resultsPerPageChanged FINAL)
|
||||||
|
Q_PROPERTY(quint64 totalResults READ totalResults WRITE setTotalResults NOTIFY totalResultsChanged FINAL)
|
||||||
|
Q_PROPERTY(QString nextPage READ nextPage WRITE setNextPage NOTIFY nextPageChanged FINAL)
|
||||||
|
Q_PROPERTY(QString previousPage READ previousPage WRITE setPreviousPage NOTIFY previousPageChanged FINAL)
|
||||||
|
Q_PROPERTY(quint64 currentPage READ currentPage WRITE setCurrentPage NOTIFY currentPageChanged FINAL)
|
||||||
|
Q_PROPERTY(QString lastSavedFile READ lastSavedFile NOTIFY lastSavedFileChanged FINAL)
|
||||||
|
Q_PROPERTY(int status READ status WRITE setStatus NOTIFY statusChanged FINAL)
|
||||||
|
Q_PROPERTY(PexelsVideoEntryModel *videoModel READ videoModel NOTIFY videoModelChanged FINAL)
|
||||||
|
Q_PROPERTY(quint64 currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged FINAL)
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(PexelsVideoSearchModel)
|
||||||
|
|
||||||
|
#endif // PexelsVideoSearchModel_H
|
||||||
Reference in New Issue
Block a user