mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2024-11-22 09:16:05 +03:00
- Search engine now supports category-based requests (only Mininova engine for now but the rest is coming soon)
- Updated "buy it" icon
This commit is contained in:
parent
b8d8862562
commit
4a1c8a7279
19 changed files with 628 additions and 532 deletions
|
@ -1,5 +1,6 @@
|
||||||
* Unknown - Christophe Dumez <chris@qbittorrent.org> - v1.5.0
|
* Unknown - Christophe Dumez <chris@qbittorrent.org> - v1.5.0
|
||||||
- FEATURE: Added Magnet URI support
|
- FEATURE: Added Magnet URI support
|
||||||
|
- FEATURE: Search engine supports category-based requests
|
||||||
- FEATURE: Make use of torrent enclosure in RSS feeds for direct download
|
- FEATURE: Make use of torrent enclosure in RSS feeds for direct download
|
||||||
- FEATURE: Implemented a RSS feed downloader with filter support
|
- FEATURE: Implemented a RSS feed downloader with filter support
|
||||||
- FEATURE: Save old RSS item to hard disk to remember them on start up
|
- FEATURE: Save old RSS item to hard disk to remember them on start up
|
||||||
|
|
|
@ -462,7 +462,7 @@ void FinishedTorrents::displayFinishedListMenu(const QPoint&){
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// hide/show columns menu
|
// hide/show columns menu
|
||||||
void FinishedTorrents::displayFinishedHoSMenu(const QPoint& pos){
|
void FinishedTorrents::displayFinishedHoSMenu(const QPoint&){
|
||||||
QMenu hideshowColumn(this);
|
QMenu hideshowColumn(this);
|
||||||
hideshowColumn.setTitle(tr("Hide or Show Column"));
|
hideshowColumn.setTitle(tr("Hide or Show Column"));
|
||||||
int lastCol = F_RATIO;
|
int lastCol = F_RATIO;
|
||||||
|
@ -470,7 +470,7 @@ void FinishedTorrents::displayFinishedHoSMenu(const QPoint& pos){
|
||||||
hideshowColumn.addAction(getActionHoSCol(i));
|
hideshowColumn.addAction(getActionHoSCol(i));
|
||||||
}
|
}
|
||||||
// Call menu
|
// Call menu
|
||||||
hideshowColumn.exec(mapToGlobal(pos)+QPoint(10,34));
|
hideshowColumn.exec(QCursor::pos());
|
||||||
}
|
}
|
||||||
|
|
||||||
// toggle hide/show a column
|
// toggle hide/show a column
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 813 B |
BIN
src/Icons/oxygen/wallet.png
Normal file
BIN
src/Icons/oxygen/wallet.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
|
@ -142,7 +142,7 @@
|
||||||
<action name="actionBuy_it">
|
<action name="actionBuy_it">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="icons.qrc">
|
<iconset resource="icons.qrc">
|
||||||
<normaloff>:/Icons/money.png</normaloff>:/Icons/money.png</iconset>
|
<normaloff>:/Icons/oxygen/wallet.png</normaloff>:/Icons/oxygen/wallet.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Buy it</string>
|
<string>Buy it</string>
|
||||||
|
|
|
@ -312,7 +312,7 @@ void DownloadingTorrents::displayDLListMenu(const QPoint&) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// hide/show columns menu
|
// hide/show columns menu
|
||||||
void DownloadingTorrents::displayDLHoSMenu(const QPoint& pos){
|
void DownloadingTorrents::displayDLHoSMenu(const QPoint&){
|
||||||
QMenu hideshowColumn(this);
|
QMenu hideshowColumn(this);
|
||||||
hideshowColumn.setTitle(tr("Hide or Show Column"));
|
hideshowColumn.setTitle(tr("Hide or Show Column"));
|
||||||
int lastCol;
|
int lastCol;
|
||||||
|
@ -325,7 +325,7 @@ void DownloadingTorrents::displayDLHoSMenu(const QPoint& pos){
|
||||||
hideshowColumn.addAction(getActionHoSCol(i));
|
hideshowColumn.addAction(getActionHoSCol(i));
|
||||||
}
|
}
|
||||||
// Call menu
|
// Call menu
|
||||||
hideshowColumn.exec(mapToGlobal(pos)+QPoint(10,10));
|
hideshowColumn.exec(QCursor::pos());
|
||||||
}
|
}
|
||||||
|
|
||||||
// toggle hide/show a column
|
// toggle hide/show a column
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
#include <QInputDialog>
|
#include <QInputDialog>
|
||||||
|
|
||||||
#ifdef HAVE_ZZIP
|
#ifdef HAVE_ZZIP
|
||||||
#include <zzip/zzip.h>
|
#include <zzip/zzip.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ENGINE_NAME 0
|
#define ENGINE_NAME 0
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
#define ENGINE_STATE 2
|
#define ENGINE_STATE 2
|
||||||
#define ENGINE_ID 3
|
#define ENGINE_ID 3
|
||||||
|
|
||||||
engineSelectDlg::engineSelectDlg(QWidget *parent) : QDialog(parent) {
|
engineSelectDlg::engineSelectDlg(QWidget *parent, SupportedEngines *supported_engines) : QDialog(parent), supported_engines(supported_engines) {
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
pluginsTree->header()->resizeSection(0, 170);
|
pluginsTree->header()->resizeSection(0, 170);
|
||||||
|
@ -66,14 +66,14 @@ engineSelectDlg::engineSelectDlg(QWidget *parent) : QDialog(parent) {
|
||||||
downloader = new downloadThread(this);
|
downloader = new downloadThread(this);
|
||||||
connect(downloader, SIGNAL(downloadFinished(QString, QString)), this, SLOT(processDownloadedFile(QString, QString)));
|
connect(downloader, SIGNAL(downloadFinished(QString, QString)), this, SLOT(processDownloadedFile(QString, QString)));
|
||||||
connect(downloader, SIGNAL(downloadFailure(QString, QString)), this, SLOT(handleDownloadFailure(QString, QString)));
|
connect(downloader, SIGNAL(downloadFailure(QString, QString)), this, SLOT(handleDownloadFailure(QString, QString)));
|
||||||
loadSupportedSearchEngines(true);
|
loadSupportedSearchEngines();
|
||||||
|
connect(supported_engines, SIGNAL(newSupportedEngine(QString)), this, SLOT(addNewEngine(QString)));
|
||||||
connect(pluginsTree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(toggleEngineState(QTreeWidgetItem*, int)));
|
connect(pluginsTree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(toggleEngineState(QTreeWidgetItem*, int)));
|
||||||
show();
|
show();
|
||||||
}
|
}
|
||||||
|
|
||||||
engineSelectDlg::~engineSelectDlg() {
|
engineSelectDlg::~engineSelectDlg() {
|
||||||
qDebug("Destroying engineSelectDlg");
|
qDebug("Destroying engineSelectDlg");
|
||||||
saveSettings();
|
|
||||||
emit enginesChanged();
|
emit enginesChanged();
|
||||||
qDebug("Before deleting downloader");
|
qDebug("Before deleting downloader");
|
||||||
delete downloader;
|
delete downloader;
|
||||||
|
@ -115,43 +115,24 @@ void engineSelectDlg::dragEnterEvent(QDragEnterEvent *event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void engineSelectDlg::saveSettings() {
|
|
||||||
qDebug("Saving engines settings");
|
|
||||||
QStringList known_engines;
|
|
||||||
QVariantList known_enginesEnabled;
|
|
||||||
QString engine;
|
|
||||||
foreach(engine, installed_engines.keys()) {
|
|
||||||
known_engines << engine;
|
|
||||||
known_enginesEnabled << QVariant(installed_engines.value(engine, true));
|
|
||||||
qDebug("Engine %s has state: %d", engine.toLocal8Bit().data(), installed_engines.value(engine, true));
|
|
||||||
}
|
|
||||||
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
|
|
||||||
settings.setValue(QString::fromUtf8("SearchEngines/knownEngines"), known_engines);
|
|
||||||
settings.setValue(QString::fromUtf8("SearchEngines/knownEnginesEnabled"), known_enginesEnabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
void engineSelectDlg::on_updateButton_clicked() {
|
void engineSelectDlg::on_updateButton_clicked() {
|
||||||
// Download version file from primary server
|
// Download version file from primary server
|
||||||
downloader->downloadUrl("http://www.dchris.eu/search_engine2/versions.txt");
|
downloader->downloadUrl("http://www.dchris.eu/search_engine2/versions.txt");
|
||||||
}
|
}
|
||||||
|
|
||||||
void engineSelectDlg::toggleEngineState(QTreeWidgetItem *item, int) {
|
void engineSelectDlg::toggleEngineState(QTreeWidgetItem *item, int) {
|
||||||
int index = pluginsTree->indexOfTopLevelItem(item);
|
SupportedEngine *engine = supported_engines->value(item->text(ENGINE_ID));
|
||||||
QString id = item->text(ENGINE_ID);
|
engine->setEnabled(!engine->isEnabled());
|
||||||
bool new_val = !installed_engines.value(id, true);
|
if(engine->isEnabled()) {
|
||||||
installed_engines[id] = new_val;
|
item->setText(ENGINE_STATE, tr("Yes"));
|
||||||
QString enabledTxt;
|
setRowColor(pluginsTree->indexOfTopLevelItem(item), "green");
|
||||||
if(new_val){
|
} else {
|
||||||
enabledTxt = tr("True");
|
item->setText(ENGINE_STATE, tr("No"));
|
||||||
setRowColor(index, "green");
|
setRowColor(pluginsTree->indexOfTopLevelItem(item), "red");
|
||||||
}else{
|
|
||||||
enabledTxt = tr("False");
|
|
||||||
setRowColor(index, "red");
|
|
||||||
}
|
}
|
||||||
item->setText(ENGINE_STATE, enabledTxt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void engineSelectDlg::displayContextMenu(const QPoint& pos) {
|
void engineSelectDlg::displayContextMenu(const QPoint&) {
|
||||||
QMenu myContextMenu(this);
|
QMenu myContextMenu(this);
|
||||||
QModelIndex index;
|
QModelIndex index;
|
||||||
// Enable/disable pause/start action given the DL state
|
// Enable/disable pause/start action given the DL state
|
||||||
|
@ -160,11 +141,11 @@ void engineSelectDlg::displayContextMenu(const QPoint& pos) {
|
||||||
QTreeWidgetItem *item;
|
QTreeWidgetItem *item;
|
||||||
foreach(item, items) {
|
foreach(item, items) {
|
||||||
QString id = item->text(ENGINE_ID);
|
QString id = item->text(ENGINE_ID);
|
||||||
if(installed_engines.value(id, true) and !has_disable) {
|
if(supported_engines->value(id)->isEnabled() and !has_disable) {
|
||||||
myContextMenu.addAction(actionDisable);
|
myContextMenu.addAction(actionDisable);
|
||||||
has_disable = true;
|
has_disable = true;
|
||||||
}
|
}
|
||||||
if(!installed_engines.value(id, true) and !has_enable) {
|
if(!supported_engines->value(id)->isEnabled() and !has_enable) {
|
||||||
myContextMenu.addAction(actionEnable);
|
myContextMenu.addAction(actionEnable);
|
||||||
has_enable = true;
|
has_enable = true;
|
||||||
}
|
}
|
||||||
|
@ -172,7 +153,7 @@ void engineSelectDlg::displayContextMenu(const QPoint& pos) {
|
||||||
}
|
}
|
||||||
myContextMenu.addSeparator();
|
myContextMenu.addSeparator();
|
||||||
myContextMenu.addAction(actionUninstall);
|
myContextMenu.addAction(actionUninstall);
|
||||||
myContextMenu.exec(mapToGlobal(pos)+QPoint(12, 58));
|
myContextMenu.exec(QCursor::pos());
|
||||||
}
|
}
|
||||||
|
|
||||||
void engineSelectDlg::on_closeButton_clicked() {
|
void engineSelectDlg::on_closeButton_clicked() {
|
||||||
|
@ -191,8 +172,8 @@ void engineSelectDlg::on_actionUninstall_triggered() {
|
||||||
if(QFile::exists(":/search_engine/engines/"+id+".py")) {
|
if(QFile::exists(":/search_engine/engines/"+id+".py")) {
|
||||||
error = true;
|
error = true;
|
||||||
// Disable it instead
|
// Disable it instead
|
||||||
installed_engines.insert(id, false);
|
supported_engines->value(id)->setEnabled(false);
|
||||||
item->setText(ENGINE_STATE, tr("False"));
|
item->setText(ENGINE_STATE, tr("No"));
|
||||||
setRowColor(index, "red");
|
setRowColor(index, "red");
|
||||||
continue;
|
continue;
|
||||||
}else {
|
}else {
|
||||||
|
@ -206,8 +187,8 @@ void engineSelectDlg::on_actionUninstall_triggered() {
|
||||||
foreach(file, files) {
|
foreach(file, files) {
|
||||||
enginesFolder.remove(file);
|
enginesFolder.remove(file);
|
||||||
}
|
}
|
||||||
// Remove it from lists
|
// Remove it from supported engines
|
||||||
installed_engines.remove(id);
|
delete supported_engines->take(id);
|
||||||
delete item;
|
delete item;
|
||||||
change = true;
|
change = true;
|
||||||
}
|
}
|
||||||
|
@ -225,8 +206,8 @@ void engineSelectDlg::enableSelection() {
|
||||||
int index = pluginsTree->indexOfTopLevelItem(item);
|
int index = pluginsTree->indexOfTopLevelItem(item);
|
||||||
Q_ASSERT(index != -1);
|
Q_ASSERT(index != -1);
|
||||||
QString id = item->text(ENGINE_ID);
|
QString id = item->text(ENGINE_ID);
|
||||||
installed_engines.insert(id, true);
|
supported_engines->value(id)->setEnabled(true);
|
||||||
item->setText(ENGINE_STATE, tr("True"));
|
item->setText(ENGINE_STATE, tr("Yes"));
|
||||||
setRowColor(index, "green");
|
setRowColor(index, "green");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -238,8 +219,8 @@ void engineSelectDlg::disableSelection() {
|
||||||
int index = pluginsTree->indexOfTopLevelItem(item);
|
int index = pluginsTree->indexOfTopLevelItem(item);
|
||||||
Q_ASSERT(index != -1);
|
Q_ASSERT(index != -1);
|
||||||
QString id = item->text(ENGINE_ID);
|
QString id = item->text(ENGINE_ID);
|
||||||
installed_engines.insert(id, false);
|
supported_engines->value(id)->setEnabled(false);
|
||||||
item->setText(ENGINE_STATE, tr("False"));
|
item->setText(ENGINE_STATE, tr("No"));
|
||||||
setRowColor(index, "red");
|
setRowColor(index, "red");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -247,108 +228,11 @@ void engineSelectDlg::disableSelection() {
|
||||||
// Set the color of a row in data model
|
// Set the color of a row in data model
|
||||||
void engineSelectDlg::setRowColor(int row, QString color){
|
void engineSelectDlg::setRowColor(int row, QString color){
|
||||||
QTreeWidgetItem *item = pluginsTree->topLevelItem(row);
|
QTreeWidgetItem *item = pluginsTree->topLevelItem(row);
|
||||||
for(int i=0; i<pluginsTree->columnCount()-1; ++i){
|
for(int i=0; i<pluginsTree->columnCount(); ++i){
|
||||||
item->setData(i, Qt::ForegroundRole, QVariant(QColor(color)));
|
item->setData(i, Qt::ForegroundRole, QVariant(QColor(color)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool engineSelectDlg::checkInstalled(QString plugin_name) const {
|
|
||||||
QProcess nova;
|
|
||||||
QStringList params;
|
|
||||||
params << misc::qBittorrentPath()+"search_engine"+QDir::separator()+"nova2.py";
|
|
||||||
params << "--supported_engines";
|
|
||||||
nova.start("python", params, QIODevice::ReadOnly);
|
|
||||||
nova.waitForStarted();
|
|
||||||
nova.waitForFinished();
|
|
||||||
QByteArray result = nova.readAll();
|
|
||||||
result = result.replace("\r", "");
|
|
||||||
result = result.replace("\n", "");
|
|
||||||
QList<QByteArray> plugins_list = result.split(',');
|
|
||||||
return plugins_list.contains(plugin_name.toLocal8Bit());
|
|
||||||
}
|
|
||||||
|
|
||||||
void engineSelectDlg::loadSupportedSearchEngines(bool first) {
|
|
||||||
// Some clean up first
|
|
||||||
pluginsTree->clear();
|
|
||||||
QHash<QString, bool> old_engines;
|
|
||||||
if(first) {
|
|
||||||
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
|
|
||||||
QStringList known_engines = settings.value(QString::fromUtf8("SearchEngines/knownEngines"), QStringList()).toStringList();
|
|
||||||
QVariantList enabled = settings.value(QString::fromUtf8("SearchEngines/knownEnginesEnabled"), QList<QVariant>()).toList();
|
|
||||||
Q_ASSERT(known_engines.size() == enabled.size());
|
|
||||||
unsigned int nbKnownEngines = known_engines.size();
|
|
||||||
for(unsigned int i=0; i<nbKnownEngines; ++i) {
|
|
||||||
old_engines[known_engines.at(i)] = enabled.at(i).toBool();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
old_engines = installed_engines;
|
|
||||||
}
|
|
||||||
installed_engines.clear();
|
|
||||||
QStringList params;
|
|
||||||
// Ask nova core for the supported search engines
|
|
||||||
QProcess nova;
|
|
||||||
params << misc::qBittorrentPath()+"search_engine"+QDir::separator()+"nova2.py";
|
|
||||||
params << "--supported_engines";
|
|
||||||
nova.start("python", params, QIODevice::ReadOnly);
|
|
||||||
nova.waitForStarted();
|
|
||||||
nova.waitForFinished();
|
|
||||||
QByteArray result = nova.readAll();
|
|
||||||
result = result.replace("\r", "");
|
|
||||||
result = result.replace("\n", "");
|
|
||||||
qDebug("read: %s", result.data());
|
|
||||||
QByteArray e;
|
|
||||||
QStringList supported_engines_ids;
|
|
||||||
foreach(e, result.split(',')) {
|
|
||||||
QString en = QString(e);
|
|
||||||
supported_engines_ids << en;
|
|
||||||
installed_engines[en] = old_engines.value(en, true);
|
|
||||||
}
|
|
||||||
params.clear();
|
|
||||||
params << misc::qBittorrentPath()+"search_engine"+QDir::separator()+"nova2.py";
|
|
||||||
params << "--supported_engines_infos";
|
|
||||||
nova.start("python", params, QIODevice::ReadOnly);
|
|
||||||
nova.waitForStarted();
|
|
||||||
nova.waitForFinished();
|
|
||||||
result = nova.readAll();
|
|
||||||
result = result.replace("\r", "");
|
|
||||||
result = result.replace("\n", "");
|
|
||||||
qDebug("read: %s", result.data());
|
|
||||||
unsigned int i = 0;
|
|
||||||
foreach(e, result.split(',')) {
|
|
||||||
QString id = supported_engines_ids.at(i);
|
|
||||||
QString nameUrlCouple(e);
|
|
||||||
QStringList line = nameUrlCouple.split('|');
|
|
||||||
if(line.size() != 2) continue;
|
|
||||||
QString enabledTxt;
|
|
||||||
if(installed_engines.value(id, true)) {
|
|
||||||
enabledTxt = tr("True");
|
|
||||||
} else {
|
|
||||||
enabledTxt = tr("False");
|
|
||||||
}
|
|
||||||
line << enabledTxt;
|
|
||||||
line << id;
|
|
||||||
QTreeWidgetItem *item = new QTreeWidgetItem(pluginsTree, line);
|
|
||||||
QString iconPath = misc::qBittorrentPath()+"search_engine"+QDir::separator()+"engines"+QDir::separator()+id+".png";
|
|
||||||
if(QFile::exists(iconPath)) {
|
|
||||||
// Good, we already have the icon
|
|
||||||
item->setData(ENGINE_NAME, Qt::DecorationRole, QVariant(QIcon(iconPath)));
|
|
||||||
} else {
|
|
||||||
iconPath = misc::qBittorrentPath()+"search_engine"+QDir::separator()+"engines"+QDir::separator()+id+".ico";
|
|
||||||
if(QFile::exists(iconPath)) { // ICO support
|
|
||||||
item->setData(ENGINE_NAME, Qt::DecorationRole, QVariant(QIcon(iconPath)));
|
|
||||||
} else {
|
|
||||||
// Icon is missing, we must download it
|
|
||||||
downloader->downloadUrl(line.at(1)+"/favicon.ico");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(installed_engines.value(id, true))
|
|
||||||
setRowColor(i, "green");
|
|
||||||
else
|
|
||||||
setRowColor(i, "red");
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QTreeWidgetItem*> engineSelectDlg::findItemsWithUrl(QString url){
|
QList<QTreeWidgetItem*> engineSelectDlg::findItemsWithUrl(QString url){
|
||||||
QList<QTreeWidgetItem*> res;
|
QList<QTreeWidgetItem*> res;
|
||||||
for(int i=0; i<pluginsTree->topLevelItemCount(); ++i) {
|
for(int i=0; i<pluginsTree->topLevelItemCount(); ++i) {
|
||||||
|
@ -490,40 +374,40 @@ void engineSelectDlg::installPlugin(QString path, QString plugin_name) {
|
||||||
QMessageBox::information(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("A more recent version of %1 search engine plugin is already installed.", "%1 is the name of the search engine").arg(plugin_name.toLocal8Bit().data()));
|
QMessageBox::information(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("A more recent version of %1 search engine plugin is already installed.", "%1 is the name of the search engine").arg(plugin_name.toLocal8Bit().data()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Process with install
|
// Process with install
|
||||||
QString dest_path = misc::qBittorrentPath()+"search_engine"+QDir::separator()+"engines"+QDir::separator()+plugin_name+".py";
|
QString dest_path = misc::qBittorrentPath()+"search_engine"+QDir::separator()+"engines"+QDir::separator()+plugin_name+".py";
|
||||||
bool update = false;
|
bool update = false;
|
||||||
if(QFile::exists(dest_path)) {
|
if(QFile::exists(dest_path)) {
|
||||||
// Backup in case install fails
|
// Backup in case install fails
|
||||||
QFile::copy(dest_path, dest_path+".bak");
|
QFile::copy(dest_path, dest_path+".bak");
|
||||||
QFile::remove(dest_path);
|
QFile::remove(dest_path);
|
||||||
update = true;
|
update = true;
|
||||||
}
|
}
|
||||||
// Copy the plugin
|
// Copy the plugin
|
||||||
QFile::copy(path, dest_path);
|
QFile::copy(path, dest_path);
|
||||||
// Check if this was correctly installed
|
// Update supported plugins
|
||||||
if(!checkInstalled(plugin_name)) {
|
supported_engines->update();
|
||||||
|
// Check if this was correctly installed
|
||||||
|
if(!supported_engines->contains(plugin_name)) {
|
||||||
if(update) {
|
if(update) {
|
||||||
// Remove broken file
|
// Remove broken file
|
||||||
QFile::remove(dest_path);
|
QFile::remove(dest_path);
|
||||||
// restore backup
|
// restore backup
|
||||||
QFile::copy(dest_path+".bak", dest_path);
|
QFile::copy(dest_path+".bak", dest_path);
|
||||||
QFile::remove(dest_path+".bak");
|
QFile::remove(dest_path+".bak");
|
||||||
QMessageBox::warning(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("%1 search engine plugin could not be updated, keeping old version.", "%1 is the name of the search engine").arg(plugin_name.toLocal8Bit().data()));
|
QMessageBox::warning(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("%1 search engine plugin could not be updated, keeping old version.", "%1 is the name of the search engine").arg(plugin_name.toLocal8Bit().data()));
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// Remove broken file
|
// Remove broken file
|
||||||
QFile::remove(dest_path);
|
QFile::remove(dest_path);
|
||||||
QMessageBox::warning(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("%1 search engine plugin could not be installed.", "%1 is the name of the search engine").arg(plugin_name.toLocal8Bit().data()));
|
QMessageBox::warning(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("%1 search engine plugin could not be installed.", "%1 is the name of the search engine").arg(plugin_name.toLocal8Bit().data()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Install was successful, remove backup
|
// Install was successful, remove backup
|
||||||
if(update) {
|
if(update) {
|
||||||
QFile::remove(dest_path+".bak");
|
QFile::remove(dest_path+".bak");
|
||||||
}
|
}
|
||||||
// Refresh plugin list
|
|
||||||
loadSupportedSearchEngines();
|
|
||||||
if(update) {
|
if(update) {
|
||||||
QMessageBox::information(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("%1 search engine plugin was successfully updated.", "%1 is the name of the search engine").arg(plugin_name.toLocal8Bit().data()));
|
QMessageBox::information(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("%1 search engine plugin was successfully updated.", "%1 is the name of the search engine").arg(plugin_name.toLocal8Bit().data()));
|
||||||
return;
|
return;
|
||||||
|
@ -533,175 +417,212 @@ void engineSelectDlg::installPlugin(QString path, QString plugin_name) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void engineSelectDlg::on_installButton_clicked() {
|
void engineSelectDlg::loadSupportedSearchEngines() {
|
||||||
pluginSourceDlg *dlg = new pluginSourceDlg(this);
|
// Some clean up first
|
||||||
connect(dlg, SIGNAL(askForLocalFile()), this, SLOT(askForLocalPlugin()));
|
pluginsTree->clear();
|
||||||
connect(dlg, SIGNAL(askForUrl()), this, SLOT(askForPluginUrl()));
|
foreach(QString name, supported_engines->keys()) {
|
||||||
}
|
addNewEngine(name);
|
||||||
|
|
||||||
void engineSelectDlg::askForPluginUrl() {
|
|
||||||
bool ok;
|
|
||||||
QString url = QInputDialog::getText(this, tr("New search engine plugin URL"),
|
|
||||||
tr("URL:"), QLineEdit::Normal,
|
|
||||||
"http://", &ok);
|
|
||||||
if (ok && !url.isEmpty())
|
|
||||||
downloader->downloadUrl(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
void engineSelectDlg::askForLocalPlugin() {
|
|
||||||
QStringList pathsList = QFileDialog::getOpenFileNames(0,
|
|
||||||
tr("Select search plugins"), QDir::homePath(),
|
|
||||||
#ifdef HAVE_ZZIP
|
|
||||||
tr("qBittorrent search plugins")+QString::fromUtf8(" (*.py *.zip)"));
|
|
||||||
#else
|
|
||||||
tr("qBittorrent search plugins")+QString::fromUtf8(" (*.py)"));
|
|
||||||
#endif
|
|
||||||
QString path;
|
|
||||||
foreach(path, pathsList) {
|
|
||||||
if(path.endsWith(".py", Qt::CaseInsensitive)) {
|
|
||||||
QString plugin_name = path.split(QDir::separator()).last();
|
|
||||||
plugin_name.replace(".py", "", Qt::CaseInsensitive);
|
|
||||||
installPlugin(path, plugin_name);
|
|
||||||
}
|
|
||||||
#ifdef HAVE_ZZIP
|
|
||||||
else {
|
|
||||||
if(path.endsWith(".zip", Qt::CaseInsensitive)) {
|
|
||||||
installZipPlugin(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool engineSelectDlg::parseVersionsFile(QString versions_file, QString updateServer) {
|
void engineSelectDlg::addNewEngine(QString engine_name) {
|
||||||
qDebug("Checking if update is needed");
|
QTreeWidgetItem *item = new QTreeWidgetItem(pluginsTree);
|
||||||
bool file_correct = false;
|
SupportedEngine *engine = supported_engines->value(engine_name);
|
||||||
QFile versions(versions_file);
|
item->setText(ENGINE_NAME, engine->getFullName());
|
||||||
if(!versions.open(QIODevice::ReadOnly | QIODevice::Text)){
|
item->setText(ENGINE_URL, engine->getUrl());
|
||||||
qDebug("* Error: Could not read versions.txt file");
|
item->setText(ENGINE_ID, engine->getName());
|
||||||
return false;
|
if(engine->isEnabled()) {
|
||||||
|
item->setText(ENGINE_STATE, tr("Yes"));
|
||||||
|
setRowColor(pluginsTree->indexOfTopLevelItem(item), "green");
|
||||||
|
} else {
|
||||||
|
item->setText(ENGINE_STATE, tr("No"));
|
||||||
|
setRowColor(pluginsTree->indexOfTopLevelItem(item), "red");
|
||||||
}
|
}
|
||||||
bool updated = false;
|
// Handle icon
|
||||||
while(!versions.atEnd()) {
|
QString iconPath = misc::qBittorrentPath()+"search_engine"+QDir::separator()+"engines"+QDir::separator()+engine->getName()+".png";
|
||||||
QByteArray line = versions.readLine();
|
if(QFile::exists(iconPath)) {
|
||||||
line.replace("\n", "");
|
// Good, we already have the icon
|
||||||
line = line.trimmed();
|
item->setData(ENGINE_NAME, Qt::DecorationRole, QVariant(QIcon(iconPath)));
|
||||||
if(line.isEmpty()) continue;
|
} else {
|
||||||
if(line.startsWith("#")) continue;
|
iconPath = misc::qBittorrentPath()+"search_engine"+QDir::separator()+"engines"+QDir::separator()+engine->getName()+".ico";
|
||||||
QList<QByteArray> list = line.split(' ');
|
if(QFile::exists(iconPath)) { // ICO support
|
||||||
if(list.size() != 2) continue;
|
item->setData(ENGINE_NAME, Qt::DecorationRole, QVariant(QIcon(iconPath)));
|
||||||
QString plugin_name = QString(list.first());
|
} else {
|
||||||
if(!plugin_name.endsWith(":")) continue;
|
// Icon is missing, we must download it
|
||||||
plugin_name.chop(1); // remove trailing ':'
|
downloader->downloadUrl(engine->getUrl()+"/favicon.ico");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void engineSelectDlg::on_installButton_clicked() {
|
||||||
|
pluginSourceDlg *dlg = new pluginSourceDlg(this);
|
||||||
|
connect(dlg, SIGNAL(askForLocalFile()), this, SLOT(askForLocalPlugin()));
|
||||||
|
connect(dlg, SIGNAL(askForUrl()), this, SLOT(askForPluginUrl()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void engineSelectDlg::askForPluginUrl() {
|
||||||
bool ok;
|
bool ok;
|
||||||
float version = list.last().toFloat(&ok);
|
QString url = QInputDialog::getText(this, tr("New search engine plugin URL"),
|
||||||
qDebug("read line %s: %.2f", plugin_name.toLocal8Bit().data(), version);
|
tr("URL:"), QLineEdit::Normal,
|
||||||
if(!ok) continue;
|
"http://", &ok);
|
||||||
file_correct = true;
|
if (ok && !url.isEmpty())
|
||||||
if(isUpdateNeeded(plugin_name, version)) {
|
downloader->downloadUrl(url);
|
||||||
qDebug("Plugin: %s is outdated", plugin_name.toLocal8Bit().data());
|
}
|
||||||
// Downloading update
|
|
||||||
downloader->downloadUrl(updateServer+plugin_name+".pyqBT"); // Actually this is really a .py
|
void engineSelectDlg::askForLocalPlugin() {
|
||||||
downloader->downloadUrl(updateServer+plugin_name+".png");
|
QStringList pathsList = QFileDialog::getOpenFileNames(0,
|
||||||
updated = true;
|
tr("Select search plugins"), QDir::homePath(),
|
||||||
}else {
|
#ifdef HAVE_ZZIP
|
||||||
qDebug("Plugin: %s is up to date", plugin_name.toLocal8Bit().data());
|
tr("qBittorrent search plugins")+QString::fromUtf8(" (*.py *.zip)"));
|
||||||
|
#else
|
||||||
|
tr("qBittorrent search plugins")+QString::fromUtf8(" (*.py)"));
|
||||||
|
#endif
|
||||||
|
QString path;
|
||||||
|
foreach(path, pathsList) {
|
||||||
|
if(path.endsWith(".py", Qt::CaseInsensitive)) {
|
||||||
|
QString plugin_name = path.split(QDir::separator()).last();
|
||||||
|
plugin_name.replace(".py", "", Qt::CaseInsensitive);
|
||||||
|
installPlugin(path, plugin_name);
|
||||||
|
}
|
||||||
|
#ifdef HAVE_ZZIP
|
||||||
|
else {
|
||||||
|
if(path.endsWith(".zip", Qt::CaseInsensitive)) {
|
||||||
|
installZipPlugin(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Close file
|
|
||||||
versions.close();
|
|
||||||
// Clean up tmp file
|
|
||||||
QFile::remove(versions_file);
|
|
||||||
if(file_correct && !updated) {
|
|
||||||
QMessageBox::information(this, tr("Search plugin update")+" -- "+tr("qBittorrent"), tr("All your plugins are already up to date."));
|
|
||||||
}
|
|
||||||
return file_correct;
|
|
||||||
}
|
|
||||||
|
|
||||||
void engineSelectDlg::processDownloadedFile(QString url, QString filePath) {
|
bool engineSelectDlg::parseVersionsFile(QString versions_file, QString updateServer) {
|
||||||
qDebug("engineSelectDlg received %s", url.toLocal8Bit().data());
|
qDebug("Checking if update is needed");
|
||||||
if(url.endsWith("favicon.ico", Qt::CaseInsensitive)){
|
bool file_correct = false;
|
||||||
// Icon downloaded
|
QFile versions(versions_file);
|
||||||
QImage fileIcon;
|
if(!versions.open(QIODevice::ReadOnly | QIODevice::Text)){
|
||||||
if(fileIcon.load(filePath)) {
|
qDebug("* Error: Could not read versions.txt file");
|
||||||
QList<QTreeWidgetItem*> items = findItemsWithUrl(url);
|
return false;
|
||||||
QTreeWidgetItem *item;
|
}
|
||||||
foreach(item, items){
|
bool updated = false;
|
||||||
QString id = item->text(ENGINE_ID);
|
while(!versions.atEnd()) {
|
||||||
QString iconPath;
|
QByteArray line = versions.readLine();
|
||||||
QFile icon(filePath);
|
line.replace("\n", "");
|
||||||
icon.open(QIODevice::ReadOnly);
|
line = line.trimmed();
|
||||||
if(ICOHandler::canRead(&icon))
|
if(line.isEmpty()) continue;
|
||||||
iconPath = misc::qBittorrentPath()+"search_engine"+QDir::separator()+"engines"+QDir::separator()+id+".ico";
|
if(line.startsWith("#")) continue;
|
||||||
else
|
QList<QByteArray> list = line.split(' ');
|
||||||
iconPath = misc::qBittorrentPath()+"search_engine"+QDir::separator()+"engines"+QDir::separator()+id+".png";
|
if(list.size() != 2) continue;
|
||||||
QFile::copy(filePath, iconPath);
|
QString plugin_name = QString(list.first());
|
||||||
item->setData(ENGINE_NAME, Qt::DecorationRole, QVariant(QIcon(iconPath)));
|
if(!plugin_name.endsWith(":")) continue;
|
||||||
|
plugin_name.chop(1); // remove trailing ':'
|
||||||
|
bool ok;
|
||||||
|
float version = list.last().toFloat(&ok);
|
||||||
|
qDebug("read line %s: %.2f", plugin_name.toLocal8Bit().data(), version);
|
||||||
|
if(!ok) continue;
|
||||||
|
file_correct = true;
|
||||||
|
if(isUpdateNeeded(plugin_name, version)) {
|
||||||
|
qDebug("Plugin: %s is outdated", plugin_name.toLocal8Bit().data());
|
||||||
|
// Downloading update
|
||||||
|
downloader->downloadUrl(updateServer+plugin_name+".pyqBT"); // Actually this is really a .py
|
||||||
|
downloader->downloadUrl(updateServer+plugin_name+".png");
|
||||||
|
updated = true;
|
||||||
|
}else {
|
||||||
|
qDebug("Plugin: %s is up to date", plugin_name.toLocal8Bit().data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Delete tmp file
|
// Close file
|
||||||
QFile::remove(filePath);
|
versions.close();
|
||||||
return;
|
// Clean up tmp file
|
||||||
|
QFile::remove(versions_file);
|
||||||
|
if(file_correct && !updated) {
|
||||||
|
QMessageBox::information(this, tr("Search plugin update")+" -- "+tr("qBittorrent"), tr("All your plugins are already up to date."));
|
||||||
|
}
|
||||||
|
return file_correct;
|
||||||
}
|
}
|
||||||
if(url == "http://www.dchris.eu/search_engine2/versions.txt") {
|
|
||||||
if(!parseVersionsFile(filePath, "http://www.dchris.eu/search_engine2/")) {
|
void engineSelectDlg::processDownloadedFile(QString url, QString filePath) {
|
||||||
|
qDebug("engineSelectDlg received %s", url.toLocal8Bit().data());
|
||||||
|
if(url.endsWith("favicon.ico", Qt::CaseInsensitive)){
|
||||||
|
// Icon downloaded
|
||||||
|
QImage fileIcon;
|
||||||
|
if(fileIcon.load(filePath)) {
|
||||||
|
QList<QTreeWidgetItem*> items = findItemsWithUrl(url);
|
||||||
|
QTreeWidgetItem *item;
|
||||||
|
foreach(item, items){
|
||||||
|
QString id = item->text(ENGINE_ID);
|
||||||
|
QString iconPath;
|
||||||
|
QFile icon(filePath);
|
||||||
|
icon.open(QIODevice::ReadOnly);
|
||||||
|
if(ICOHandler::canRead(&icon))
|
||||||
|
iconPath = misc::qBittorrentPath()+"search_engine"+QDir::separator()+"engines"+QDir::separator()+id+".ico";
|
||||||
|
else
|
||||||
|
iconPath = misc::qBittorrentPath()+"search_engine"+QDir::separator()+"engines"+QDir::separator()+id+".png";
|
||||||
|
QFile::copy(filePath, iconPath);
|
||||||
|
item->setData(ENGINE_NAME, Qt::DecorationRole, QVariant(QIcon(iconPath)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Delete tmp file
|
||||||
|
QFile::remove(filePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(url == "http://www.dchris.eu/search_engine2/versions.txt") {
|
||||||
|
if(!parseVersionsFile(filePath, "http://www.dchris.eu/search_engine2/")) {
|
||||||
|
qDebug("Primary update server failed, try secondary");
|
||||||
|
downloader->downloadUrl("http://hydr0g3n.free.fr/search_engine2/versions.txt");
|
||||||
|
}
|
||||||
|
QFile::remove(filePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(url == "http://hydr0g3n.free.fr/search_engine2/versions.txt") {
|
||||||
|
if(!parseVersionsFile(filePath, "http://hydr0g3n.free.fr/search_engine2/")) {
|
||||||
|
QMessageBox::warning(this, tr("Search plugin update")+" -- "+tr("qBittorrent"), tr("Sorry, update server is temporarily unavailable."));
|
||||||
|
}
|
||||||
|
QFile::remove(filePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(url.endsWith(".pyqBT", Qt::CaseInsensitive) || url.endsWith(".py", Qt::CaseInsensitive)) {
|
||||||
|
QString plugin_name = url.split('/').last();
|
||||||
|
plugin_name.replace(".pyqBT", "");
|
||||||
|
plugin_name.replace(".py", "");
|
||||||
|
installPlugin(filePath, plugin_name);
|
||||||
|
QFile::remove(filePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#ifdef HAVE_ZZIP
|
||||||
|
if(url.endsWith(".zip", Qt::CaseInsensitive)) {
|
||||||
|
installZipPlugin(filePath);
|
||||||
|
QFile::remove(filePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void engineSelectDlg::handleDownloadFailure(QString url, QString reason) {
|
||||||
|
if(url.endsWith("favicon.ico", Qt::CaseInsensitive)){
|
||||||
|
qDebug("Could not download favicon: %s, reason: %s", url.toLocal8Bit().data(), reason.toLocal8Bit().data());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(url == "http://www.dchris.eu/search_engine2/versions.txt") {
|
||||||
|
// Primary update server failed, try secondary
|
||||||
qDebug("Primary update server failed, try secondary");
|
qDebug("Primary update server failed, try secondary");
|
||||||
downloader->downloadUrl("http://hydr0g3n.free.fr/search_engine2/versions.txt");
|
downloader->downloadUrl("http://hydr0g3n.free.fr/search_engine2/versions.txt");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
QFile::remove(filePath);
|
if(url == "http://hydr0g3n.free.fr/search_engine2/versions.txt") {
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(url == "http://hydr0g3n.free.fr/search_engine2/versions.txt") {
|
|
||||||
if(!parseVersionsFile(filePath, "http://hydr0g3n.free.fr/search_engine2/")) {
|
|
||||||
QMessageBox::warning(this, tr("Search plugin update")+" -- "+tr("qBittorrent"), tr("Sorry, update server is temporarily unavailable."));
|
QMessageBox::warning(this, tr("Search plugin update")+" -- "+tr("qBittorrent"), tr("Sorry, update server is temporarily unavailable."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(url.endsWith(".pyqBT", Qt::CaseInsensitive) || url.endsWith(".py", Qt::CaseInsensitive)) {
|
||||||
|
// a plugin update download has been failed
|
||||||
|
QString plugin_name = url.split('/').last();
|
||||||
|
plugin_name.replace(".pyqBT", "", Qt::CaseInsensitive);
|
||||||
|
plugin_name.replace(".py", "", Qt::CaseInsensitive);
|
||||||
|
QMessageBox::warning(this, tr("Search plugin update")+" -- "+tr("qBittorrent"), tr("Sorry, %1 search plugin install failed.", "%1 is the name of the search engine").arg(plugin_name.toLocal8Bit().data()));
|
||||||
}
|
}
|
||||||
QFile::remove(filePath);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(url.endsWith(".pyqBT", Qt::CaseInsensitive) || url.endsWith(".py", Qt::CaseInsensitive)) {
|
|
||||||
QString plugin_name = url.split('/').last();
|
|
||||||
plugin_name.replace(".pyqBT", "");
|
|
||||||
plugin_name.replace(".py", "");
|
|
||||||
installPlugin(filePath, plugin_name);
|
|
||||||
QFile::remove(filePath);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#ifdef HAVE_ZZIP
|
#ifdef HAVE_ZZIP
|
||||||
if(url.endsWith(".zip", Qt::CaseInsensitive)) {
|
if(url.endsWith(".zip", Qt::CaseInsensitive)) {
|
||||||
installZipPlugin(filePath);
|
QString plugin_name = url.split('/').last();
|
||||||
QFile::remove(filePath);
|
plugin_name.replace(".zip", "", Qt::CaseInsensitive);
|
||||||
return;
|
QMessageBox::warning(this, tr("Search plugin update")+" -- "+tr("qBittorrent"), tr("Sorry, %1 search plugin install failed.", "%1 is the name of the search engine").arg(plugin_name.toLocal8Bit().data()));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
void engineSelectDlg::handleDownloadFailure(QString url, QString reason) {
|
|
||||||
if(url.endsWith("favicon.ico", Qt::CaseInsensitive)){
|
|
||||||
qDebug("Could not download favicon: %s, reason: %s", url.toLocal8Bit().data(), reason.toLocal8Bit().data());
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if(url == "http://www.dchris.eu/search_engine2/versions.txt") {
|
|
||||||
// Primary update server failed, try secondary
|
|
||||||
qDebug("Primary update server failed, try secondary");
|
|
||||||
downloader->downloadUrl("http://hydr0g3n.free.fr/search_engine2/versions.txt");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(url == "http://hydr0g3n.free.fr/search_engine2/versions.txt") {
|
|
||||||
QMessageBox::warning(this, tr("Search plugin update")+" -- "+tr("qBittorrent"), tr("Sorry, update server is temporarily unavailable."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(url.endsWith(".pyqBT", Qt::CaseInsensitive) || url.endsWith(".py", Qt::CaseInsensitive)) {
|
|
||||||
// a plugin update download has been failed
|
|
||||||
QString plugin_name = url.split('/').last();
|
|
||||||
plugin_name.replace(".pyqBT", "", Qt::CaseInsensitive);
|
|
||||||
plugin_name.replace(".py", "", Qt::CaseInsensitive);
|
|
||||||
QMessageBox::warning(this, tr("Search plugin update")+" -- "+tr("qBittorrent"), tr("Sorry, %1 search plugin install failed.", "%1 is the name of the search engine").arg(plugin_name.toLocal8Bit().data()));
|
|
||||||
}
|
|
||||||
#ifdef HAVE_ZZIP
|
|
||||||
if(url.endsWith(".zip", Qt::CaseInsensitive)) {
|
|
||||||
QString plugin_name = url.split('/').last();
|
|
||||||
plugin_name.replace(".zip", "", Qt::CaseInsensitive);
|
|
||||||
QMessageBox::warning(this, tr("Search plugin update")+" -- "+tr("qBittorrent"), tr("Sorry, %1 search plugin install failed.", "%1 is the name of the search engine").arg(plugin_name.toLocal8Bit().data()));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#define ENGINE_SELECT_DLG_H
|
#define ENGINE_SELECT_DLG_H
|
||||||
|
|
||||||
#include "ui_engineSelect.h"
|
#include "ui_engineSelect.h"
|
||||||
|
#include "supportedEngines.h"
|
||||||
|
|
||||||
class downloadThread;
|
class downloadThread;
|
||||||
class QDropEvent;
|
class QDropEvent;
|
||||||
|
@ -40,12 +41,11 @@ class engineSelectDlg : public QDialog, public Ui::engineSelect{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Search related
|
|
||||||
QHash<QString, bool> installed_engines;
|
|
||||||
downloadThread *downloader;
|
downloadThread *downloader;
|
||||||
|
SupportedEngines *supported_engines;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
engineSelectDlg(QWidget *parent);
|
engineSelectDlg(QWidget *parent, SupportedEngines *supported_engines);
|
||||||
~engineSelectDlg();
|
~engineSelectDlg();
|
||||||
QList<QTreeWidgetItem*> findItemsWithUrl(QString url);
|
QList<QTreeWidgetItem*> findItemsWithUrl(QString url);
|
||||||
QTreeWidgetItem* findItemWithID(QString id);
|
QTreeWidgetItem* findItemWithID(QString id);
|
||||||
|
@ -53,15 +53,14 @@ class engineSelectDlg : public QDialog, public Ui::engineSelect{
|
||||||
protected:
|
protected:
|
||||||
bool parseVersionsFile(QString versions_file, QString updateServer);
|
bool parseVersionsFile(QString versions_file, QString updateServer);
|
||||||
bool isUpdateNeeded(QString plugin_name, float new_version) const;
|
bool isUpdateNeeded(QString plugin_name, float new_version) const;
|
||||||
bool checkInstalled(QString plugin_name) const;
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void enginesChanged();
|
void enginesChanged();
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void saveSettings();
|
|
||||||
void on_closeButton_clicked();
|
void on_closeButton_clicked();
|
||||||
void loadSupportedSearchEngines(bool first=false);
|
void loadSupportedSearchEngines();
|
||||||
|
void addNewEngine(QString engine_name);
|
||||||
void toggleEngineState(QTreeWidgetItem*, int);
|
void toggleEngineState(QTreeWidgetItem*, int);
|
||||||
void setRowColor(int row, QString color);
|
void setRowColor(int row, QString color);
|
||||||
void processDownloadedFile(QString url, QString filePath);
|
void processDownloadedFile(QString url, QString filePath);
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<!DOCTYPE RCC><RCC version="1.0">
|
<!DOCTYPE RCC><RCC version="1.0">
|
||||||
<qresource>
|
<qresource>
|
||||||
<file>Icons/rss32.png</file>
|
<file>Icons/rss32.png</file>
|
||||||
<file>Icons/money.png</file>
|
|
||||||
<file>Icons/sphere2.png</file>
|
<file>Icons/sphere2.png</file>
|
||||||
<file>Icons/downarrow.png</file>
|
<file>Icons/downarrow.png</file>
|
||||||
<file>Icons/url.png</file>
|
<file>Icons/url.png</file>
|
||||||
|
@ -95,6 +94,7 @@
|
||||||
<file>Icons/oxygen/bt_settings.png</file>
|
<file>Icons/oxygen/bt_settings.png</file>
|
||||||
<file>Icons/oxygen/document-new.png</file>
|
<file>Icons/oxygen/document-new.png</file>
|
||||||
<file>Icons/oxygen/tab-close.png</file>
|
<file>Icons/oxygen/tab-close.png</file>
|
||||||
|
<file>Icons/oxygen/wallet.png</file>
|
||||||
<file>Icons/oxygen/webui.png</file>
|
<file>Icons/oxygen/webui.png</file>
|
||||||
<file>Icons/oxygen/list-remove.png</file>
|
<file>Icons/oxygen/list-remove.png</file>
|
||||||
<file>Icons/oxygen/connection.png</file>
|
<file>Icons/oxygen/connection.png</file>
|
||||||
|
|
|
@ -30,53 +30,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QComboBox" name="comboCategory">
|
<widget class="QComboBox" name="comboCategory"/>
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>All categories</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Movies</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>TV shows</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Music</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Games</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Anime</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Software</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Pictures</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Books</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="search_button">
|
<widget class="QPushButton" name="search_button">
|
||||||
|
|
|
@ -76,27 +76,43 @@ SearchEngine::SearchEngine(bittorrent *BTSession, QSystemTrayIcon *myTrayIcon, b
|
||||||
connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tab_changed(int)));
|
connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tab_changed(int)));
|
||||||
searchTimeout = new QTimer(this);
|
searchTimeout = new QTimer(this);
|
||||||
searchTimeout->setSingleShot(true);
|
searchTimeout->setSingleShot(true);
|
||||||
connect(searchTimeout, SIGNAL(timeout()), this, SLOT(on_stop_search_button_clicked()));
|
connect(searchTimeout, SIGNAL(timeout()), this, SLOT(on_search_button_clicked()));
|
||||||
// Check last enabled search engines
|
|
||||||
loadEngineSettings();
|
|
||||||
// Update nova.py search plugin if necessary
|
// Update nova.py search plugin if necessary
|
||||||
updateNova();
|
updateNova();
|
||||||
|
supported_engines = new SupportedEngines();
|
||||||
|
// Fill in category combobox
|
||||||
|
fillCatCombobox();
|
||||||
connect(search_pattern, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(displayPatternContextMenu(QPoint)));
|
connect(search_pattern, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(displayPatternContextMenu(QPoint)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SearchEngine::fillCatCombobox() {
|
||||||
|
comboCategory->clear();
|
||||||
|
comboCategory->addItem(full_cat_names["all"], QVariant("all"));
|
||||||
|
QStringList supported_cat = supported_engines->supportedCategories();
|
||||||
|
foreach(QString cat, supported_cat) {
|
||||||
|
qDebug("Supported category: %s", cat.toLocal8Bit().data());
|
||||||
|
comboCategory->addItem(full_cat_names[cat], QVariant(cat));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SearchEngine::selectedCategory() const {
|
||||||
|
return comboCategory->itemData(comboCategory->currentIndex()).toString();
|
||||||
|
}
|
||||||
|
|
||||||
SearchEngine::~SearchEngine(){
|
SearchEngine::~SearchEngine(){
|
||||||
qDebug("Search destruction");
|
qDebug("Search destruction");
|
||||||
// save the searchHistory for later uses
|
// save the searchHistory for later uses
|
||||||
saveSearchHistory();
|
saveSearchHistory();
|
||||||
searchProcess->kill();
|
searchProcess->kill();
|
||||||
searchProcess->waitForFinished();
|
searchProcess->waitForFinished();
|
||||||
foreach(QProcess *downloader, downloaders) {
|
foreach(QProcess *downloader, downloaders) {
|
||||||
downloader->kill();
|
downloader->kill();
|
||||||
downloader->waitForFinished();
|
downloader->waitForFinished();
|
||||||
delete downloader;
|
delete downloader;
|
||||||
}
|
}
|
||||||
delete searchTimeout;
|
delete searchTimeout;
|
||||||
delete searchProcess;
|
delete searchProcess;
|
||||||
|
delete supported_engines;
|
||||||
if(searchCompleter)
|
if(searchCompleter)
|
||||||
delete searchCompleter;
|
delete searchCompleter;
|
||||||
}
|
}
|
||||||
|
@ -145,20 +161,19 @@ void SearchEngine::displayPatternContextMenu(QPoint) {
|
||||||
|
|
||||||
void SearchEngine::tab_changed(int t)
|
void SearchEngine::tab_changed(int t)
|
||||||
{//when we switch from a tab that is not empty to another that is empty the download button
|
{//when we switch from a tab that is not empty to another that is empty the download button
|
||||||
//doesn't have to be available
|
//doesn't have to be available
|
||||||
if(t>-1)
|
if(t>-1)
|
||||||
{//-1 = no more tab
|
{//-1 = no more tab
|
||||||
if(all_tab.at(tabWidget->currentIndex())->getCurrentSearchListModel()->rowCount()) {
|
if(all_tab.at(tabWidget->currentIndex())->getCurrentSearchListModel()->rowCount()) {
|
||||||
download_button->setEnabled(true);
|
download_button->setEnabled(true);
|
||||||
} else {
|
} else {
|
||||||
download_button->setEnabled(false);
|
download_button->setEnabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchEngine::on_enginesButton_clicked() {
|
void SearchEngine::on_enginesButton_clicked() {
|
||||||
engineSelectDlg *dlg = new engineSelectDlg(this);
|
new engineSelectDlg(this, supported_engines);
|
||||||
connect(dlg, SIGNAL(enginesChanged()), this, SLOT(loadEngineSettings()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the last searchs from a QSettings to a QStringList
|
// get the last searchs from a QSettings to a QStringList
|
||||||
|
@ -169,23 +184,6 @@ void SearchEngine::startSearchHistory(){
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchEngine::loadEngineSettings() {
|
|
||||||
qDebug("Loading engine settings");
|
|
||||||
enabled_engines.clear();
|
|
||||||
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
|
|
||||||
QStringList known_engines = settings.value(QString::fromUtf8("SearchEngines/knownEngines"), QStringList()).toStringList();
|
|
||||||
QVariantList known_enginesEnabled = settings.value(QString::fromUtf8("SearchEngines/knownEnginesEnabled"), QList<QVariant>()).toList();
|
|
||||||
unsigned int i = 0;
|
|
||||||
foreach(const QString &engine, known_engines) {
|
|
||||||
if(known_enginesEnabled.at(i).toBool())
|
|
||||||
enabled_engines << engine;
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
if(enabled_engines.empty())
|
|
||||||
enabled_engines << "all";
|
|
||||||
qDebug("Engine settings loaded");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the history list into the QSettings for the next session
|
// Save the history list into the QSettings for the next session
|
||||||
void SearchEngine::saveSearchHistory()
|
void SearchEngine::saveSearchHistory()
|
||||||
{
|
{
|
||||||
|
@ -198,14 +196,14 @@ void SearchEngine::saveSearchHistory()
|
||||||
// Function called when we click on search button
|
// Function called when we click on search button
|
||||||
void SearchEngine::on_search_button_clicked(){
|
void SearchEngine::on_search_button_clicked(){
|
||||||
if(searchProcess->state() != QProcess::NotRunning){
|
if(searchProcess->state() != QProcess::NotRunning){
|
||||||
searchProcess->kill();
|
searchProcess->terminate();
|
||||||
searchProcess->waitForFinished();
|
search_stopped = true;
|
||||||
|
if(searchTimeout->isActive()) {
|
||||||
|
searchTimeout->stop();
|
||||||
|
}
|
||||||
search_button->setText("Search");
|
search_button->setText("Search");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(searchTimeout->isActive()) {
|
|
||||||
searchTimeout->stop();
|
|
||||||
}
|
|
||||||
QString pattern = search_pattern->text().trimmed();
|
QString pattern = search_pattern->text().trimmed();
|
||||||
// No search pattern entered
|
// No search pattern entered
|
||||||
if(pattern.isEmpty()){
|
if(pattern.isEmpty()){
|
||||||
|
@ -230,12 +228,13 @@ void SearchEngine::on_search_button_clicked(){
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getting checked search engines
|
// Getting checked search engines
|
||||||
Q_ASSERT(!enabled_engines.empty());
|
|
||||||
QStringList params;
|
QStringList params;
|
||||||
QStringList engineNames;
|
QStringList engineNames;
|
||||||
search_stopped = false;
|
search_stopped = false;
|
||||||
params << misc::qBittorrentPath()+"search_engine"+QDir::separator()+"nova2.py";
|
params << misc::qBittorrentPath()+"search_engine"+QDir::separator()+"nova2.py";
|
||||||
params << enabled_engines.join(",");
|
params << supported_engines->enginesEnabled().join(",");
|
||||||
|
qDebug("Search with category: %s", selectedCategory().toLocal8Bit().data());
|
||||||
|
params << selectedCategory();
|
||||||
params << pattern.split(" ");
|
params << pattern.split(" ");
|
||||||
// Update SearchEngine widgets
|
// Update SearchEngine widgets
|
||||||
no_search_results = true;
|
no_search_results = true;
|
||||||
|
@ -293,15 +292,15 @@ void SearchEngine::saveResultsColumnsWidth() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchEngine::downloadTorrent(QString engine_url, QString torrent_url) {
|
void SearchEngine::downloadTorrent(QString engine_url, QString torrent_url) {
|
||||||
QProcess *downloadProcess = new QProcess(this);
|
QProcess *downloadProcess = new QProcess(this);
|
||||||
connect(downloadProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(downloadFinished(int,QProcess::ExitStatus)));
|
connect(downloadProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(downloadFinished(int,QProcess::ExitStatus)));
|
||||||
downloaders << downloadProcess;
|
downloaders << downloadProcess;
|
||||||
QStringList params;
|
QStringList params;
|
||||||
params << misc::qBittorrentPath()+"search_engine"+QDir::separator()+"nova2dl.py";
|
params << misc::qBittorrentPath()+"search_engine"+QDir::separator()+"nova2dl.py";
|
||||||
params << engine_url;
|
params << engine_url;
|
||||||
params << torrent_url;
|
params << torrent_url;
|
||||||
// Launch search
|
// Launch search
|
||||||
downloadProcess->start("python", params, QIODevice::ReadOnly);
|
downloadProcess->start("python", params, QIODevice::ReadOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchEngine::searchStarted(){
|
void SearchEngine::searchStarted(){
|
||||||
|
@ -316,7 +315,7 @@ void SearchEngine::downloadSelectedItem(const QModelIndex& index){
|
||||||
int row = index.row();
|
int row = index.row();
|
||||||
// Get Item url
|
// Get Item url
|
||||||
QStandardItemModel *model = all_tab.at(tabWidget->currentIndex())->getCurrentSearchListModel();
|
QStandardItemModel *model = all_tab.at(tabWidget->currentIndex())->getCurrentSearchListModel();
|
||||||
QString engine_url = model->data(model->index(index.row(), ENGINE_URL_COLUMN)).toString();
|
QString engine_url = model->data(model->index(index.row(), ENGINE_URL_COLUMN)).toString();
|
||||||
QString torrent_url = model->data(model->index(index.row(), URL_COLUMN)).toString();
|
QString torrent_url = model->data(model->index(index.row(), URL_COLUMN)).toString();
|
||||||
// Download from url
|
// Download from url
|
||||||
downloadTorrent(engine_url, torrent_url);
|
downloadTorrent(engine_url, torrent_url);
|
||||||
|
@ -343,19 +342,19 @@ void SearchEngine::readSearchOutput(){
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchEngine::downloadFinished(int exitcode, QProcess::ExitStatus) {
|
void SearchEngine::downloadFinished(int exitcode, QProcess::ExitStatus) {
|
||||||
QProcess *downloadProcess = (QProcess*)sender();
|
QProcess *downloadProcess = (QProcess*)sender();
|
||||||
if(exitcode == 0) {
|
if(exitcode == 0) {
|
||||||
QString line = QString::fromUtf8(downloadProcess->readAllStandardOutput()).trimmed();
|
QString line = QString::fromUtf8(downloadProcess->readAllStandardOutput()).trimmed();
|
||||||
QStringList parts = line.split(' ');
|
QStringList parts = line.split(' ');
|
||||||
if(parts.size() == 2) {
|
if(parts.size() == 2) {
|
||||||
QString path = parts[0];
|
QString path = parts[0];
|
||||||
QString url = parts[1];
|
QString url = parts[1];
|
||||||
BTSession->processDownloadedFile(url, path);
|
BTSession->processDownloadedFile(url, path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
qDebug("Deleting downloadProcess");
|
qDebug("Deleting downloadProcess");
|
||||||
downloaders.removeAll(downloadProcess);
|
downloaders.removeAll(downloadProcess);
|
||||||
delete downloadProcess;
|
delete downloadProcess;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update nova.py search plugin if necessary
|
// Update nova.py search plugin if necessary
|
||||||
|
@ -386,8 +385,8 @@ void SearchEngine::updateNova() {
|
||||||
QFile::Permissions perm=QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner | QFile::ReadUser | QFile::WriteUser | QFile::ExeUser | QFile::ReadGroup | QFile::ReadGroup;
|
QFile::Permissions perm=QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner | QFile::ReadUser | QFile::WriteUser | QFile::ExeUser | QFile::ReadGroup | QFile::ReadGroup;
|
||||||
QFile(misc::qBittorrentPath()+"search_engine"+QDir::separator()+"nova2.py").setPermissions(perm);
|
QFile(misc::qBittorrentPath()+"search_engine"+QDir::separator()+"nova2.py").setPermissions(perm);
|
||||||
|
|
||||||
filePath = misc::qBittorrentPath()+"search_engine"+QDir::separator()+"nova2dl.py";
|
filePath = misc::qBittorrentPath()+"search_engine"+QDir::separator()+"nova2dl.py";
|
||||||
if(misc::getPluginVersion(":/search_engine/nova2dl.py") > misc::getPluginVersion(filePath)) {
|
if(misc::getPluginVersion(":/search_engine/nova2dl.py") > misc::getPluginVersion(filePath)) {
|
||||||
if(QFile::exists(filePath)){
|
if(QFile::exists(filePath)){
|
||||||
QFile::remove(filePath);
|
QFile::remove(filePath);
|
||||||
}
|
}
|
||||||
|
@ -409,7 +408,7 @@ void SearchEngine::updateNova() {
|
||||||
}
|
}
|
||||||
QFile::copy(":/search_engine/helpers.py", filePath);
|
QFile::copy(":/search_engine/helpers.py", filePath);
|
||||||
}
|
}
|
||||||
QFile(misc::qBittorrentPath()+"search_engine"+QDir::separator()+"helpers.py").setPermissions(perm);
|
QFile(misc::qBittorrentPath()+"search_engine"+QDir::separator()+"helpers.py").setPermissions(perm);
|
||||||
QString destDir = misc::qBittorrentPath()+"search_engine"+QDir::separator()+"engines"+QDir::separator();
|
QString destDir = misc::qBittorrentPath()+"search_engine"+QDir::separator()+"engines"+QDir::separator();
|
||||||
QDir shipped_subDir(":/search_engine/engines/");
|
QDir shipped_subDir(":/search_engine/engines/");
|
||||||
QStringList files = shipped_subDir.entryList();
|
QStringList files = shipped_subDir.entryList();
|
||||||
|
@ -462,6 +461,9 @@ void SearchEngine::searchFinished(int exitcode,QProcess::ExitStatus){
|
||||||
if(currentSearchTab)
|
if(currentSearchTab)
|
||||||
currentSearchTab->getCurrentLabel()->setText(tr("Results", "i.e: Search results")+QString::fromUtf8(" <i>(")+misc::toQString(nb_search_results)+QString::fromUtf8(")</i>:"));
|
currentSearchTab->getCurrentLabel()->setText(tr("Results", "i.e: Search results")+QString::fromUtf8(" <i>(")+misc::toQString(nb_search_results)+QString::fromUtf8(")</i>:"));
|
||||||
search_button->setText("Search");
|
search_button->setText("Search");
|
||||||
|
if(searchTimeout->isActive()) {
|
||||||
|
searchTimeout->stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SLOT to append one line to search results list
|
// SLOT to append one line to search results list
|
||||||
|
@ -491,34 +493,26 @@ void SearchEngine::appendSearchResult(QString line){
|
||||||
download_button->setEnabled(true);
|
download_button->setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop search while it is working in background
|
|
||||||
void SearchEngine::on_stop_search_button_clicked(){
|
|
||||||
// Kill process
|
|
||||||
searchProcess->terminate();
|
|
||||||
search_stopped = true;
|
|
||||||
searchTimeout->stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear search results list
|
// Clear search results list
|
||||||
void SearchEngine::closeTab_button_clicked(){
|
void SearchEngine::closeTab_button_clicked(){
|
||||||
if(all_tab.size()) {
|
if(all_tab.size()) {
|
||||||
qDebug("currentTab rank: %d", tabWidget->currentIndex());
|
qDebug("currentTab rank: %d", tabWidget->currentIndex());
|
||||||
qDebug("currentSearchTab rank: %d", tabWidget->indexOf(currentSearchTab));
|
qDebug("currentSearchTab rank: %d", tabWidget->indexOf(currentSearchTab));
|
||||||
if(tabWidget->currentIndex() == tabWidget->indexOf(currentSearchTab)) {
|
if(tabWidget->currentIndex() == tabWidget->indexOf(currentSearchTab)) {
|
||||||
qDebug("Deleted current search Tab");
|
qDebug("Deleted current search Tab");
|
||||||
if(searchProcess->state() != QProcess::NotRunning){
|
if(searchProcess->state() != QProcess::NotRunning){
|
||||||
searchProcess->terminate();
|
searchProcess->terminate();
|
||||||
}
|
}
|
||||||
if(searchTimeout->isActive()) {
|
if(searchTimeout->isActive()) {
|
||||||
searchTimeout->stop();
|
searchTimeout->stop();
|
||||||
}
|
}
|
||||||
search_stopped = true;
|
search_stopped = true;
|
||||||
currentSearchTab = 0;
|
currentSearchTab = 0;
|
||||||
}
|
}
|
||||||
delete all_tab.takeAt(tabWidget->currentIndex());
|
delete all_tab.takeAt(tabWidget->currentIndex());
|
||||||
if(!all_tab.size()) {
|
if(!all_tab.size()) {
|
||||||
closeTab_button->setEnabled(false);
|
closeTab_button->setEnabled(false);
|
||||||
download_button->setEnabled(false);
|
download_button->setEnabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -532,7 +526,7 @@ void SearchEngine::on_download_button_clicked(){
|
||||||
// Get Item url
|
// Get Item url
|
||||||
QStandardItemModel *model = all_tab.at(tabWidget->currentIndex())->getCurrentSearchListModel();
|
QStandardItemModel *model = all_tab.at(tabWidget->currentIndex())->getCurrentSearchListModel();
|
||||||
QString torrent_url = model->data(model->index(index.row(), URL_COLUMN)).toString();
|
QString torrent_url = model->data(model->index(index.row(), URL_COLUMN)).toString();
|
||||||
QString engine_url = model->data(model->index(index.row(), ENGINE_URL_COLUMN)).toString();
|
QString engine_url = model->data(model->index(index.row(), ENGINE_URL_COLUMN)).toString();
|
||||||
downloadTorrent(engine_url, torrent_url);
|
downloadTorrent(engine_url, torrent_url);
|
||||||
all_tab.at(tabWidget->currentIndex())->setRowColor(index.row(), "red");
|
all_tab.at(tabWidget->currentIndex())->setRowColor(index.row(), "red");
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include "ui_search.h"
|
#include "ui_search.h"
|
||||||
#include "engineSelectDlg.h"
|
#include "engineSelectDlg.h"
|
||||||
#include "SearchTab.h"
|
#include "SearchTab.h"
|
||||||
|
#include "supportedEngines.h"
|
||||||
|
|
||||||
class bittorrent;
|
class bittorrent;
|
||||||
class QSystemTrayIcon;
|
class QSystemTrayIcon;
|
||||||
|
@ -50,52 +51,55 @@ class SearchEngine;
|
||||||
class SearchEngine : public QWidget, public Ui::search_engine{
|
class SearchEngine : public QWidget, public Ui::search_engine{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Search related
|
// Search related
|
||||||
QProcess *searchProcess;
|
QProcess *searchProcess;
|
||||||
QList<QProcess*> downloaders;
|
QList<QProcess*> downloaders;
|
||||||
bool search_stopped;
|
bool search_stopped;
|
||||||
bool no_search_results;
|
bool no_search_results;
|
||||||
QByteArray search_result_line_truncated;
|
QByteArray search_result_line_truncated;
|
||||||
unsigned long nb_search_results;
|
unsigned long nb_search_results;
|
||||||
QPointer<QCompleter> searchCompleter;
|
QPointer<QCompleter> searchCompleter;
|
||||||
QStringList searchHistory;
|
QStringList searchHistory;
|
||||||
bittorrent *BTSession;
|
bittorrent *BTSession;
|
||||||
QSystemTrayIcon *myTrayIcon;
|
QSystemTrayIcon *myTrayIcon;
|
||||||
bool systrayIntegration;
|
bool systrayIntegration;
|
||||||
QStringList enabled_engines;
|
SupportedEngines *supported_engines;
|
||||||
QTimer *searchTimeout;
|
QTimer *searchTimeout;
|
||||||
SearchTab *currentSearchTab;
|
SearchTab *currentSearchTab;
|
||||||
QPushButton *closeTab_button;
|
QPushButton *closeTab_button;
|
||||||
QList<SearchTab*> all_tab; // To store all tabs
|
QList<SearchTab*> all_tab; // To store all tabs
|
||||||
public:
|
const SearchCategories full_cat_names;
|
||||||
SearchEngine(bittorrent *BTSession, QSystemTrayIcon *myTrayIcon, bool systrayIntegration);
|
public:
|
||||||
~SearchEngine();
|
SearchEngine(bittorrent *BTSession, QSystemTrayIcon *myTrayIcon, bool systrayIntegration);
|
||||||
float getPluginVersion(QString filePath) const;
|
~SearchEngine();
|
||||||
public slots:
|
float getPluginVersion(QString filePath) const;
|
||||||
void on_download_button_clicked();
|
QString selectedCategory() const;
|
||||||
void downloadSelectedItem(const QModelIndex& index);
|
|
||||||
protected slots:
|
public slots:
|
||||||
// Search slots
|
void on_download_button_clicked();
|
||||||
void tab_changed(int);//to prevent the use of the download button when the tab is empty
|
void downloadSelectedItem(const QModelIndex& index);
|
||||||
void on_search_button_clicked();
|
|
||||||
void on_stop_search_button_clicked();
|
protected slots:
|
||||||
void closeTab_button_clicked();
|
// Search slots
|
||||||
void appendSearchResult(QString line);
|
void tab_changed(int);//to prevent the use of the download button when the tab is empty
|
||||||
void searchFinished(int exitcode,QProcess::ExitStatus);
|
void on_search_button_clicked();
|
||||||
void readSearchOutput();
|
void closeTab_button_clicked();
|
||||||
void loadEngineSettings();
|
void appendSearchResult(QString line);
|
||||||
void searchStarted();
|
void searchFinished(int exitcode,QProcess::ExitStatus);
|
||||||
void startSearchHistory();
|
void readSearchOutput();
|
||||||
void updateNova();
|
void searchStarted();
|
||||||
void saveSearchHistory();
|
void startSearchHistory();
|
||||||
void on_enginesButton_clicked();
|
void updateNova();
|
||||||
void propagateSectionResized(int index, int oldsize , int newsize);
|
void saveSearchHistory();
|
||||||
void saveResultsColumnsWidth();
|
void on_enginesButton_clicked();
|
||||||
void downloadFinished(int exitcode, QProcess::ExitStatus);
|
void propagateSectionResized(int index, int oldsize , int newsize);
|
||||||
void downloadTorrent(QString engine_url, QString torrent_url);
|
void saveResultsColumnsWidth();
|
||||||
void displayPatternContextMenu(QPoint);
|
void downloadFinished(int exitcode, QProcess::ExitStatus);
|
||||||
void createCompleter();
|
void downloadTorrent(QString engine_url, QString torrent_url);
|
||||||
|
void displayPatternContextMenu(QPoint);
|
||||||
|
void createCompleter();
|
||||||
|
void fillCatCombobox();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#VERSION: 1.23
|
#VERSION: 1.31
|
||||||
#AUTHORS: Fabien Devaux (fab@gnux.info)
|
#AUTHORS: Fabien Devaux (fab@gnux.info)
|
||||||
|
|
||||||
# Redistribution and use in source and binary forms, with or without
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -31,14 +31,15 @@ from xml.dom import minidom
|
||||||
import re
|
import re
|
||||||
|
|
||||||
class mininova(object):
|
class mininova(object):
|
||||||
|
# Mandatory properties
|
||||||
url = 'http://www.mininova.org'
|
url = 'http://www.mininova.org'
|
||||||
name = 'Mininova'
|
name = 'Mininova'
|
||||||
table_items = 'added cat name size seeds leech'.split()
|
supported_categories = {'all': '0', 'movies': '4', 'tv': '8', 'music': '5', 'games': '3', 'anime': '1', 'software': '7', 'pictures': '6', 'books': '2'}
|
||||||
|
|
||||||
def download_torrent(self, info):
|
def download_torrent(self, info):
|
||||||
print download_file(info)
|
print download_file(info)
|
||||||
|
|
||||||
def search(self, what):
|
def search(self, what, cat='all'):
|
||||||
|
|
||||||
def get_link(lnk):
|
def get_link(lnk):
|
||||||
lnks = lnk.getElementsByTagName('a')
|
lnks = lnk.getElementsByTagName('a')
|
||||||
|
@ -71,10 +72,15 @@ class mininova(object):
|
||||||
return txt.toxml()
|
return txt.toxml()
|
||||||
else:
|
else:
|
||||||
return ''.join([ get_text(n) for n in txt.childNodes])
|
return ''.join([ get_text(n) for n in txt.childNodes])
|
||||||
|
|
||||||
|
if cat == 'all':
|
||||||
|
self.table_items = 'added cat name size seeds leech'.split()
|
||||||
|
else:
|
||||||
|
self.table_items = 'added name size seeds leech'.split()
|
||||||
page = 1
|
page = 1
|
||||||
while True and page<11:
|
while True and page<11:
|
||||||
res = 0
|
res = 0
|
||||||
dat = retrieve_url(self.url+'/search/%s/seeds/%d'%(what, page))
|
dat = retrieve_url(self.url+'/search/%s/%s/seeds/%d'%(what, self.supported_categories[cat], page))
|
||||||
dat = re.sub("<a href=\"http://www.boardreader.com/index.php.*\"", "<a href=\"plop\"", dat)
|
dat = re.sub("<a href=\"http://www.boardreader.com/index.php.*\"", "<a href=\"plop\"", dat)
|
||||||
dat = re.sub("<=", "<=", dat)
|
dat = re.sub("<=", "<=", dat)
|
||||||
dat = re.sub("&\s", "& ", dat)
|
dat = re.sub("&\s", "& ", dat)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
isohunt: 1.21
|
isohunt: 1.21
|
||||||
torrentreactor: 1.11
|
torrentreactor: 1.11
|
||||||
btjunkie: 2.11
|
btjunkie: 2.11
|
||||||
mininova: 1.23
|
mininova: 1.31
|
||||||
piratebay: 1.11
|
piratebay: 1.11
|
||||||
|
|
|
@ -64,15 +64,15 @@ def retrieve_url(url):
|
||||||
return dat.encode('utf-8', 'replace')
|
return dat.encode('utf-8', 'replace')
|
||||||
|
|
||||||
def download_file(url):
|
def download_file(url):
|
||||||
""" Download file at url and write it to a file, return the path to the file and the url """
|
""" Download file at url and write it to a file, return the path to the file and the url """
|
||||||
file, path = tempfile.mkstemp()
|
file, path = tempfile.mkstemp()
|
||||||
file = os.fdopen(file, "wb")
|
file = os.fdopen(file, "wb")
|
||||||
# Download url
|
# Download url
|
||||||
req = urllib2.Request(url)
|
req = urllib2.Request(url)
|
||||||
response = urllib2.urlopen(req)
|
response = urllib2.urlopen(req)
|
||||||
dat = response.read()
|
dat = response.read()
|
||||||
# Write it to a file
|
# Write it to a file
|
||||||
file.write(dat)
|
file.write(dat)
|
||||||
file.close()
|
file.close()
|
||||||
# return file path
|
# return file path
|
||||||
return path+" "+url
|
return path+" "+url
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
# POSSIBILITY OF SUCH DAMAGE.
|
# POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
|
||||||
#VERSION: 1.10
|
#VERSION: 1.23
|
||||||
|
|
||||||
# Author:
|
# Author:
|
||||||
# Fabien Devaux <fab AT gnux DOT info>
|
# Fabien Devaux <fab AT gnux DOT info>
|
||||||
|
@ -43,6 +43,7 @@ import os
|
||||||
import glob
|
import glob
|
||||||
|
|
||||||
THREADED = True
|
THREADED = True
|
||||||
|
CATEGORIES = ('all', 'movies', 'tv', 'music', 'games', 'anime', 'software', 'pictures', 'books')
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# Every engine should have a "search" method taking
|
# Every engine should have a "search" method taking
|
||||||
|
@ -65,48 +66,90 @@ for engine in engines:
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def engineToXml(short_name):
|
||||||
|
xml = "<%s>\n"%short_name
|
||||||
|
exec "engine = %s()"%short_name
|
||||||
|
xml += "<name>%s</name>\n"%engine.name
|
||||||
|
xml += "<url>%s</url>\n"%engine.url
|
||||||
|
xml += "<categories>"
|
||||||
|
if hasattr(engine, 'supported_categories'):
|
||||||
|
supported_categories = engine.supported_categories.keys()
|
||||||
|
supported_categories.remove('all')
|
||||||
|
xml += " ".join(supported_categories)
|
||||||
|
xml += "</categories>\n"
|
||||||
|
xml += "</%s>\n"%short_name
|
||||||
|
return xml
|
||||||
|
|
||||||
|
def displayCapabilities():
|
||||||
|
"""
|
||||||
|
Display capabilities in XML format
|
||||||
|
<capabilities>
|
||||||
|
<engine_short_name>
|
||||||
|
<name>long name</name>
|
||||||
|
<url>http://example.com</url>
|
||||||
|
<categories>movies music games</categories>
|
||||||
|
</engine_short_name>
|
||||||
|
</capabilities>
|
||||||
|
"""
|
||||||
|
xml = "<capabilities>"
|
||||||
|
for short_name in supported_engines:
|
||||||
|
xml += engineToXml(short_name)
|
||||||
|
xml += "</capabilities>"
|
||||||
|
print xml
|
||||||
|
|
||||||
class EngineLauncher(threading.Thread):
|
class EngineLauncher(threading.Thread):
|
||||||
def __init__(self, engine, what):
|
def __init__(self, engine, what, cat='all'):
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
self.engine = engine
|
self.engine = engine
|
||||||
self.what = what
|
self.what = what
|
||||||
|
self.cat = cat
|
||||||
def run(self):
|
def run(self):
|
||||||
self.engine.search(self.what)
|
if hasattr(self.engine, 'supported_categories'):
|
||||||
|
if self.cat == 'all' or self.cat in self.engine.supported_categories.keys():
|
||||||
|
self.engine.search(self.what, self.cat)
|
||||||
|
elif self.cat == 'all':
|
||||||
|
self.engine.search(self.what)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if len(sys.argv) < 2:
|
if len(sys.argv) < 2:
|
||||||
raise SystemExit('./nova2.py [all|engine1[,engine2]*] <keywords>\navailable engines: %s'%
|
raise SystemExit('./nova2.py [all|engine1[,engine2]*] <category> <keywords>\navailable engines: %s'%
|
||||||
(','.join(supported_engines)))
|
(','.join(supported_engines)))
|
||||||
|
|
||||||
if len(sys.argv) == 2:
|
if len(sys.argv) == 2:
|
||||||
if sys.argv[1] == "--supported_engines":
|
if sys.argv[1] == "--capabilities":
|
||||||
print ','.join(supported_engines)
|
displayCapabilities()
|
||||||
sys.exit(0)
|
|
||||||
elif sys.argv[1] == "--supported_engines_infos":
|
|
||||||
res = []
|
|
||||||
for e in supported_engines:
|
|
||||||
exec "res.append(%s().name+'|'+%s().url)"%(e,e)
|
|
||||||
print ','.join(res)
|
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
else:
|
else:
|
||||||
raise SystemExit('./nova.py [all|engine1[,engine2]*] <keywords>\navailable engines: %s'%
|
raise SystemExit('./nova.py [all|engine1[,engine2]*] <category> <keywords>\navailable engines: %s'%
|
||||||
(','.join(supported_engines)))
|
(','.join(supported_engines)))
|
||||||
|
|
||||||
engines_list = [e.lower() for e in sys.argv[1].strip().split(',')]
|
engines_list = [e.lower() for e in sys.argv[1].strip().split(',')]
|
||||||
|
|
||||||
if 'all' in engines_list:
|
if 'all' in engines_list:
|
||||||
engines_list = supported_engines
|
engines_list = supported_engines
|
||||||
|
|
||||||
what = '+'.join(sys.argv[2:])
|
cat = sys.argv[2].lower()
|
||||||
|
|
||||||
|
if cat not in CATEGORIES:
|
||||||
|
raise SystemExit('Invalid category!')
|
||||||
|
|
||||||
|
what = '+'.join(sys.argv[3:])
|
||||||
|
|
||||||
threads = []
|
threads = []
|
||||||
for engine in engines_list:
|
for engine in engines_list:
|
||||||
try:
|
try:
|
||||||
if THREADED:
|
if THREADED:
|
||||||
exec "l = EngineLauncher(%s(), what)" % engine
|
exec "l = EngineLauncher(%s(), what, cat)"%engine
|
||||||
threads.append(l)
|
threads.append(l)
|
||||||
l.start()
|
l.start()
|
||||||
else:
|
else:
|
||||||
engine().search(what)
|
exec "e = %s()"%engine
|
||||||
|
if hasattr(engine, 'supported_categories'):
|
||||||
|
if cat == 'all' or cat in e.supported_categories.keys():
|
||||||
|
e.search(what, cat)
|
||||||
|
elif self.cat == 'all':
|
||||||
|
e.search(what)
|
||||||
|
engine().search(what, cat)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
if THREADED:
|
if THREADED:
|
||||||
|
|
|
@ -118,7 +118,7 @@
|
||||||
<action name="actionBuy_it">
|
<action name="actionBuy_it">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="icons.qrc">
|
<iconset resource="icons.qrc">
|
||||||
<normaloff>:/Icons/money.png</normaloff>:/Icons/money.png</iconset>
|
<normaloff>:/Icons/oxygen/wallet.png</normaloff>:/Icons/oxygen/wallet.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Buy it</string>
|
<string>Buy it</string>
|
||||||
|
|
|
@ -185,7 +185,8 @@ HEADERS += GUI.h \
|
||||||
stacktrace.h \
|
stacktrace.h \
|
||||||
torrentPersistentData.h \
|
torrentPersistentData.h \
|
||||||
FeedDownloader.h \
|
FeedDownloader.h \
|
||||||
feedList.h
|
feedList.h \
|
||||||
|
supportedEngines.h
|
||||||
FORMS += MainWindow.ui \
|
FORMS += MainWindow.ui \
|
||||||
options.ui \
|
options.ui \
|
||||||
about.ui \
|
about.ui \
|
||||||
|
|
173
src/supportedEngines.h
Normal file
173
src/supportedEngines.h
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt4 and libtorrent.
|
||||||
|
* Copyright (C) 2006 Christophe Dumez
|
||||||
|
*
|
||||||
|
* 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) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the copyright holders give permission to
|
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||||
|
* and distribute the linked executables. You must obey the GNU General Public
|
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||||
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
|
* exception statement from your version.
|
||||||
|
*
|
||||||
|
* Contact : chris@qbittorrent.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SEARCHENGINES_H
|
||||||
|
#define SEARCHENGINES_H
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QDomDocument>
|
||||||
|
#include <QDomNode>
|
||||||
|
#include <QDomElement>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QSettings>
|
||||||
|
|
||||||
|
#include "misc.h"
|
||||||
|
|
||||||
|
class SearchCategories: public QObject, public QHash<QString, QString> {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
SearchCategories() {
|
||||||
|
(*this)["all"] = tr("All categories");
|
||||||
|
(*this)["movies"] = tr("Movies");
|
||||||
|
(*this)["tv"] = tr("TV shows");
|
||||||
|
(*this)["music"] = tr("Music");
|
||||||
|
(*this)["games"] = tr("Games");
|
||||||
|
(*this)["anime"] = tr("Anime");
|
||||||
|
(*this)["software"] = tr("Software");
|
||||||
|
(*this)["pictures"] = tr("Pictures");
|
||||||
|
(*this)["books"] = tr("Books");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SupportedEngine {
|
||||||
|
private:
|
||||||
|
QString name;
|
||||||
|
QString full_name;
|
||||||
|
QString url;
|
||||||
|
QStringList supported_categories;
|
||||||
|
bool enabled;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SupportedEngine(QDomElement engine_elem) {
|
||||||
|
name = engine_elem.tagName();
|
||||||
|
full_name = engine_elem.elementsByTagName("name").at(0).toElement().text();
|
||||||
|
url = engine_elem.elementsByTagName("url").at(0).toElement().text();
|
||||||
|
supported_categories = engine_elem.elementsByTagName("categories").at(0).toElement().text().split(" ");
|
||||||
|
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
|
||||||
|
QVariantList disabled_engines = settings.value(QString::fromUtf8("SearchEngines/disabledEngines"), QVariantList()).toList();
|
||||||
|
enabled = !disabled_engines.contains(QVariant(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString getName() const { return name; }
|
||||||
|
QString getUrl() const { return url; }
|
||||||
|
QString getFullName() const { return full_name; }
|
||||||
|
QStringList getSupportedCategories() const { return supported_categories; }
|
||||||
|
bool isEnabled() const { return enabled; }
|
||||||
|
void setEnabled(bool _enabled) {
|
||||||
|
enabled = _enabled;
|
||||||
|
// Save to Hard disk
|
||||||
|
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
|
||||||
|
QVariantList disabled_engines = settings.value(QString::fromUtf8("SearchEngines/disabledEngines"), QVariantList()).toList();
|
||||||
|
if(enabled) {
|
||||||
|
disabled_engines.removeAll(QVariant(name));
|
||||||
|
} else {
|
||||||
|
disabled_engines.append(QVariant(name));
|
||||||
|
}
|
||||||
|
settings.setValue("SearchEngines/disabledEngines", disabled_engines);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SupportedEngines: public QObject, public QHash<QString, SupportedEngine*> {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void newSupportedEngine(QString name);
|
||||||
|
|
||||||
|
public:
|
||||||
|
SupportedEngines() {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
~SupportedEngines() {
|
||||||
|
qDeleteAll(this->values());
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList enginesEnabled() const {
|
||||||
|
QStringList engines;
|
||||||
|
foreach(SupportedEngine *engine, values()) {
|
||||||
|
if(engine->isEnabled())
|
||||||
|
engines << engine->getName();
|
||||||
|
}
|
||||||
|
return engines;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList supportedCategories() const {
|
||||||
|
QStringList supported_cat;
|
||||||
|
foreach(SupportedEngine *engine, values()) {
|
||||||
|
QStringList s = engine->getSupportedCategories();
|
||||||
|
foreach(QString cat, s) {
|
||||||
|
cat = cat.trimmed();
|
||||||
|
if(!cat.isEmpty() && !supported_cat.contains(cat))
|
||||||
|
supported_cat << cat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return supported_cat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void update() {
|
||||||
|
QProcess nova;
|
||||||
|
QStringList params;
|
||||||
|
params << misc::qBittorrentPath()+"search_engine"+QDir::separator()+"nova2.py";
|
||||||
|
params << "--capabilities";
|
||||||
|
nova.start("python", params, QIODevice::ReadOnly);
|
||||||
|
nova.waitForStarted();
|
||||||
|
nova.waitForFinished();
|
||||||
|
QString capabilities = QString(nova.readAll());
|
||||||
|
QDomDocument xml_doc;
|
||||||
|
if(!xml_doc.setContent(capabilities)) {
|
||||||
|
std::cerr << "Could not parse Nova search engine capabilities, msg: " << capabilities.toLocal8Bit().data() << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QDomElement root = xml_doc.documentElement();
|
||||||
|
if(root.tagName() != "capabilities") {
|
||||||
|
std::cout << "Invalid XML file for Nova search engine capabilities, msg: " << capabilities.toLocal8Bit().data() << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for(QDomNode engine_node = root.firstChild(); !engine_node.isNull(); engine_node = engine_node.nextSibling()) {
|
||||||
|
QDomElement engine_elem = engine_node.toElement();
|
||||||
|
if(!engine_elem.isNull()) {
|
||||||
|
SupportedEngine *s = new SupportedEngine(engine_elem);
|
||||||
|
if(this->contains(s->getName())) {
|
||||||
|
// Already in the list
|
||||||
|
delete s;
|
||||||
|
} else {
|
||||||
|
qDebug("Supported search engine: %s", s->getFullName().toLocal8Bit().data());
|
||||||
|
(*this)[s->getName()] = s;
|
||||||
|
emit newSupportedEngine(s->getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SEARCHENGINES_H
|
Loading…
Reference in a new issue