Skip to content

Commit

Permalink
WebAPI: Add a way to download .torrent file using search plugin
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
glassez committed May 15, 2024
1 parent 2c47f09 commit 4d8713c
Show file tree
Hide file tree
Showing 11 changed files with 89 additions and 50 deletions.
10 changes: 5 additions & 5 deletions src/base/search/searchdownloadhandler.cpp
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/base/search/searchdownloadhandler.h
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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);
Expand Down
14 changes: 8 additions & 6 deletions src/base/search/searchhandler.cpp
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/base/search/searchhandler.h
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -46,6 +46,7 @@ struct SearchResult
qlonglong fileSize = 0;
qlonglong nbSeeders = 0;
qlonglong nbLeechers = 0;
QString engineName;
QString siteUrl;
QString descrLink;
QDateTime pubDate;
Expand Down
17 changes: 14 additions & 3 deletions src/base/search/searchpluginmanager.cpp
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down
5 changes: 3 additions & 2 deletions src/base/search/searchpluginmanager.h
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -75,6 +75,7 @@ class SearchPluginManager final : public QObject
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);
Expand All @@ -84,7 +85,7 @@ class SearchPluginManager final : public QObject
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);
Expand Down
12 changes: 7 additions & 5 deletions src/gui/search/searchjobwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -269,16 +270,16 @@ 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))
{
addTorrentToSession(torrentUrl, option);
}
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);
Expand Down Expand Up @@ -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 =
{
Expand All @@ -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));
Expand Down
1 change: 1 addition & 0 deletions src/gui/search/searchsortmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class SearchSortModel final : public QSortFilterProxyModel
SIZE,
SEEDS,
LEECHES,
ENGINE_NAME,
ENGINE_URL,
PUB_DATE,
DL_LINK,
Expand Down
42 changes: 16 additions & 26 deletions src/searchengine/nova3/nova2dl.py
Original file line number Diff line number Diff line change
@@ -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:
Expand All @@ -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

Expand All @@ -40,34 +40,24 @@

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)
29 changes: 29 additions & 0 deletions src/webui/api/searchcontroller.cpp
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -300,6 +327,7 @@ int SearchController::generateSearchId() const
* - "fileSize"
* - "nbSeeders"
* - "nbLeechers"
* - "engineName"
* - "siteUrl"
* - "descrLink"
* - "pubDate"
Expand All @@ -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)}
Expand Down
2 changes: 2 additions & 0 deletions src/webui/api/searchcontroller.h
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -56,6 +57,7 @@ private slots:
void statusAction();
void resultsAction();
void deleteAction();
void downloadTorrentAction();
void pluginsAction();
void installPluginAction();
void uninstallPluginAction();
Expand Down

0 comments on commit 4d8713c

Please sign in to comment.