mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2025-12-23 16:58:06 -06:00
committed by
GitHub
parent
facfa26eed
commit
dd1bd8ad10
@@ -30,8 +30,9 @@
|
||||
|
||||
#include <QProcess>
|
||||
|
||||
#include "../utils/foreignapps.h"
|
||||
#include "../utils/fs.h"
|
||||
#include "base/path.h"
|
||||
#include "base/utils/foreignapps.h"
|
||||
#include "base/utils/fs.h"
|
||||
#include "searchpluginmanager.h"
|
||||
|
||||
SearchDownloadHandler::SearchDownloadHandler(const QString &siteUrl, const QString &url, SearchPluginManager *manager)
|
||||
@@ -44,7 +45,7 @@ SearchDownloadHandler::SearchDownloadHandler(const QString &siteUrl, const QStri
|
||||
, this, &SearchDownloadHandler::downloadProcessFinished);
|
||||
const QStringList params
|
||||
{
|
||||
Utils::Fs::toNativePath(m_manager->engineLocation() + "/nova2dl.py"),
|
||||
(m_manager->engineLocation() / Path("nova2dl.py")).toString(),
|
||||
siteUrl,
|
||||
url
|
||||
};
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <QVector>
|
||||
|
||||
#include "base/global.h"
|
||||
#include "base/path.h"
|
||||
#include "base/utils/foreignapps.h"
|
||||
#include "base/utils/fs.h"
|
||||
#include "searchpluginmanager.h"
|
||||
@@ -67,7 +68,7 @@ SearchHandler::SearchHandler(const QString &pattern, const QString &category, co
|
||||
|
||||
const QStringList params
|
||||
{
|
||||
Utils::Fs::toNativePath(m_manager->engineLocation() + "/nova2.py"),
|
||||
(m_manager->engineLocation() / Path("nova2.py")).toString(),
|
||||
m_usedPlugins.join(','),
|
||||
m_category
|
||||
};
|
||||
|
||||
@@ -52,30 +52,31 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
void clearPythonCache(const QString &path)
|
||||
void clearPythonCache(const Path &path)
|
||||
{
|
||||
// remove python cache artifacts in `path` and subdirs
|
||||
|
||||
QStringList dirs = {path};
|
||||
QDirIterator iter {path, (QDir::AllDirs | QDir::NoDotAndDotDot), QDirIterator::Subdirectories};
|
||||
PathList dirs = {path};
|
||||
QDirIterator iter {path.data(), (QDir::AllDirs | QDir::NoDotAndDotDot), QDirIterator::Subdirectories};
|
||||
while (iter.hasNext())
|
||||
dirs += iter.next();
|
||||
dirs += Path(iter.next());
|
||||
|
||||
for (const QString &dir : asConst(dirs))
|
||||
for (const Path &dir : asConst(dirs))
|
||||
{
|
||||
// python 3: remove "__pycache__" folders
|
||||
if (dir.endsWith("/__pycache__"))
|
||||
if (dir.filename() == QLatin1String("__pycache__"))
|
||||
{
|
||||
Utils::Fs::removeDirRecursive(dir);
|
||||
Utils::Fs::removeDirRecursively(dir);
|
||||
continue;
|
||||
}
|
||||
|
||||
// python 2: remove "*.pyc" files
|
||||
const QStringList files = QDir(dir).entryList(QDir::Files);
|
||||
const QStringList files = QDir(dir.data()).entryList(QDir::Files);
|
||||
for (const QString &file : files)
|
||||
{
|
||||
if (file.endsWith(".pyc"))
|
||||
Utils::Fs::forceRemove(file);
|
||||
const Path path {file};
|
||||
if (path.hasExtension(QLatin1String(".pyc")))
|
||||
Utils::Fs::removeFile(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -210,21 +211,22 @@ void SearchPluginManager::installPlugin(const QString &source)
|
||||
}
|
||||
else
|
||||
{
|
||||
QString path = source;
|
||||
if (path.startsWith("file:", Qt::CaseInsensitive))
|
||||
path = QUrl(path).toLocalFile();
|
||||
const Path path {source.startsWith("file:", Qt::CaseInsensitive) ? QUrl(source).toLocalFile() : source};
|
||||
|
||||
QString pluginName = Utils::Fs::fileName(path);
|
||||
pluginName.chop(pluginName.size() - pluginName.lastIndexOf('.'));
|
||||
|
||||
if (!path.endsWith(".py", Qt::CaseInsensitive))
|
||||
emit pluginInstallationFailed(pluginName, tr("Unknown search engine plugin file format."));
|
||||
else
|
||||
QString pluginName = path.filename();
|
||||
if (pluginName.endsWith(".py", Qt::CaseInsensitive))
|
||||
{
|
||||
pluginName.chop(pluginName.size() - pluginName.lastIndexOf('.'));
|
||||
installPlugin_impl(pluginName, path);
|
||||
}
|
||||
else
|
||||
{
|
||||
emit pluginInstallationFailed(pluginName, tr("Unknown search engine plugin file format."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SearchPluginManager::installPlugin_impl(const QString &name, const QString &path)
|
||||
void SearchPluginManager::installPlugin_impl(const QString &name, const Path &path)
|
||||
{
|
||||
const PluginVersion newVersion = getPluginVersion(path);
|
||||
const PluginInfo *plugin = pluginInfo(name);
|
||||
@@ -236,30 +238,31 @@ void SearchPluginManager::installPlugin_impl(const QString &name, const QString
|
||||
}
|
||||
|
||||
// Process with install
|
||||
const QString destPath = pluginPath(name);
|
||||
const Path destPath = pluginPath(name);
|
||||
const Path backupPath = destPath + ".bak";
|
||||
bool updated = false;
|
||||
if (QFile::exists(destPath))
|
||||
if (destPath.exists())
|
||||
{
|
||||
// Backup in case install fails
|
||||
QFile::copy(destPath, destPath + ".bak");
|
||||
Utils::Fs::forceRemove(destPath);
|
||||
Utils::Fs::copyFile(destPath, backupPath);
|
||||
Utils::Fs::removeFile(destPath);
|
||||
updated = true;
|
||||
}
|
||||
// Copy the plugin
|
||||
QFile::copy(path, destPath);
|
||||
Utils::Fs::copyFile(path, destPath);
|
||||
// Update supported plugins
|
||||
update();
|
||||
// Check if this was correctly installed
|
||||
if (!m_plugins.contains(name))
|
||||
{
|
||||
// Remove broken file
|
||||
Utils::Fs::forceRemove(destPath);
|
||||
Utils::Fs::removeFile(destPath);
|
||||
LogMsg(tr("Plugin %1 is not supported.").arg(name), Log::INFO);
|
||||
if (updated)
|
||||
{
|
||||
// restore backup
|
||||
QFile::copy(destPath + ".bak", destPath);
|
||||
Utils::Fs::forceRemove(destPath + ".bak");
|
||||
Utils::Fs::copyFile(backupPath, destPath);
|
||||
Utils::Fs::removeFile(backupPath);
|
||||
// Update supported plugins
|
||||
update();
|
||||
emit pluginUpdateFailed(name, tr("Plugin is not supported."));
|
||||
@@ -275,7 +278,7 @@ void SearchPluginManager::installPlugin_impl(const QString &name, const QString
|
||||
if (updated)
|
||||
{
|
||||
LogMsg(tr("Plugin %1 has been successfully updated.").arg(name), Log::INFO);
|
||||
Utils::Fs::forceRemove(destPath + ".bak");
|
||||
Utils::Fs::removeFile(backupPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -285,12 +288,11 @@ bool SearchPluginManager::uninstallPlugin(const QString &name)
|
||||
clearPythonCache(engineLocation());
|
||||
|
||||
// remove it from hard drive
|
||||
const QDir pluginsFolder(pluginsLocation());
|
||||
QStringList filters;
|
||||
filters << name + ".*";
|
||||
const QStringList files = pluginsFolder.entryList(filters, QDir::Files, QDir::Unsorted);
|
||||
const Path pluginsPath = pluginsLocation();
|
||||
const QStringList filters {name + QLatin1String(".*")};
|
||||
const QStringList files = QDir(pluginsPath.data()).entryList(filters, QDir::Files, QDir::Unsorted);
|
||||
for (const QString &file : files)
|
||||
Utils::Fs::forceRemove(pluginsFolder.absoluteFilePath(file));
|
||||
Utils::Fs::removeFile(pluginsPath / Path(file));
|
||||
// Remove it from supported engines
|
||||
delete m_plugins.take(name);
|
||||
|
||||
@@ -301,15 +303,17 @@ bool SearchPluginManager::uninstallPlugin(const QString &name)
|
||||
void SearchPluginManager::updateIconPath(PluginInfo *const plugin)
|
||||
{
|
||||
if (!plugin) return;
|
||||
QString iconPath = QString::fromLatin1("%1/%2.png").arg(pluginsLocation(), plugin->name);
|
||||
if (QFile::exists(iconPath))
|
||||
|
||||
const Path pluginsPath = pluginsLocation();
|
||||
Path iconPath = pluginsPath / Path(plugin->name + QLatin1String(".png"));
|
||||
if (iconPath.exists())
|
||||
{
|
||||
plugin->iconPath = iconPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
iconPath = QString::fromLatin1("%1/%2.ico").arg(pluginsLocation(), plugin->name);
|
||||
if (QFile::exists(iconPath))
|
||||
iconPath = pluginsPath / Path(plugin->name + QLatin1String(".ico"));
|
||||
if (iconPath.exists())
|
||||
plugin->iconPath = iconPath;
|
||||
}
|
||||
}
|
||||
@@ -357,20 +361,18 @@ QString SearchPluginManager::pluginFullName(const QString &pluginName)
|
||||
return pluginInfo(pluginName) ? pluginInfo(pluginName)->fullName : QString();
|
||||
}
|
||||
|
||||
QString SearchPluginManager::pluginsLocation()
|
||||
Path SearchPluginManager::pluginsLocation()
|
||||
{
|
||||
return QString::fromLatin1("%1/engines").arg(engineLocation());
|
||||
return (engineLocation() / Path("engines"));
|
||||
}
|
||||
|
||||
QString SearchPluginManager::engineLocation()
|
||||
Path SearchPluginManager::engineLocation()
|
||||
{
|
||||
static QString location;
|
||||
static Path location;
|
||||
if (location.isEmpty())
|
||||
{
|
||||
location = Utils::Fs::expandPathAbs(specialFolderLocation(SpecialFolder::Data) + "/nova3");
|
||||
|
||||
const QDir locationDir(location);
|
||||
locationDir.mkpath(locationDir.absolutePath());
|
||||
location = specialFolderLocation(SpecialFolder::Data) / Path("nova3");
|
||||
Utils::Fs::mkpath(location);
|
||||
}
|
||||
|
||||
return location;
|
||||
@@ -388,12 +390,12 @@ void SearchPluginManager::pluginDownloadFinished(const Net::DownloadResult &resu
|
||||
{
|
||||
if (result.status == Net::DownloadStatus::Success)
|
||||
{
|
||||
const QString filePath = Utils::Fs::toUniformPath(result.filePath);
|
||||
const Path filePath = result.filePath;
|
||||
|
||||
QString pluginName = Utils::Fs::fileName(result.url);
|
||||
pluginName.chop(pluginName.size() - pluginName.lastIndexOf('.')); // Remove extension
|
||||
installPlugin_impl(pluginName, filePath);
|
||||
Utils::Fs::forceRemove(filePath);
|
||||
Path pluginPath {QUrl(result.url).path()};
|
||||
pluginPath.removeExtension(); // Remove extension
|
||||
installPlugin_impl(pluginPath.filename(), filePath);
|
||||
Utils::Fs::removeFile(filePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -412,37 +414,37 @@ void SearchPluginManager::pluginDownloadFinished(const Net::DownloadResult &resu
|
||||
void SearchPluginManager::updateNova()
|
||||
{
|
||||
// create nova directory if necessary
|
||||
const QDir searchDir(engineLocation());
|
||||
const Path enginePath = engineLocation();
|
||||
|
||||
QFile packageFile(searchDir.absoluteFilePath("__init__.py"));
|
||||
QFile packageFile {(enginePath / Path("__init__.py")).data()};
|
||||
packageFile.open(QIODevice::WriteOnly);
|
||||
packageFile.close();
|
||||
|
||||
searchDir.mkdir("engines");
|
||||
Utils::Fs::mkdir(enginePath / Path("engines"));
|
||||
|
||||
QFile packageFile2(searchDir.absolutePath() + "/engines/__init__.py");
|
||||
QFile packageFile2 {(enginePath / Path("engines/__init__.py")).data()};
|
||||
packageFile2.open(QIODevice::WriteOnly);
|
||||
packageFile2.close();
|
||||
|
||||
// Copy search plugin files (if necessary)
|
||||
const auto updateFile = [](const QString &filename, const bool compareVersion)
|
||||
const auto updateFile = [&enginePath](const Path &filename, const bool compareVersion)
|
||||
{
|
||||
const QString filePathBundled = ":/searchengine/nova3/" + filename;
|
||||
const QString filePathDisk = QDir(engineLocation()).absoluteFilePath(filename);
|
||||
const Path filePathBundled = Path(":/searchengine/nova3") / filename;
|
||||
const Path filePathDisk = enginePath / filename;
|
||||
|
||||
if (compareVersion && (getPluginVersion(filePathBundled) <= getPluginVersion(filePathDisk)))
|
||||
return;
|
||||
|
||||
Utils::Fs::forceRemove(filePathDisk);
|
||||
QFile::copy(filePathBundled, filePathDisk);
|
||||
Utils::Fs::removeFile(filePathDisk);
|
||||
Utils::Fs::copyFile(filePathBundled, filePathDisk);
|
||||
};
|
||||
|
||||
updateFile("helpers.py", true);
|
||||
updateFile("nova2.py", true);
|
||||
updateFile("nova2dl.py", true);
|
||||
updateFile("novaprinter.py", true);
|
||||
updateFile("sgmllib3.py", false);
|
||||
updateFile("socks.py", false);
|
||||
updateFile(Path("helpers.py"), true);
|
||||
updateFile(Path("nova2.py"), true);
|
||||
updateFile(Path("nova2dl.py"), true);
|
||||
updateFile(Path("novaprinter.py"), true);
|
||||
updateFile(Path("sgmllib3.py"), false);
|
||||
updateFile(Path("socks.py"), false);
|
||||
}
|
||||
|
||||
void SearchPluginManager::update()
|
||||
@@ -450,7 +452,7 @@ void SearchPluginManager::update()
|
||||
QProcess nova;
|
||||
nova.setProcessEnvironment(QProcessEnvironment::systemEnvironment());
|
||||
|
||||
const QStringList params {Utils::Fs::toNativePath(engineLocation() + "/nova2.py"), "--capabilities"};
|
||||
const QStringList params {(engineLocation() / Path("/nova2.py")).toString(), QLatin1String("--capabilities")};
|
||||
nova.start(Utils::ForeignApps::pythonInfo().executableName, params, QIODevice::ReadOnly);
|
||||
nova.waitForFinished();
|
||||
|
||||
@@ -559,14 +561,14 @@ bool SearchPluginManager::isUpdateNeeded(const QString &pluginName, const Plugin
|
||||
return (newVersion > oldVersion);
|
||||
}
|
||||
|
||||
QString SearchPluginManager::pluginPath(const QString &name)
|
||||
Path SearchPluginManager::pluginPath(const QString &name)
|
||||
{
|
||||
return QString::fromLatin1("%1/%2.py").arg(pluginsLocation(), name);
|
||||
return (pluginsLocation() / Path(name + QLatin1String(".py")));
|
||||
}
|
||||
|
||||
PluginVersion SearchPluginManager::getPluginVersion(const QString &filePath)
|
||||
PluginVersion SearchPluginManager::getPluginVersion(const Path &filePath)
|
||||
{
|
||||
QFile pluginFile(filePath);
|
||||
QFile pluginFile {filePath.data()};
|
||||
if (!pluginFile.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
return {};
|
||||
|
||||
@@ -581,7 +583,7 @@ PluginVersion SearchPluginManager::getPluginVersion(const QString &filePath)
|
||||
return version;
|
||||
|
||||
LogMsg(tr("Search plugin '%1' contains invalid version string ('%2')")
|
||||
.arg(Utils::Fs::fileName(filePath), versionStr), Log::MsgType::WARNING);
|
||||
.arg(filePath.filename(), versionStr), Log::MsgType::WARNING);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <QMetaType>
|
||||
#include <QObject>
|
||||
|
||||
#include "base/path.h"
|
||||
#include "base/utils/version.h"
|
||||
|
||||
using PluginVersion = Utils::Version<unsigned short, 2>;
|
||||
@@ -50,7 +51,7 @@ struct PluginInfo
|
||||
QString fullName;
|
||||
QString url;
|
||||
QStringList supportedCategories;
|
||||
QString iconPath;
|
||||
Path iconPath;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
@@ -85,11 +86,11 @@ public:
|
||||
SearchHandler *startSearch(const QString &pattern, const QString &category, const QStringList &usedPlugins);
|
||||
SearchDownloadHandler *downloadTorrent(const QString &siteUrl, const QString &url);
|
||||
|
||||
static PluginVersion getPluginVersion(const QString &filePath);
|
||||
static PluginVersion getPluginVersion(const Path &filePath);
|
||||
static QString categoryFullName(const QString &categoryName);
|
||||
QString pluginFullName(const QString &pluginName);
|
||||
static QString pluginsLocation();
|
||||
static QString engineLocation();
|
||||
static Path pluginsLocation();
|
||||
static Path engineLocation();
|
||||
|
||||
signals:
|
||||
void pluginEnabled(const QString &name, bool enabled);
|
||||
@@ -106,13 +107,13 @@ private:
|
||||
void update();
|
||||
void updateNova();
|
||||
void parseVersionInfo(const QByteArray &info);
|
||||
void installPlugin_impl(const QString &name, const QString &path);
|
||||
void installPlugin_impl(const QString &name, const Path &path);
|
||||
bool isUpdateNeeded(const QString &pluginName, PluginVersion newVersion) const;
|
||||
|
||||
void versionInfoDownloadFinished(const Net::DownloadResult &result);
|
||||
void pluginDownloadFinished(const Net::DownloadResult &result);
|
||||
|
||||
static QString pluginPath(const QString &name);
|
||||
static Path pluginPath(const QString &name);
|
||||
|
||||
static QPointer<SearchPluginManager> m_instance;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user