mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2024-11-27 03:30:34 +00:00
WebAPI: Add a way to download .torrent file using search plugin
* Simplify nova2dl script * Use search engine name instead of site URL (like nova2 does) * Add a way to download torrent using search plugin PR #20824.
This commit is contained in:
parent
2c47f09d7a
commit
4d8713ce11
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2018 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2018-2024 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@ -36,10 +36,10 @@
|
||||
#include "base/utils/fs.h"
|
||||
#include "searchpluginmanager.h"
|
||||
|
||||
SearchDownloadHandler::SearchDownloadHandler(const QString &siteUrl, const QString &url, SearchPluginManager *manager)
|
||||
: QObject {manager}
|
||||
SearchDownloadHandler::SearchDownloadHandler(const QString &pluginName, const QString &url, SearchPluginManager *manager)
|
||||
: QObject(manager)
|
||||
, m_manager {manager}
|
||||
, m_downloadProcess {new QProcess {this}}
|
||||
, m_downloadProcess {new QProcess(this)}
|
||||
{
|
||||
m_downloadProcess->setEnvironment(QProcess::systemEnvironment());
|
||||
connect(m_downloadProcess, qOverload<int, QProcess::ExitStatus>(&QProcess::finished)
|
||||
@ -48,7 +48,7 @@ SearchDownloadHandler::SearchDownloadHandler(const QString &siteUrl, const QStri
|
||||
{
|
||||
Utils::ForeignApps::PYTHON_ISOLATE_MODE_FLAG,
|
||||
(SearchPluginManager::engineLocation() / Path(u"nova2dl.py"_s)).toString(),
|
||||
siteUrl,
|
||||
pluginName,
|
||||
url
|
||||
};
|
||||
// Launch search
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2018 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2018-2024 Vladimir Golovnev <glassez@yandex.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@ -41,7 +41,7 @@ class SearchDownloadHandler : public QObject
|
||||
|
||||
friend class SearchPluginManager;
|
||||
|
||||
SearchDownloadHandler(const QString &siteUrl, const QString &url, SearchPluginManager *manager);
|
||||
SearchDownloadHandler(const QString &pluginName, const QString &url, SearchPluginManager *manager);
|
||||
|
||||
signals:
|
||||
void downloadFinished(const QString &path);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015, 2018 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2015-2024 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@ -61,13 +61,13 @@ namespace
|
||||
}
|
||||
|
||||
SearchHandler::SearchHandler(const QString &pattern, const QString &category, const QStringList &usedPlugins, SearchPluginManager *manager)
|
||||
: QObject {manager}
|
||||
: QObject(manager)
|
||||
, m_pattern {pattern}
|
||||
, m_category {category}
|
||||
, m_usedPlugins {usedPlugins}
|
||||
, m_manager {manager}
|
||||
, m_searchProcess {new QProcess {this}}
|
||||
, m_searchTimeout {new QTimer {this}}
|
||||
, m_searchProcess {new QProcess(this)}
|
||||
, m_searchTimeout {new QTimer(this)}
|
||||
{
|
||||
// Load environment variables (proxy)
|
||||
m_searchProcess->setEnvironment(QProcess::systemEnvironment());
|
||||
@ -177,7 +177,8 @@ bool SearchHandler::parseSearchResult(const QStringView line, SearchResult &sear
|
||||
const QList<QStringView> parts = line.split(u'|');
|
||||
const int nbFields = parts.size();
|
||||
|
||||
if (nbFields <= PL_ENGINE_URL) return false; // Anything after ENGINE_URL is optional
|
||||
if (nbFields <= PL_ENGINE_URL)
|
||||
return false; // Anything after ENGINE_URL is optional
|
||||
|
||||
searchResult = SearchResult();
|
||||
searchResult.fileUrl = parts.at(PL_DL_LINK).trimmed().toString(); // download URL
|
||||
@ -194,7 +195,8 @@ bool SearchHandler::parseSearchResult(const QStringView line, SearchResult &sear
|
||||
if (!ok || (searchResult.nbLeechers < 0))
|
||||
searchResult.nbLeechers = -1;
|
||||
|
||||
searchResult.siteUrl = parts.at(PL_ENGINE_URL).trimmed().toString(); // Search site URL
|
||||
searchResult.siteUrl = parts.at(PL_ENGINE_URL).trimmed().toString(); // Search engine site URL
|
||||
searchResult.engineName = m_manager->pluginNameBySiteURL(searchResult.siteUrl); // Search engine name
|
||||
|
||||
if (nbFields > PL_DESC_LINK)
|
||||
searchResult.descrLink = parts.at(PL_DESC_LINK).trimmed().toString(); // Description Link
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015, 2018 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2015-2024 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@ -46,6 +46,7 @@ struct SearchResult
|
||||
qlonglong fileSize = 0;
|
||||
qlonglong nbSeeders = 0;
|
||||
qlonglong nbLeechers = 0;
|
||||
QString engineName;
|
||||
QString siteUrl;
|
||||
QString descrLink;
|
||||
QDateTime pubDate;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015, 2018 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2015-2024 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@ -181,6 +181,17 @@ PluginInfo *SearchPluginManager::pluginInfo(const QString &name) const
|
||||
return m_plugins.value(name);
|
||||
}
|
||||
|
||||
QString SearchPluginManager::pluginNameBySiteURL(const QString &siteURL) const
|
||||
{
|
||||
for (const PluginInfo *plugin : asConst(m_plugins))
|
||||
{
|
||||
if (plugin->url == siteURL)
|
||||
return plugin->name;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void SearchPluginManager::enablePlugin(const QString &name, const bool enabled)
|
||||
{
|
||||
PluginInfo *plugin = m_plugins.value(name, nullptr);
|
||||
@ -338,9 +349,9 @@ void SearchPluginManager::checkForUpdates()
|
||||
, this, &SearchPluginManager::versionInfoDownloadFinished);
|
||||
}
|
||||
|
||||
SearchDownloadHandler *SearchPluginManager::downloadTorrent(const QString &siteUrl, const QString &url)
|
||||
SearchDownloadHandler *SearchPluginManager::downloadTorrent(const QString &pluginName, const QString &url)
|
||||
{
|
||||
return new SearchDownloadHandler {siteUrl, url, this};
|
||||
return new SearchDownloadHandler(pluginName, url, this);
|
||||
}
|
||||
|
||||
SearchHandler *SearchPluginManager::startSearch(const QString &pattern, const QString &category, const QStringList &usedPlugins)
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015, 2018 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2015-2024 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@ -75,6 +75,7 @@ public:
|
||||
QStringList supportedCategories() const;
|
||||
QStringList getPluginCategories(const QString &pluginName) const;
|
||||
PluginInfo *pluginInfo(const QString &name) const;
|
||||
QString pluginNameBySiteURL(const QString &siteURL) const;
|
||||
|
||||
void enablePlugin(const QString &name, bool enabled = true);
|
||||
void updatePlugin(const QString &name);
|
||||
@ -84,7 +85,7 @@ public:
|
||||
void checkForUpdates();
|
||||
|
||||
SearchHandler *startSearch(const QString &pattern, const QString &category, const QStringList &usedPlugins);
|
||||
SearchDownloadHandler *downloadTorrent(const QString &siteUrl, const QString &url);
|
||||
SearchDownloadHandler *downloadTorrent(const QString &pluginName, const QString &url);
|
||||
|
||||
static PluginVersion getPluginVersion(const Path &filePath);
|
||||
static QString categoryFullName(const QString &categoryName);
|
||||
|
@ -70,7 +70,8 @@ SearchJobWidget::SearchJobWidget(SearchHandler *searchHandler, IGUIApplication *
|
||||
m_searchListModel->setHeaderData(SearchSortModel::SIZE, Qt::Horizontal, tr("Size", "i.e: file size"));
|
||||
m_searchListModel->setHeaderData(SearchSortModel::SEEDS, Qt::Horizontal, tr("Seeders", "i.e: Number of full sources"));
|
||||
m_searchListModel->setHeaderData(SearchSortModel::LEECHES, Qt::Horizontal, tr("Leechers", "i.e: Number of partial sources"));
|
||||
m_searchListModel->setHeaderData(SearchSortModel::ENGINE_URL, Qt::Horizontal, tr("Search engine"));
|
||||
m_searchListModel->setHeaderData(SearchSortModel::ENGINE_NAME, Qt::Horizontal, tr("Engine"));
|
||||
m_searchListModel->setHeaderData(SearchSortModel::ENGINE_URL, Qt::Horizontal, tr("Engine URL"));
|
||||
m_searchListModel->setHeaderData(SearchSortModel::PUB_DATE, Qt::Horizontal, tr("Published On"));
|
||||
// Set columns text alignment
|
||||
m_searchListModel->setHeaderData(SearchSortModel::SIZE, Qt::Horizontal, QVariant(Qt::AlignRight | Qt::AlignVCenter), Qt::TextAlignmentRole);
|
||||
@ -269,8 +270,8 @@ void SearchJobWidget::downloadTorrent(const QModelIndex &rowIndex, const AddTorr
|
||||
{
|
||||
const QString torrentUrl = m_proxyModel->data(
|
||||
m_proxyModel->index(rowIndex.row(), SearchSortModel::DL_LINK)).toString();
|
||||
const QString siteUrl = m_proxyModel->data(
|
||||
m_proxyModel->index(rowIndex.row(), SearchSortModel::ENGINE_URL)).toString();
|
||||
const QString engineName = m_proxyModel->data(
|
||||
m_proxyModel->index(rowIndex.row(), SearchSortModel::ENGINE_NAME)).toString();
|
||||
|
||||
if (torrentUrl.startsWith(u"magnet:", Qt::CaseInsensitive))
|
||||
{
|
||||
@ -278,7 +279,7 @@ void SearchJobWidget::downloadTorrent(const QModelIndex &rowIndex, const AddTorr
|
||||
}
|
||||
else
|
||||
{
|
||||
SearchDownloadHandler *downloadHandler = m_searchHandler->manager()->downloadTorrent(siteUrl, torrentUrl);
|
||||
SearchDownloadHandler *downloadHandler = m_searchHandler->manager()->downloadTorrent(engineName, torrentUrl);
|
||||
connect(downloadHandler, &SearchDownloadHandler::downloadFinished
|
||||
, this, [this, option](const QString &source) { addTorrentToSession(source, option); });
|
||||
connect(downloadHandler, &SearchDownloadHandler::downloadFinished, downloadHandler, &SearchDownloadHandler::deleteLater);
|
||||
@ -516,7 +517,7 @@ void SearchJobWidget::appendSearchResults(const QVector<SearchResult> &results)
|
||||
m_searchListModel->insertRow(row);
|
||||
|
||||
const auto setModelData = [this, row] (const int column, const QString &displayData
|
||||
, const QVariant &underlyingData, const Qt::Alignment textAlignmentData = {})
|
||||
, const QVariant &underlyingData, const Qt::Alignment textAlignmentData = {})
|
||||
{
|
||||
const QMap<int, QVariant> data =
|
||||
{
|
||||
@ -529,6 +530,7 @@ void SearchJobWidget::appendSearchResults(const QVector<SearchResult> &results)
|
||||
|
||||
setModelData(SearchSortModel::NAME, result.fileName, result.fileName);
|
||||
setModelData(SearchSortModel::DL_LINK, result.fileUrl, result.fileUrl);
|
||||
setModelData(SearchSortModel::ENGINE_NAME, result.engineName, result.engineName);
|
||||
setModelData(SearchSortModel::ENGINE_URL, result.siteUrl, result.siteUrl);
|
||||
setModelData(SearchSortModel::DESC_LINK, result.descrLink, result.descrLink);
|
||||
setModelData(SearchSortModel::SIZE, Utils::Misc::friendlyUnit(result.fileSize), result.fileSize, (Qt::AlignRight | Qt::AlignVCenter));
|
||||
|
@ -44,6 +44,7 @@ public:
|
||||
SIZE,
|
||||
SEEDS,
|
||||
LEECHES,
|
||||
ENGINE_NAME,
|
||||
ENGINE_URL,
|
||||
PUB_DATE,
|
||||
DL_LINK,
|
||||
|
@ -1,7 +1,9 @@
|
||||
#VERSION: 1.23
|
||||
#VERSION: 1.24
|
||||
|
||||
# Author:
|
||||
# Christophe DUMEZ (chris@qbittorrent.org)
|
||||
# Contributors:
|
||||
# Vladimir Golovnev (glassez@yandex.ru)
|
||||
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
@ -27,9 +29,7 @@
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import glob
|
||||
import importlib
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
@ -40,34 +40,24 @@ if current_path not in sys.path:
|
||||
|
||||
from helpers import download_file
|
||||
|
||||
supported_engines = dict()
|
||||
|
||||
engines = glob.glob(os.path.join(os.path.dirname(__file__), 'engines', '*.py'))
|
||||
for engine in engines:
|
||||
e = engine.split(os.sep)[-1][:-3]
|
||||
if len(e.strip()) == 0:
|
||||
continue
|
||||
if e.startswith('_'):
|
||||
continue
|
||||
try:
|
||||
module = importlib.import_module("engines." + e)
|
||||
engine_class = getattr(module, e)
|
||||
globals()[e] = engine_class
|
||||
engine_url = getattr(engine_class, 'url')
|
||||
supported_engines[engine_url] = e
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 3:
|
||||
raise SystemExit('./nova2dl.py engine_url download_parameter')
|
||||
engine_url = sys.argv[1].strip()
|
||||
raise SystemExit('./nova2dl.py engine_name download_parameter')
|
||||
|
||||
engine_name = sys.argv[1].strip()
|
||||
download_param = sys.argv[2].strip()
|
||||
if engine_url not in supported_engines.keys():
|
||||
raise SystemExit('./nova2dl.py: this engine_url was not recognized')
|
||||
engine = globals()[supported_engines[engine_url]]()
|
||||
|
||||
try:
|
||||
module = importlib.import_module("engines." + engine_name)
|
||||
engine_class = getattr(module, engine_name)
|
||||
engine = engine_class()
|
||||
except Exception as e:
|
||||
print(repr(e))
|
||||
raise SystemExit('./nova2dl.py: this engine_name was not recognized')
|
||||
|
||||
if hasattr(engine, 'download_torrent'):
|
||||
engine.download_torrent(download_param)
|
||||
else:
|
||||
print(download_file(download_param))
|
||||
|
||||
sys.exit(0)
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2024 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2018 Thomas Piccirello <thomas.piccirello@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@ -36,8 +37,11 @@
|
||||
#include <QList>
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include "base/addtorrentmanager.h"
|
||||
#include "base/global.h"
|
||||
#include "base/interfaces/iapplication.h"
|
||||
#include "base/logger.h"
|
||||
#include "base/search/searchdownloadhandler.h"
|
||||
#include "base/search/searchhandler.h"
|
||||
#include "base/utils/datetime.h"
|
||||
#include "base/utils/foreignapps.h"
|
||||
@ -213,6 +217,29 @@ void SearchController::deleteAction()
|
||||
m_searchHandlers.erase(iter);
|
||||
}
|
||||
|
||||
void SearchController::downloadTorrentAction()
|
||||
{
|
||||
requireParams({u"torrentUrl"_s, u"pluginName"_s});
|
||||
|
||||
const QString torrentUrl = params()[u"torrentUrl"_s];
|
||||
const QString pluginName = params()[u"pluginName"_s];
|
||||
|
||||
if (torrentUrl.startsWith(u"magnet:", Qt::CaseInsensitive))
|
||||
{
|
||||
app()->addTorrentManager()->addTorrent(torrentUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
SearchDownloadHandler *downloadHandler = SearchPluginManager::instance()->downloadTorrent(pluginName, torrentUrl);
|
||||
connect(downloadHandler, &SearchDownloadHandler::downloadFinished
|
||||
, this, [this, downloadHandler](const QString &source)
|
||||
{
|
||||
app()->addTorrentManager()->addTorrent(source);
|
||||
downloadHandler->deleteLater();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void SearchController::pluginsAction()
|
||||
{
|
||||
const QStringList allPlugins = SearchPluginManager::instance()->allPlugins();
|
||||
@ -300,6 +327,7 @@ int SearchController::generateSearchId() const
|
||||
* - "fileSize"
|
||||
* - "nbSeeders"
|
||||
* - "nbLeechers"
|
||||
* - "engineName"
|
||||
* - "siteUrl"
|
||||
* - "descrLink"
|
||||
* - "pubDate"
|
||||
@ -316,6 +344,7 @@ QJsonObject SearchController::getResults(const QList<SearchResult> &searchResult
|
||||
{u"fileSize"_s, searchResult.fileSize},
|
||||
{u"nbSeeders"_s, searchResult.nbSeeders},
|
||||
{u"nbLeechers"_s, searchResult.nbLeechers},
|
||||
{u"engineName"_s, searchResult.engineName},
|
||||
{u"siteUrl"_s, searchResult.siteUrl},
|
||||
{u"descrLink"_s, searchResult.descrLink},
|
||||
{u"pubDate"_s, Utils::DateTime::toSecsSinceEpoch(searchResult.pubDate)}
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2024 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2018 Thomas Piccirello <thomas.piccirello@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@ -56,6 +57,7 @@ private slots:
|
||||
void statusAction();
|
||||
void resultsAction();
|
||||
void deleteAction();
|
||||
void downloadTorrentAction();
|
||||
void pluginsAction();
|
||||
void installPluginAction();
|
||||
void uninstallPluginAction();
|
||||
|
Loading…
Reference in New Issue
Block a user