diff --git a/src/effects/effectsrepository.cpp b/src/effects/effectsrepository.cpp
index f83ca06f5..cc6bc65cd 100644
--- a/src/effects/effectsrepository.cpp
+++ b/src/effects/effectsrepository.cpp
@@ -1,356 +1,355 @@
/***************************************************************************
* Copyright (C) 2017 by Nicolas Carion *
* 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 . *
***************************************************************************/
#include "effectsrepository.hpp"
#include "core.h"
#include "kdenlivesettings.h"
#include "profiles/profilemodel.hpp"
#include "xml/xml.hpp"
#include
#include
#include
#include
#include
#include
std::unique_ptr EffectsRepository::instance;
std::once_flag EffectsRepository::m_onceFlag;
EffectsRepository::EffectsRepository()
: AbstractAssetsRepository()
{
init();
// Check that our favorite effects are valid
QStringList invalidEffect;
for (const QString &effect : KdenliveSettings::favorite_effects()) {
if (!exists(effect)) {
invalidEffect << effect;
}
}
if (!invalidEffect.isEmpty()) {
pCore->displayMessage(i18n("Some of your favorite effects are invalid and were removed: %1", invalidEffect.join(QLatin1Char(','))), ErrorMessage);
QStringList newFavorites = KdenliveSettings::favorite_effects();
for (const QString &effect : invalidEffect) {
newFavorites.removeAll(effect);
}
KdenliveSettings::setFavorite_effects(newFavorites);
}
}
Mlt::Properties *EffectsRepository::retrieveListFromMlt() const
{
return pCore->getMltRepository()->filters();
}
Mlt::Properties *EffectsRepository::getMetadata(const QString &effectId) const
{
return pCore->getMltRepository()->metadata(filter_type, effectId.toLatin1().data());
}
void EffectsRepository::parseCustomAssetFile(const QString &file_name, std::unordered_map &customAssets) const
{
QFile file(file_name);
QDomDocument doc;
doc.setContent(&file, false);
file.close();
QDomElement base = doc.documentElement();
if (base.tagName() == QLatin1String("effectgroup")) {
// in that case we have a custom effect
Info info;
info.xml = base;
info.type = EffectType::Custom;
QString tag = base.attribute(QStringLiteral("tag"), QString());
QString id = base.hasAttribute(QStringLiteral("id")) ? base.attribute(QStringLiteral("id")) : tag;
QString name = base.attribute(QStringLiteral("name"), QString());
info.name = name;
info.id = id;
info.mltId = tag;
if (customAssets.count(id) > 0) {
qDebug() << "Error: conflicting effect name" << id;
} else {
customAssets[id] = info;
}
return;
}
QDomNodeList effects = doc.elementsByTagName(QStringLiteral("effect"));
int nbr_effect = effects.count();
if (nbr_effect == 0) {
qDebug() << "+++++++++++++\nEffect broken: " << file_name << "\n+++++++++++";
return;
}
for (int i = 0; i < nbr_effect; ++i) {
QDomNode currentNode = effects.item(i);
if (currentNode.isNull()) {
continue;
}
QDomElement currentEffect = currentNode.toElement();
Info result;
bool ok = parseInfoFromXml(currentEffect, result);
if (!ok) {
continue;
}
if (customAssets.count(result.id) > 0) {
qDebug() << "Warning: duplicate custom definition of effect" << result.id << "found. Only last one will be considered. Duplicate found in"
<< file_name;
}
result.xml = currentEffect;
// Parse type information.
+ // Video effect by default
+ result.type = EffectType::Video;
QString type = currentEffect.attribute(QStringLiteral("type"), QString());
if (type == QLatin1String("audio")) {
result.type = EffectType::Audio;
} else if (type == QLatin1String("customVideo")) {
result.type = EffectType::Custom;
} else if (type == QLatin1String("customAudio")) {
result.type = EffectType::CustomAudio;
} else if (type == QLatin1String("hidden")) {
result.type = EffectType::Hidden;
} else if (type == QLatin1String("custom")) {
// Old type effect, update to customVideo / customAudio
const QString effectTag = currentEffect.attribute(QStringLiteral("tag"));
QScopedPointer metadata(getMetadata(effectTag));
if (metadata && metadata->is_valid()) {
Mlt::Properties tags((mlt_properties)metadata->get_data("tags"));
if (QString(tags.get(0)) == QLatin1String("Audio")) {
result.type = EffectType::CustomAudio;
currentEffect.setAttribute(QStringLiteral("type"), QStringLiteral("customAudio"));
} else {
result.type = EffectType::Custom;
currentEffect.setAttribute(QStringLiteral("type"), QStringLiteral("customVideo"));
}
QFile effectFile(file_name);
if (effectFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
effectFile.write(doc.toString().toUtf8());
}
file.close();
}
- } else {
- result.type = EffectType::Video;
}
-
customAssets[result.id] = result;
}
}
std::unique_ptr &EffectsRepository::get()
{
std::call_once(m_onceFlag, [] { instance.reset(new EffectsRepository()); });
return instance;
}
QStringList EffectsRepository::assetDirs() const
{
return QStandardPaths::locateAll(QStandardPaths::AppDataLocation, QStringLiteral("effects"), QStandardPaths::LocateDirectory);
}
void EffectsRepository::parseType(QScopedPointer &metadata, Info &res)
{
res.type = EffectType::Video;
Mlt::Properties tags((mlt_properties)metadata->get_data("tags"));
if (QString(tags.get(0)) == QLatin1String("Audio")) {
res.type = EffectType::Audio;
}
}
QString EffectsRepository::assetBlackListPath() const
{
return QStringLiteral(":data/blacklisted_effects.txt");
}
QString EffectsRepository::assetPreferredListPath() const
{
return QStringLiteral(":data/preferred_effects.txt");
}
bool EffectsRepository::isPreferred(const QString &effectId) const
{
return m_preferred_list.contains(effectId);
}
std::unique_ptr EffectsRepository::getEffect(const QString &effectId) const
{
Q_ASSERT(exists(effectId));
QString service_name = m_assets.at(effectId).mltId;
// We create the Mlt element from its name
auto filter = std::make_unique(pCore->getCurrentProfile()->profile(), service_name.toLatin1().constData(), nullptr);
return filter;
}
bool EffectsRepository::hasInternalEffect(const QString &effectId) const
{
// Retrieve the list of MLT's available assets.
QScopedPointer assets(retrieveListFromMlt());
int max = assets->count();
for (int i = 0; i < max; ++i) {
if (assets->get_name(i) == effectId) {
return true;
}
}
return false;
}
QPair EffectsRepository::reloadCustom(const QString &path)
{
std::unordered_map customAssets;
parseCustomAssetFile(path, customAssets);
QPair result;
// TODO: handle files with several effects
for (const auto &custom : customAssets) {
// Custom assets should override default ones
m_assets[custom.first] = custom.second;
result.first = custom.first;
result.second = custom.second.mltId;
}
return result;
}
QPair EffectsRepository::fixDeprecatedEffects()
{
QString customAssetDir = QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("effects"), QStandardPaths::LocateDirectory);
QPair results;
QDir current_dir(customAssetDir);
QStringList filter;
filter << QStringLiteral("*.xml");
QStringList fileList = current_dir.entryList(filter, QDir::Files);
QStringList failed;
for (const auto &file : fileList) {
QString path = current_dir.absoluteFilePath(file);
QPair fixResult = fixCustomAssetFile(path);
if (!fixResult.first.isEmpty()) {
results.first << fixResult.first;
} else if (!fixResult.second.isEmpty()) {
results.second << fixResult.second;
}
}
return results;
}
QPair EffectsRepository::fixCustomAssetFile(const QString &path)
{
QPair results;
QFile file(path);
QDomDocument doc;
doc.setContent(&file, false);
file.close();
QDomElement base = doc.documentElement();
if (base.tagName() == QLatin1String("effectgroup")) {
// Groups not implemented
return results;
}
QDomNodeList effects = doc.elementsByTagName(QStringLiteral("effect"));
int nbr_effect = effects.count();
if (nbr_effect == 0) {
qDebug() << "+++++++++++++\nEffect broken: " << path << "\n+++++++++++";
results.second = path;
return results;
}
bool effectAdjusted = false;
for (int i = 0; i < nbr_effect; ++i) {
QDomNode currentNode = effects.item(i);
if (currentNode.isNull()) {
continue;
}
QDomElement currentEffect = currentNode.toElement();
Info result;
bool ok = parseInfoFromXml(currentEffect, result);
if (!ok) {
continue;
}
if (currentEffect.hasAttribute(QLatin1String("kdenlive_info"))) {
// This is a pre 19.x custom effect, adjust param values
// First backup effect in legacy folder
QDir dir(QFileInfo(path).absoluteDir());
if (!dir.mkpath(QStringLiteral("legacy"))) {
// Cannot create the legacy folder, abort
qDebug()<<" = = = Could not create legacy folder in : "<