mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2026-01-07 08:02:30 -06:00
Compare commits
2 Commits
3de2a9f486
...
d02b01c733
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d02b01c733 | ||
|
|
10b879bdaf |
@@ -28,9 +28,11 @@
|
|||||||
|
|
||||||
#include "searchdownloadhandler.h"
|
#include "searchdownloadhandler.h"
|
||||||
|
|
||||||
|
#include <QtLogging>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
|
||||||
#include "base/global.h"
|
#include "base/global.h"
|
||||||
|
#include "base/logger.h"
|
||||||
#include "base/path.h"
|
#include "base/path.h"
|
||||||
#include "base/utils/foreignapps.h"
|
#include "base/utils/foreignapps.h"
|
||||||
#include "base/utils/fs.h"
|
#include "base/utils/fs.h"
|
||||||
@@ -38,6 +40,8 @@
|
|||||||
|
|
||||||
SearchDownloadHandler::SearchDownloadHandler(const QString &pluginName, const QString &url, SearchPluginManager *manager)
|
SearchDownloadHandler::SearchDownloadHandler(const QString &pluginName, const QString &url, SearchPluginManager *manager)
|
||||||
: QObject(manager)
|
: QObject(manager)
|
||||||
|
, m_pluginName {pluginName}
|
||||||
|
, m_url {url}
|
||||||
, m_manager {manager}
|
, m_manager {manager}
|
||||||
, m_downloadProcess {new QProcess(this)}
|
, m_downloadProcess {new QProcess(this)}
|
||||||
{
|
{
|
||||||
@@ -58,10 +62,17 @@ SearchDownloadHandler::SearchDownloadHandler(const QString &pluginName, const QS
|
|||||||
m_downloadProcess->start(Utils::ForeignApps::pythonInfo().executablePath.data(), params, QIODevice::ReadOnly);
|
m_downloadProcess->start(Utils::ForeignApps::pythonInfo().executablePath.data(), params, QIODevice::ReadOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchDownloadHandler::downloadProcessFinished(int exitcode)
|
void SearchDownloadHandler::downloadProcessFinished(const int exitcode)
|
||||||
{
|
{
|
||||||
QString path;
|
const auto errMsg = QString::fromUtf8(m_downloadProcess->readAllStandardError()).trimmed();
|
||||||
|
if (!errMsg.isEmpty())
|
||||||
|
{
|
||||||
|
qWarning("%s", qUtf8Printable(errMsg));
|
||||||
|
LogMsg(tr("Error occurred when downloading torrent via search engine. Engine: \"%1\". URL: \"%2\". Error: \"%3\".")
|
||||||
|
.arg(m_pluginName, m_url, errMsg), Log::WARNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString path;
|
||||||
if ((exitcode == 0) && (m_downloadProcess->exitStatus() == QProcess::NormalExit))
|
if ((exitcode == 0) && (m_downloadProcess->exitStatus() == QProcess::NormalExit))
|
||||||
{
|
{
|
||||||
const QString line = QString::fromUtf8(m_downloadProcess->readAllStandardOutput()).trimmed();
|
const QString line = QString::fromUtf8(m_downloadProcess->readAllStandardOutput()).trimmed();
|
||||||
@@ -70,5 +81,5 @@ void SearchDownloadHandler::downloadProcessFinished(int exitcode)
|
|||||||
path = parts[0].toString();
|
path = parts[0].toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
emit downloadFinished(path);
|
emit downloadFinished(path, errMsg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
class QProcess;
|
class QProcess;
|
||||||
|
|
||||||
@@ -44,11 +45,13 @@ class SearchDownloadHandler : public QObject
|
|||||||
SearchDownloadHandler(const QString &pluginName, const QString &url, SearchPluginManager *manager);
|
SearchDownloadHandler(const QString &pluginName, const QString &url, SearchPluginManager *manager);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void downloadFinished(const QString &path);
|
void downloadFinished(const QString &path, const QString &errorMessage);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void downloadProcessFinished(int exitcode);
|
void downloadProcessFinished(int exitcode);
|
||||||
|
|
||||||
|
QString m_pluginName;
|
||||||
|
QString m_url;
|
||||||
SearchPluginManager *m_manager = nullptr;
|
SearchPluginManager *m_manager = nullptr;
|
||||||
QProcess *m_downloadProcess = nullptr;
|
QProcess *m_downloadProcess = nullptr;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,12 +31,14 @@
|
|||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
|
#include <QtLogging>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QMetaObject>
|
#include <QMetaObject>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#include "base/global.h"
|
#include "base/global.h"
|
||||||
|
#include "base/logger.h"
|
||||||
#include "base/path.h"
|
#include "base/path.h"
|
||||||
#include "base/utils/bytearray.h"
|
#include "base/utils/bytearray.h"
|
||||||
#include "base/utils/foreignapps.h"
|
#include "base/utils/foreignapps.h"
|
||||||
@@ -59,6 +61,26 @@ namespace
|
|||||||
PL_PUB_DATE,
|
PL_PUB_DATE,
|
||||||
NB_PLUGIN_COLUMNS
|
NB_PLUGIN_COLUMNS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
QString toString(const QProcess::ProcessError error)
|
||||||
|
{
|
||||||
|
switch (error)
|
||||||
|
{
|
||||||
|
case QProcess::FailedToStart:
|
||||||
|
return SearchHandler::tr("Process failed to start");
|
||||||
|
case QProcess::Crashed:
|
||||||
|
return SearchHandler::tr("Process crashed");
|
||||||
|
case QProcess::Timedout:
|
||||||
|
return SearchHandler::tr("Process timed out");
|
||||||
|
case QProcess::WriteError:
|
||||||
|
return SearchHandler::tr("Process write error");
|
||||||
|
case QProcess::ReadError:
|
||||||
|
return SearchHandler::tr("Process read error");
|
||||||
|
case QProcess::UnknownError:
|
||||||
|
return SearchHandler::tr("Process unknown error");
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
SearchHandler::SearchHandler(const QString &pattern, const QString &category, const QStringList &usedPlugins, SearchPluginManager *manager)
|
SearchHandler::SearchHandler(const QString &pattern, const QString &category, const QStringList &usedPlugins, SearchPluginManager *manager)
|
||||||
@@ -86,7 +108,16 @@ SearchHandler::SearchHandler(const QString &pattern, const QString &category, co
|
|||||||
};
|
};
|
||||||
m_searchProcess->setArguments(params + m_pattern.split(u' '));
|
m_searchProcess->setArguments(params + m_pattern.split(u' '));
|
||||||
|
|
||||||
connect(m_searchProcess, &QProcess::errorOccurred, this, &SearchHandler::processFailed);
|
connect(m_searchProcess, &QProcess::errorOccurred, this, [this](const QProcess::ProcessError error)
|
||||||
|
{
|
||||||
|
if (!m_searchCancelled)
|
||||||
|
{
|
||||||
|
const auto errMsg = toString(error);
|
||||||
|
LogMsg(tr("Search process failed. Search query: \"%1\". Category: \"%2\". Engines: \"%3\". Error: \"%4\".")
|
||||||
|
.arg(m_pattern, m_category, m_usedPlugins.join(u", "), errMsg), Log::WARNING);
|
||||||
|
emit searchFailed(errMsg);
|
||||||
|
}
|
||||||
|
});
|
||||||
connect(m_searchProcess, &QProcess::readyReadStandardOutput, this, &SearchHandler::readSearchOutput);
|
connect(m_searchProcess, &QProcess::readyReadStandardOutput, this, &SearchHandler::readSearchOutput);
|
||||||
connect(m_searchProcess, qOverload<int, QProcess::ExitStatus>(&QProcess::finished)
|
connect(m_searchProcess, qOverload<int, QProcess::ExitStatus>(&QProcess::finished)
|
||||||
, this, &SearchHandler::processFinished);
|
, this, &SearchHandler::processFinished);
|
||||||
@@ -127,12 +158,20 @@ void SearchHandler::processFinished(const int exitcode)
|
|||||||
{
|
{
|
||||||
m_searchTimeout->stop();
|
m_searchTimeout->stop();
|
||||||
|
|
||||||
|
const auto errMsg = QString::fromUtf8(m_searchProcess->readAllStandardError()).trimmed();
|
||||||
|
if (!errMsg.isEmpty())
|
||||||
|
{
|
||||||
|
qWarning("%s", qUtf8Printable(errMsg));
|
||||||
|
LogMsg(tr("Error occurred in search engine. Search query: \"%1\". Category: \"%2\". Engines: \"%3\". Error: \"%4\".")
|
||||||
|
.arg(m_pattern, m_category, m_usedPlugins.join(u", "), errMsg), Log::WARNING);
|
||||||
|
}
|
||||||
|
|
||||||
if (m_searchCancelled)
|
if (m_searchCancelled)
|
||||||
emit searchFinished(true);
|
emit searchFinished(true);
|
||||||
else if ((m_searchProcess->exitStatus() == QProcess::NormalExit) && (exitcode == 0))
|
else if ((m_searchProcess->exitStatus() == QProcess::NormalExit) && (exitcode == 0))
|
||||||
emit searchFinished(false);
|
emit searchFinished(false);
|
||||||
else
|
else
|
||||||
emit searchFailed();
|
emit searchFailed(errMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// search QProcess return output as soon as it gets new
|
// search QProcess return output as soon as it gets new
|
||||||
@@ -161,12 +200,6 @@ void SearchHandler::readSearchOutput()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchHandler::processFailed()
|
|
||||||
{
|
|
||||||
if (!m_searchCancelled)
|
|
||||||
emit searchFailed();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse one line of search results list
|
// Parse one line of search results list
|
||||||
// Line is in the following form:
|
// Line is in the following form:
|
||||||
// file url | file name | file size | nb seeds | nb leechers | Search engine url
|
// file url | file name | file size | nb seeds | nb leechers | Search engine url
|
||||||
|
|||||||
@@ -74,12 +74,11 @@ public:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void searchFinished(bool cancelled = false);
|
void searchFinished(bool cancelled = false);
|
||||||
void searchFailed();
|
void searchFailed(const QString &errorMessage);
|
||||||
void newSearchResults(const QList<SearchResult> &results);
|
void newSearchResults(const QList<SearchResult> &results);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void readSearchOutput();
|
void readSearchOutput();
|
||||||
void processFailed();
|
|
||||||
void processFinished(int exitcode);
|
void processFinished(int exitcode);
|
||||||
bool parseSearchResult(QByteArrayView line, SearchResult &searchResult);
|
bool parseSearchResult(QByteArrayView line, SearchResult &searchResult);
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include <QtLogging>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include <QDomDocument>
|
#include <QDomDocument>
|
||||||
@@ -559,6 +560,13 @@ void SearchPluginManager::update()
|
|||||||
nova.start(Utils::ForeignApps::pythonInfo().executablePath.data(), params, QIODevice::ReadOnly);
|
nova.start(Utils::ForeignApps::pythonInfo().executablePath.data(), params, QIODevice::ReadOnly);
|
||||||
nova.waitForFinished();
|
nova.waitForFinished();
|
||||||
|
|
||||||
|
if (const auto errMsg = QString::fromUtf8(nova.readAllStandardError()).trimmed()
|
||||||
|
; !errMsg.isEmpty())
|
||||||
|
{
|
||||||
|
qWarning("%s", qUtf8Printable(errMsg));
|
||||||
|
LogMsg(tr("Error occurred when fetching search engine capabilities. Error: \"%1\".").arg(errMsg), Log::WARNING);
|
||||||
|
}
|
||||||
|
|
||||||
const auto capabilities = QString::fromUtf8(nova.readAllStandardOutput());
|
const auto capabilities = QString::fromUtf8(nova.readAllStandardOutput());
|
||||||
QDomDocument xmlDoc;
|
QDomDocument xmlDoc;
|
||||||
if (!xmlDoc.setContent(capabilities))
|
if (!xmlDoc.setContent(capabilities))
|
||||||
|
|||||||
@@ -64,10 +64,12 @@ namespace
|
|||||||
return QApplication::palette().color(QPalette::Disabled, QPalette::WindowText);
|
return QApplication::palette().color(QPalette::Disabled, QPalette::WindowText);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString statusText(SearchJobWidget::Status st)
|
QString statusText(const SearchJobWidget::Status st)
|
||||||
{
|
{
|
||||||
switch (st)
|
switch (st)
|
||||||
{
|
{
|
||||||
|
case SearchJobWidget::Status::Ready:
|
||||||
|
break;
|
||||||
case SearchJobWidget::Status::Ongoing:
|
case SearchJobWidget::Status::Ongoing:
|
||||||
return SearchJobWidget::tr("Searching...");
|
return SearchJobWidget::tr("Searching...");
|
||||||
case SearchJobWidget::Status::Finished:
|
case SearchJobWidget::Status::Finished:
|
||||||
@@ -78,9 +80,8 @@ namespace
|
|||||||
return SearchJobWidget::tr("An error occurred during search...");
|
return SearchJobWidget::tr("An error occurred during search...");
|
||||||
case SearchJobWidget::Status::NoResults:
|
case SearchJobWidget::Status::NoResults:
|
||||||
return SearchJobWidget::tr("Search returned no results");
|
return SearchJobWidget::tr("Search returned no results");
|
||||||
default:
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -402,7 +403,7 @@ void SearchJobWidget::copyField(const int column) const
|
|||||||
QApplication::clipboard()->setText(list.join(u'\n'));
|
QApplication::clipboard()->setText(list.join(u'\n'));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchJobWidget::setStatus(Status value)
|
void SearchJobWidget::setStatus(const Status value)
|
||||||
{
|
{
|
||||||
if (m_status == value)
|
if (m_status == value)
|
||||||
return;
|
return;
|
||||||
@@ -426,9 +427,12 @@ void SearchJobWidget::downloadTorrent(const QModelIndex &rowIndex, const AddTorr
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
SearchDownloadHandler *downloadHandler = SearchPluginManager::instance()->downloadTorrent(engineName, torrentUrl);
|
SearchDownloadHandler *downloadHandler = SearchPluginManager::instance()->downloadTorrent(engineName, torrentUrl);
|
||||||
connect(downloadHandler, &SearchDownloadHandler::downloadFinished
|
connect(downloadHandler, &SearchDownloadHandler::downloadFinished, this
|
||||||
, this, [this, option](const QString &source) { addTorrentToSession(source, option); });
|
, [this, downloadHandler, option](const QString &source, [[maybe_unused]] const QString &errorMessage)
|
||||||
connect(downloadHandler, &SearchDownloadHandler::downloadFinished, downloadHandler, &SearchDownloadHandler::deleteLater);
|
{
|
||||||
|
addTorrentToSession(source, option);
|
||||||
|
downloadHandler->deleteLater();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setRowVisited(rowIndex.row());
|
setRowVisited(rowIndex.row());
|
||||||
@@ -631,7 +635,7 @@ void SearchJobWidget::searchFinished(bool cancelled)
|
|||||||
setStatus(Status::Finished);
|
setStatus(Status::Finished);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchJobWidget::searchFailed()
|
void SearchJobWidget::searchFailed([[maybe_unused]] const QString &errorMessage)
|
||||||
{
|
{
|
||||||
setStatus(Status::Error);
|
setStatus(Status::Error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ private:
|
|||||||
void contextMenuEvent(QContextMenuEvent *event) override;
|
void contextMenuEvent(QContextMenuEvent *event) override;
|
||||||
void onItemDoubleClicked(const QModelIndex &index);
|
void onItemDoubleClicked(const QModelIndex &index);
|
||||||
void searchFinished(bool cancelled);
|
void searchFinished(bool cancelled);
|
||||||
void searchFailed();
|
void searchFailed(const QString &errorMessage);
|
||||||
void appendSearchResults(const QList<SearchResult> &results);
|
void appendSearchResults(const QList<SearchResult> &results);
|
||||||
void updateResultsCount();
|
void updateResultsCount();
|
||||||
void setStatus(Status value);
|
void setStatus(Status value);
|
||||||
|
|||||||
@@ -114,8 +114,8 @@ void SearchController::startAction()
|
|||||||
|
|
||||||
const auto id = generateSearchId();
|
const auto id = generateSearchId();
|
||||||
const std::shared_ptr<SearchHandler> searchHandler {SearchPluginManager::instance()->startSearch(pattern, category, pluginsToUse)};
|
const std::shared_ptr<SearchHandler> searchHandler {SearchPluginManager::instance()->startSearch(pattern, category, pluginsToUse)};
|
||||||
QObject::connect(searchHandler.get(), &SearchHandler::searchFinished, this, [id, this]() { m_activeSearches.remove(id); });
|
connect(searchHandler.get(), &SearchHandler::searchFinished, this, [this, id] { m_activeSearches.remove(id); });
|
||||||
QObject::connect(searchHandler.get(), &SearchHandler::searchFailed, this, [id, this]() { m_activeSearches.remove(id); });
|
connect(searchHandler.get(), &SearchHandler::searchFailed, this, [this, id]([[maybe_unused]] const QString &errorMessage) { m_activeSearches.remove(id); });
|
||||||
|
|
||||||
m_searchHandlers.insert(id, searchHandler);
|
m_searchHandlers.insert(id, searchHandler);
|
||||||
|
|
||||||
@@ -235,8 +235,8 @@ void SearchController::downloadTorrentAction()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
SearchDownloadHandler *downloadHandler = SearchPluginManager::instance()->downloadTorrent(pluginName, torrentUrl);
|
SearchDownloadHandler *downloadHandler = SearchPluginManager::instance()->downloadTorrent(pluginName, torrentUrl);
|
||||||
connect(downloadHandler, &SearchDownloadHandler::downloadFinished
|
connect(downloadHandler, &SearchDownloadHandler::downloadFinished, this
|
||||||
, this, [this, downloadHandler](const QString &source)
|
, [this, downloadHandler](const QString &source, [[maybe_unused]] const QString &errorMessage)
|
||||||
{
|
{
|
||||||
app()->addTorrentManager()->addTorrent(source);
|
app()->addTorrentManager()->addTorrent(source);
|
||||||
downloadHandler->deleteLater();
|
downloadHandler->deleteLater();
|
||||||
|
|||||||
@@ -503,7 +503,7 @@
|
|||||||
const iframeElement = document.createElement("iframe");
|
const iframeElement = document.createElement("iframe");
|
||||||
iframeElement.id = "rssDescription";
|
iframeElement.id = "rssDescription";
|
||||||
iframeElement.sandbox = "allow-same-origin"; // allowed to get parent css
|
iframeElement.sandbox = "allow-same-origin"; // allowed to get parent css
|
||||||
iframeElement.srcdoc = `<html ${rootColor}><head><meta charset="utf-8"><link rel="stylesheet" type="text/css" href="css/style.css?v=${CACHEID}"></head><body>${articleDescription}</body></html>`;
|
iframeElement.srcdoc = `<html ${rootColor}><head><meta charset="utf-8"><meta name="referrer" content="same-origin"><link rel="stylesheet" type="text/css" href="css/style.css?v=${CACHEID}"></head><body>${articleDescription}</body></html>`;
|
||||||
|
|
||||||
detailsView.append(iframeElement);
|
detailsView.append(iframeElement);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user