Commit 3a65398e authored by Julius Künzel's avatar Julius Künzel
Browse files

Initial version of online resource rewrite

parent 54bbc6ae
......@@ -6,6 +6,7 @@ add_subdirectory(lumas)
add_subdirectory(man)
add_subdirectory(titles)
add_subdirectory(profiles)
add_subdirectory(resourceproviders)
add_subdirectory(shortcuts)
install(FILES
......
INSTALL (FILES
archiveorg.json
freesound.json
pexels_photo.json
pexels_video.json
filmmusicio.json
pixabay_photo.json
DESTINATION ${DATA_INSTALL_DIR}/kdenlive/resourceproviders)
......@@ -54,6 +54,7 @@ add_subdirectory(lib)
add_subdirectory(library)
add_subdirectory(mltcontroller)
add_subdirectory(monitor)
add_subdirectory(onlineresources)
add_subdirectory(profiles)
add_subdirectory(project)
add_subdirectory(qml)
......
......@@ -52,6 +52,7 @@
#include "monitor/monitor.h"
#include "monitor/monitormanager.h"
#include "monitor/scopes/audiographspectrum.h"
#include "onlineresources/resourcewidget.hpp"
#include "profiles/profilemodel.hpp"
#include "project/cliptranscode.h"
#include "project/dialogs/archivewidget.h"
......@@ -65,7 +66,7 @@
#include "titler/titlewidget.h"
#include "transitions/transitionlist/view/transitionlistwidget.hpp"
#include "transitions/transitionsrepository.hpp"
#include "utils/resourcewidget.h"
//#include "utils/resourcewidget_old.h" //TODO
#include "utils/thememanager.h"
#include "utils/otioconvertions.h"
#include "lib/localeHandling.h"
......@@ -347,12 +348,28 @@ void MainWindow::init()
QDockWidget* clipDockWidget = addDock(i18n("Media Browser"), QStringLiteral("bin_clip"), pCore->bin()->getWidget());
pCore->bin()->dockWidgetInit(clipDockWidget);
// Online resources widget
ResourceWidget *onlineResources = new ResourceWidget(this);
m_onlineResourcesDock = addDock(i18n("Online Resources"), QStringLiteral("onlineresources"), onlineResources);
//connect(m_clipMonitor, &Monitor::addClipToProject, this, &Bin::slotAddClipToProject);
//connect(m_clipMonitor, &Monitor::refreshCurrentClip, this, &Bin::slotOpenCurrent);
connect(onlineResources, &ResourceWidget::previewClip, [&](const QString &path) {
m_clipMonitor->slotPreviewOnlineResource(path);
m_clipMonitorDock->show();
m_clipMonitorDock->raise();
});
connect(onlineResources, &ResourceWidget::addClip, this, &MainWindow::slotAddProjectClip);
/*connect(spectrumDock, &QDockWidget::visibilityChanged, this, [&](bool visible) {
m_audioSpectrum->dockVisible(visible);
});*/
// Close library and audiospectrum and others on first run
screenGrabDock->close();
libraryDock->close();
subtitlesDock->close();
spectrumDock->close();
clipDockWidget->close();
m_onlineResourcesDock->close();
m_assetPanel = new AssetPanel(this);
m_effectStackDock = addDock(i18n("Effect/Composition Stack"), QStringLiteral("effect_stack"), m_assetPanel);
......@@ -3734,12 +3751,15 @@ void MainWindow::slotDownloadResources()
} else {
currentFolder = KdenliveSettings::defaultprojectfolder();
}
auto *d = new ResourceWidget(currentFolder);
connect(d, &ResourceWidget::addClip, this, &MainWindow::slotAddProjectClip);
connect(d, &ResourceWidget::addLicenseInfo, this, &MainWindow::slotAddTextNote);
d->show();
d->raise();
d->activateWindow();
m_onlineResourcesDock->show();
m_onlineResourcesDock->raise();
//auto *d = new ResourceWidget(currentFolder);
//auto *d = new ResourceDialog(currentFolder);
//connect(d, &ResourceWidget::addClip, this, &MainWindow::slotAddProjectClip);
//connect(d, &ResourceWidget::addLicenseInfo, this, &MainWindow::slotAddTextNote);
//d->show();
//d->raise();
//d->activateWindow();
}
void MainWindow::slotProcessImportKeyframes(GraphicsRectItem type, const QString &tag, const QString &keyframes)
......
......@@ -199,6 +199,7 @@ private:
QDockWidget *m_undoViewDock;
QDockWidget *m_mixerDock;
QDockWidget *m_onlineResourcesDock;
KSelectAction *m_timeFormatButton;
KSelectAction *m_compositeAction;
......
......@@ -1325,6 +1325,10 @@ std::shared_ptr<Mlt::Consumer> GLWidget::consumer()
return m_consumer;
}
Mlt::Producer *GLWidget::producer() {
return m_producer.get();
}
void GLWidget::resetConsumer(bool fullReset)
{
if (fullReset && m_consumer) {
......
......@@ -1726,6 +1726,22 @@ void Monitor::slotOpenDvdFile(const QString &file)
// render->loadUrl(file);
}
void Monitor::slotPreviewOnlineResource(const QString &path)
{
warningMessage(i18n("It maybe takes a while until the preview is loaded"), 15000);
slotOpenClip(nullptr);
m_streamAction->setVisible(false);
m_glMonitor->setProducer(path);
m_glMonitor->producer();
m_timePos->setRange(0, m_glMonitor->producer()->get_length() - 1);
m_glMonitor->getControllerProxy()->setClipProperties(-1, ClipType::Unknown, false, i18n("Online Resources Preview"));
m_glMonitor->setRulerInfo(m_glMonitor->producer()->get_length() - 1);
loadQmlScene(MonitorSceneDefault);
checkOverlay();
slotStart();
switchPlay(true);
}
void Monitor::setCustomProfile(const QString &profile, const Timecode &tc)
{
// TODO or deprecate
......
......@@ -278,6 +278,7 @@ private slots:
public slots:
void slotSetScreen(int screenIndex);
void slotOpenDvdFile(const QString &);
void slotPreviewOnlineResource(const QString &path);
// void slotSetClipProducer(DocClipBase *clip, QPoint zone = QPoint(), bool forceUpdate = false, int position = -1);
void updateClipProducer(const std::shared_ptr<Mlt::Producer> &prod);
void updateClipProducer(const QString &playlist);
......
set(kdenlive_SRCS
${kdenlive_SRCS}
#onlineresources/logindialog.cpp
onlineresources/providermodel.cpp
onlineresources/providersrepository.cpp
onlineresources/resourcewidget.cpp
PARENT_SCOPE)
This diff is collapsed.
/***************************************************************************
* Copyright (C) 2011 by Jean-Baptiste Mardelle (jb@kdenlive.org) *
* *
* Copyright (C) 2021 by Julius Künzel *
* This file is part of Kdenlive. See www.kdenlive.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 2 of the License, or *
* (at your option) any later version. *
* (at your option) version 3 or any later version accepted by the *
* membership of KDE e.V. (or its successor approved by the membership *
* of KDE e.V.), which shall act as a proxy defined in Section 14 of *
* version 3 of the license. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
......@@ -13,87 +16,93 @@
* 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, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
* along with this program. If not, see <https://www.gnu.org/licenses/>.*
***************************************************************************/
#ifndef ABSTRACTSERVICE_H
#define ABSTRACTSERVICE_H
#include <QListWidget>
#ifndef PROVIDERMODEL_H
#define PROVIDERMODEL_H
const int imageRole = Qt::UserRole;
const int urlRole = Qt::UserRole + 1;
const int downloadRole = Qt::UserRole + 2;
const int durationRole = Qt::UserRole + 3;
const int previewRole = Qt::UserRole + 4;
const int authorRole = Qt::UserRole + 5;
const int authorUrl = Qt::UserRole + 6;
const int infoUrl = Qt::UserRole + 7;
const int infoData = Qt::UserRole + 8;
const int idRole = Qt::UserRole + 9;
const int licenseRole = Qt::UserRole + 10;
const int descriptionRole = Qt::UserRole + 11;
#include <QObject>
#include <QJsonDocument>
#include <QJsonObject>
#include <kio/jobclasses.h>
#include <QNetworkReply>
#include <QTemporaryFile>
#include <QPixmap>
struct OnlineItemInfo
struct ResourceItemInfo
{
QString itemPreview;
QString itemName;
QString itemDownload;
QString itemId;
QString fileType;
QString name;
QString description;
QString id;
QString infoUrl;
QString license;
QString attributionText;
QString author;
QString authorUrl;
QString description;
int width;
int height;
int duration;
QString downloadUrl;
QString filetype;
QStringList downloadUrls;
QStringList downloadLabels;
QString imageUrl;
QString previewUrl;
int filesize;
QString fileType;
QString HQpreview;
};
class AbstractService : public QObject
class ProviderModel : public QObject
{
Q_OBJECT
public:
enum SERVICETYPE { NOSERVICE = 0, FREESOUND = 1, OPENCLIPART = 2, ARCHIVEORG = 3 };
enum SERVICETYPE { UNKNOWN = 0, AUDIO = 1, VIDEO = 2, IMAGE = 3};
enum INTEGRATIONTYPE { BUILDIN = 1, BROWSER = 2};
ProviderModel() = delete;
ProviderModel(const QString &path);
explicit AbstractService(QListWidget *listWidget, QObject *parent = nullptr);
~AbstractService() override;
/** @brief Get file extension for currently selected item. */
virtual QString getExtension(QListWidgetItem *item);
/** @brief Get recommEnded download file name. */
virtual QString getDefaultDownloadName(QListWidgetItem *item);
/** @brief Does this service provide a preview (for example preview a sound. */
bool hasPreview;
/** @brief Does this service provide meta info about the item. */
bool hasMetadata;
/** @brief Should we show the "import" button or does this service provide download urls in info browser. */
bool inlineDownload;
/** @brief The type for this service. */
SERVICETYPE serviceType;
bool is_valid() const;
QString name() const;
QString homepage() const;
ProviderModel::SERVICETYPE type() const;
ProviderModel::INTEGRATIONTYPE integratonType() const;
QString attribution() const;
bool downloadOAuth2() const;
public slots:
virtual void slotStartSearch(const QString &searchText, int page = 0);
virtual OnlineItemInfo displayItemDetails(QListWidgetItem *item);
virtual bool startItemPreview(QListWidgetItem *item);
virtual void stopItemPreview(QListWidgetItem *item);
void slotStartSearch(const QString &searchText, int page);
void slotFetchFiles(const QString &id);
//void slotShowResults(QNetworkReply *reply);
protected:
QListWidget *m_listWidget;
QString m_path;
QString m_name;
QString m_homepage;
INTEGRATIONTYPE m_integrationtype;
SERVICETYPE m_type;
QString m_clientkey;
QString m_attribution;
bool m_invalid;
QJsonDocument m_doc;
QString m_apiroot;
QJsonObject m_search;
QJsonObject m_download;
private:
void validate();
QUrl getSearchUrl(const QString &searchText, const int page = 1);
QUrl getFilesUrl(const QString &id);
std::pair<QList<ResourceItemInfo>, const int> parseSearchResponse(const QByteArray &res);
std::pair<QStringList, QStringList> parseFilesResponse(const QByteArray &res, const QString &id);
QTemporaryFile *m_tmpThumbFile;
const int m_perPage = 15;
signals:
void searchInfo(const QString &);
void maxPages(int);
/** @brief Emit meta info for current item in formatted html. */
void gotMetaInfo(const QString &);
/** @brief Emit some extra meta info (description, license). */
void gotMetaInfo(const QMap<QString, QString> &info);
/** @brief We have an url for current item's preview thumbnail. */
void gotThumb(const QString &url);
/** @brief The requested search query is finished. */
void searchDone();
void searchDone(QList<ResourceItemInfo> &list, const int pageCount);
void searchError(const QString &msg = QString());
void fetchedFiles(QStringList, QStringList, const QString &token = QString());
};
#endif
#endif // PROVIDERMODEL_H
/***************************************************************************
* Copyright (C) 2021 by Julius Künzel *
* This file is part of Kdenlive. See www.kdenlive.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 2 of the License, or *
* (at your option) version 3 or any later version accepted by the *
* membership of KDE e.V. (or its successor approved by the membership *
* of KDE e.V.), which shall act as a proxy defined in Section 14 of *
* version 3 of the license. *
* *
* 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 <https://www.gnu.org/licenses/>.*
***************************************************************************/
#include "providersrepository.hpp"
#include <QStandardPaths>
#include <QDir>
std::unique_ptr<ProvidersRepository> ProvidersRepository::instance;
std::once_flag ProvidersRepository::m_onceFlag;
ProvidersRepository::ProvidersRepository()
{
refresh();
}
std::unique_ptr<ProvidersRepository> &ProvidersRepository::get()
{
std::call_once(m_onceFlag, [] { instance.reset(new ProvidersRepository()); });
return instance;
}
void ProvidersRepository::refresh(bool fullRefresh) {
//Lock to avoid changes to config files while reading them
QWriteLocker locker(&m_mutex);
if (fullRefresh) {
// Reset all providers
m_providers.clear();
}
// Helper function to check a profile and print debug info
auto check_provider = [&](std::unique_ptr<ProviderModel> &provider, const QString &file) {
if (m_providers.count(file) > 0) {
return false;
}
if (!provider->is_valid()) {
qCWarning(KDENLIVE_LOG) << "//// WARNING: invalid provider found: " << file << ". Ignoring.";
return false;
}
return true;
};
QStringList profilesFiles;
// list Providers
QStringList customProfilesDir = QStandardPaths::locateAll(QStandardPaths::AppDataLocation, QStringLiteral("resourceproviders"), QStandardPaths::LocateDirectory);
for (const auto &dir : qAsConst(customProfilesDir)) {
QStringList files = QDir(dir).entryList(QDir::Files);
for (const auto &file : qAsConst(files)) {
profilesFiles << QDir(dir).absoluteFilePath(file);
}
}
qDebug() << "Files: " << profilesFiles;
// Iterate through files
for (const auto &file : qAsConst(profilesFiles)) {
std::unique_ptr<ProviderModel> provider(new ProviderModel(file));
if (check_provider(provider, file)) {
m_providers.insert(std::make_pair(file, std::move(provider)));
}
}
}
QVector<QPair<QString, QString>> ProvidersRepository::getAllProviers() const
{
QReadLocker locker(&m_mutex);
QVector<QPair<QString, QString>> list;
for (const auto &provider : m_providers) {
list.push_back({provider.second->name(), provider.first});
}
std::sort(list.begin(), list.end());
return list;
}
std::unique_ptr<ProviderModel> &ProvidersRepository::getProvider(const QString &path)
{
QReadLocker locker(&m_mutex);
if (m_providers.count(path) == 0) {
return (*(m_providers.begin())).second;
}
return m_providers.at(path);
}
/***************************************************************************
* Copyright (C) 2011 by Jean-Baptiste Mardelle (jb@kdenlive.org) *
* *
* Copyright (C) 2021 by Julius Künzel *
* This file is part of Kdenlive. See www.kdenlive.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 2 of the License, or *
* (at your option) any later version. *
* (at your option) version 3 or any later version accepted by the *
* membership of KDE e.V. (or its successor approved by the membership *
* of KDE e.V.), which shall act as a proxy defined in Section 14 of *
* version 3 of the license. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
......@@ -13,53 +16,48 @@
* 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, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
* along with this program. If not, see <https://www.gnu.org/licenses/>.*
***************************************************************************/
#ifndef FREESOUND_H
#define FREESOUND_H
#include "abstractservice.h"
#ifndef PROVIDERSREPOSITORY_H
#define PROVIDERSREPOSITORY_H
#include <QProcess>
#include <kio/jobclasses.h>
#include "definitions.h" //for QString hash function
#include "providermodel.hpp"
#include <QReadWriteLock>
//#include <QString>
//#include <memory>
#include <mutex>
#include <unordered_map>
/**
\brief search and download sounds from freesound
/** @brief TODO This class is used to read all the profiles available to the user (MLT defaults one and Custom ones).
* You can then query profiles based on their paths
* Note that this class is a Singleton, with Mutex protections to allow concurrent access.
*/
This class is used to search the freesound.org libraries and download sounds. Is used by ResourceWidget
*/
class FreeSound : public AbstractService
class ProvidersRepository
{
Q_OBJECT
public:
explicit FreeSound(QListWidget *listWidget, QObject *parent = nullptr);
~FreeSound() override;
QString getExtension(QListWidgetItem *item) override;
QString getDefaultDownloadName(QListWidgetItem *item) override;
// Returns the instance of the Singleton
static std::unique_ptr<ProvidersRepository> &get();
/* @brief Reloads all the providers from the disk */
void refresh(bool fullRefresh = true); //TODO: change to false
QVector<QPair<QString,QString>> getAllProviers() const;
std::unique_ptr<ProviderModel> &getProvider(const QString &path);
protected:
ProvidersRepository();
public slots:
void slotStartSearch(const QString &searchText, int page = 0) override;
OnlineItemInfo displayItemDetails(QListWidgetItem *item) override;
bool startItemPreview(QListWidgetItem *item) override;
void stopItemPreview(QListWidgetItem *item) override;
static std::unique_ptr<ProvidersRepository> instance;
static std::once_flag m_onceFlag; // flag to create the repository only once;
private slots:
void slotShowResults(KJob *job);
void slotParseResults(KJob *job);
void slotPreviewFinished(int exitCode, QProcess::ExitStatus exitStatus);
void slotPreviewErrored(QProcess::ProcessError error);
mutable QReadWriteLock m_mutex;
private:
QMap<QString, QString> m_metaInfo;
QProcess *m_previewProcess;
std::unordered_map<QString, std::unique_ptr<ProviderModel>> m_providers;
signals:
void addClip(const QUrl &, const QString &);
void previewFinished();
};
#endif
#endif // PROVIDERSREPOSITORY_H
This diff is collapsed.
#ifndef REOURCEWIDGET_H
#define REOURCEWIDGET_H
#include "ui_resourcewidget_ui.h"
#include "providersrepository.hpp"
#include <QWidget>
#include <QUrl>
#include <QNetworkReply>
#include <QTemporaryFile>
#include <QSlider>
#include <QListWidgetItem>
#include <QProcess>
//#include <QOAuth2AuthorizationCodeFlow>
class OAuth2;
const int imageRole = Qt::UserRole;
const int urlRole = Qt::UserRole + 1;
const int downloadRole = Qt::UserRole + 2;
const int durationRole = Qt::UserRole + 3;
const int previewRole = Qt::UserRole + 4;
const int authorRole = Qt::UserRole + 5;
const int authorUrl = Qt::UserRole + 6;
const int infoUrl = Qt::UserRole + 7;
const int infoData = Qt::UserRole + 8;
const int idRole = Qt::UserRole + 9;
const int licenseRole = Qt::UserRole + 10;
const int descriptionRole = Qt::UserRole + 11;
const int widthRole = Qt::UserRole + 12;
const int heightRole = Qt::UserRole + 13;
const int nameRole = Qt::UserRole + 14;
const int singleDownloadRole = Qt::UserRole + 15;
const int filetypeRole = Qt::UserRole + 16;
const int downloadLabelRole = Qt::UserRole + 17;
class ResourceWidget : public QWidget, public Ui::ResourceWidget_UI
{
Q_OBJECT
public:
explicit ResourceWidget(QWidget *parent = nullptr);
~ResourceWidget() override;
protected:
bool eventFilter(QObject *obj, QEvent *ev) override;
private slots:
void slotChangeProvider();
/**
* @brief ResourceWidget::slotOpenUrl. Opens the file on the URL using the associated application via a KRun object
* @param url
*/
void slotOpenUrl(const QString &url);
void slotStartSearch();
void slotSearchFinished(QList<ResourceItemInfo> &list, const int pageCount);
void slotUpdateCurrentItem();
void slotSetIconSize(int size);
void slotZoomView(bool zoomIn);
void slotPreviewItem();
void slotChooseVersion(const QStringList &urls, const QStringList &labels, const QString &accessToken = QString());
void slotSaveItem(const QString &originalUrl = QString(), const QString &accessToken = QString());