mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2024-11-25 10:46:15 +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
|
||||
- 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: Implemented a RSS feed downloader with filter support
|
||||
- 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
|
||||
void FinishedTorrents::displayFinishedHoSMenu(const QPoint& pos){
|
||||
void FinishedTorrents::displayFinishedHoSMenu(const QPoint&){
|
||||
QMenu hideshowColumn(this);
|
||||
hideshowColumn.setTitle(tr("Hide or Show Column"));
|
||||
int lastCol = F_RATIO;
|
||||
|
@ -470,7 +470,7 @@ void FinishedTorrents::displayFinishedHoSMenu(const QPoint& pos){
|
|||
hideshowColumn.addAction(getActionHoSCol(i));
|
||||
}
|
||||
// Call menu
|
||||
hideshowColumn.exec(mapToGlobal(pos)+QPoint(10,34));
|
||||
hideshowColumn.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
// 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">
|
||||
<property name="icon">
|
||||
<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 name="text">
|
||||
<string>Buy it</string>
|
||||
|
|
|
@ -312,7 +312,7 @@ void DownloadingTorrents::displayDLListMenu(const QPoint&) {
|
|||
*/
|
||||
|
||||
// hide/show columns menu
|
||||
void DownloadingTorrents::displayDLHoSMenu(const QPoint& pos){
|
||||
void DownloadingTorrents::displayDLHoSMenu(const QPoint&){
|
||||
QMenu hideshowColumn(this);
|
||||
hideshowColumn.setTitle(tr("Hide or Show Column"));
|
||||
int lastCol;
|
||||
|
@ -325,7 +325,7 @@ void DownloadingTorrents::displayDLHoSMenu(const QPoint& pos){
|
|||
hideshowColumn.addAction(getActionHoSCol(i));
|
||||
}
|
||||
// Call menu
|
||||
hideshowColumn.exec(mapToGlobal(pos)+QPoint(10,10));
|
||||
hideshowColumn.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
// toggle hide/show a column
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
#include <QInputDialog>
|
||||
|
||||
#ifdef HAVE_ZZIP
|
||||
#include <zzip/zzip.h>
|
||||
#include <zzip/zzip.h>
|
||||
#endif
|
||||
|
||||
#define ENGINE_NAME 0
|
||||
|
@ -51,7 +51,7 @@
|
|||
#define ENGINE_STATE 2
|
||||
#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);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
pluginsTree->header()->resizeSection(0, 170);
|
||||
|
@ -66,14 +66,14 @@ engineSelectDlg::engineSelectDlg(QWidget *parent) : QDialog(parent) {
|
|||
downloader = new downloadThread(this);
|
||||
connect(downloader, SIGNAL(downloadFinished(QString, QString)), this, SLOT(processDownloadedFile(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)));
|
||||
show();
|
||||
}
|
||||
|
||||
engineSelectDlg::~engineSelectDlg() {
|
||||
qDebug("Destroying engineSelectDlg");
|
||||
saveSettings();
|
||||
emit enginesChanged();
|
||||
qDebug("Before deleting 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() {
|
||||
// Download version file from primary server
|
||||
downloader->downloadUrl("http://www.dchris.eu/search_engine2/versions.txt");
|
||||
}
|
||||
|
||||
void engineSelectDlg::toggleEngineState(QTreeWidgetItem *item, int) {
|
||||
int index = pluginsTree->indexOfTopLevelItem(item);
|
||||
QString id = item->text(ENGINE_ID);
|
||||
bool new_val = !installed_engines.value(id, true);
|
||||
installed_engines[id] = new_val;
|
||||
QString enabledTxt;
|
||||
if(new_val){
|
||||
enabledTxt = tr("True");
|
||||
setRowColor(index, "green");
|
||||
}else{
|
||||
enabledTxt = tr("False");
|
||||
setRowColor(index, "red");
|
||||
SupportedEngine *engine = supported_engines->value(item->text(ENGINE_ID));
|
||||
engine->setEnabled(!engine->isEnabled());
|
||||
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");
|
||||
}
|
||||
item->setText(ENGINE_STATE, enabledTxt);
|
||||
}
|
||||
|
||||
void engineSelectDlg::displayContextMenu(const QPoint& pos) {
|
||||
void engineSelectDlg::displayContextMenu(const QPoint&) {
|
||||
QMenu myContextMenu(this);
|
||||
QModelIndex index;
|
||||
// Enable/disable pause/start action given the DL state
|
||||
|
@ -160,11 +141,11 @@ void engineSelectDlg::displayContextMenu(const QPoint& pos) {
|
|||
QTreeWidgetItem *item;
|
||||
foreach(item, items) {
|
||||
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);
|
||||
has_disable = true;
|
||||
}
|
||||
if(!installed_engines.value(id, true) and !has_enable) {
|
||||
if(!supported_engines->value(id)->isEnabled() and !has_enable) {
|
||||
myContextMenu.addAction(actionEnable);
|
||||
has_enable = true;
|
||||
}
|
||||
|
@ -172,7 +153,7 @@ void engineSelectDlg::displayContextMenu(const QPoint& pos) {
|
|||
}
|
||||
myContextMenu.addSeparator();
|
||||
myContextMenu.addAction(actionUninstall);
|
||||
myContextMenu.exec(mapToGlobal(pos)+QPoint(12, 58));
|
||||
myContextMenu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
void engineSelectDlg::on_closeButton_clicked() {
|
||||
|
@ -191,8 +172,8 @@ void engineSelectDlg::on_actionUninstall_triggered() {
|
|||
if(QFile::exists(":/search_engine/engines/"+id+".py")) {
|
||||
error = true;
|
||||
// Disable it instead
|
||||
installed_engines.insert(id, false);
|
||||
item->setText(ENGINE_STATE, tr("False"));
|
||||
supported_engines->value(id)->setEnabled(false);
|
||||
item->setText(ENGINE_STATE, tr("No"));
|
||||
setRowColor(index, "red");
|
||||
continue;
|
||||
}else {
|
||||
|
@ -206,8 +187,8 @@ void engineSelectDlg::on_actionUninstall_triggered() {
|
|||
foreach(file, files) {
|
||||
enginesFolder.remove(file);
|
||||
}
|
||||
// Remove it from lists
|
||||
installed_engines.remove(id);
|
||||
// Remove it from supported engines
|
||||
delete supported_engines->take(id);
|
||||
delete item;
|
||||
change = true;
|
||||
}
|
||||
|
@ -225,8 +206,8 @@ void engineSelectDlg::enableSelection() {
|
|||
int index = pluginsTree->indexOfTopLevelItem(item);
|
||||
Q_ASSERT(index != -1);
|
||||
QString id = item->text(ENGINE_ID);
|
||||
installed_engines.insert(id, true);
|
||||
item->setText(ENGINE_STATE, tr("True"));
|
||||
supported_engines->value(id)->setEnabled(true);
|
||||
item->setText(ENGINE_STATE, tr("Yes"));
|
||||
setRowColor(index, "green");
|
||||
}
|
||||
}
|
||||
|
@ -238,8 +219,8 @@ void engineSelectDlg::disableSelection() {
|
|||
int index = pluginsTree->indexOfTopLevelItem(item);
|
||||
Q_ASSERT(index != -1);
|
||||
QString id = item->text(ENGINE_ID);
|
||||
installed_engines.insert(id, false);
|
||||
item->setText(ENGINE_STATE, tr("False"));
|
||||
supported_engines->value(id)->setEnabled(false);
|
||||
item->setText(ENGINE_STATE, tr("No"));
|
||||
setRowColor(index, "red");
|
||||
}
|
||||
}
|
||||
|
@ -247,108 +228,11 @@ void engineSelectDlg::disableSelection() {
|
|||
// Set the color of a row in data model
|
||||
void engineSelectDlg::setRowColor(int row, QString color){
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
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*> res;
|
||||
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()));
|
||||
return;
|
||||
}
|
||||
// Process with install
|
||||
// Process with install
|
||||
QString dest_path = misc::qBittorrentPath()+"search_engine"+QDir::separator()+"engines"+QDir::separator()+plugin_name+".py";
|
||||
bool update = false;
|
||||
if(QFile::exists(dest_path)) {
|
||||
// Backup in case install fails
|
||||
// Backup in case install fails
|
||||
QFile::copy(dest_path, dest_path+".bak");
|
||||
QFile::remove(dest_path);
|
||||
update = true;
|
||||
}
|
||||
// Copy the plugin
|
||||
// Copy the plugin
|
||||
QFile::copy(path, dest_path);
|
||||
// Check if this was correctly installed
|
||||
if(!checkInstalled(plugin_name)) {
|
||||
// Update supported plugins
|
||||
supported_engines->update();
|
||||
// Check if this was correctly installed
|
||||
if(!supported_engines->contains(plugin_name)) {
|
||||
if(update) {
|
||||
// Remove broken file
|
||||
// Remove broken file
|
||||
QFile::remove(dest_path);
|
||||
// restore backup
|
||||
// restore backup
|
||||
QFile::copy(dest_path+".bak", dest_path);
|
||||
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()));
|
||||
return;
|
||||
} else {
|
||||
// Remove broken file
|
||||
// Remove broken file
|
||||
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()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Install was successful, remove backup
|
||||
// Install was successful, remove backup
|
||||
if(update) {
|
||||
QFile::remove(dest_path+".bak");
|
||||
}
|
||||
// Refresh plugin list
|
||||
loadSupportedSearchEngines();
|
||||
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()));
|
||||
return;
|
||||
|
@ -533,175 +417,212 @@ void engineSelectDlg::installPlugin(QString path, QString plugin_name) {
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
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
|
||||
void engineSelectDlg::loadSupportedSearchEngines() {
|
||||
// Some clean up first
|
||||
pluginsTree->clear();
|
||||
foreach(QString name, supported_engines->keys()) {
|
||||
addNewEngine(name);
|
||||
}
|
||||
}
|
||||
|
||||
bool engineSelectDlg::parseVersionsFile(QString versions_file, QString updateServer) {
|
||||
qDebug("Checking if update is needed");
|
||||
bool file_correct = false;
|
||||
QFile versions(versions_file);
|
||||
if(!versions.open(QIODevice::ReadOnly | QIODevice::Text)){
|
||||
qDebug("* Error: Could not read versions.txt file");
|
||||
return false;
|
||||
void engineSelectDlg::addNewEngine(QString engine_name) {
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem(pluginsTree);
|
||||
SupportedEngine *engine = supported_engines->value(engine_name);
|
||||
item->setText(ENGINE_NAME, engine->getFullName());
|
||||
item->setText(ENGINE_URL, engine->getUrl());
|
||||
item->setText(ENGINE_ID, engine->getName());
|
||||
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;
|
||||
while(!versions.atEnd()) {
|
||||
QByteArray line = versions.readLine();
|
||||
line.replace("\n", "");
|
||||
line = line.trimmed();
|
||||
if(line.isEmpty()) continue;
|
||||
if(line.startsWith("#")) continue;
|
||||
QList<QByteArray> list = line.split(' ');
|
||||
if(list.size() != 2) continue;
|
||||
QString plugin_name = QString(list.first());
|
||||
if(!plugin_name.endsWith(":")) continue;
|
||||
plugin_name.chop(1); // remove trailing ':'
|
||||
// Handle icon
|
||||
QString iconPath = misc::qBittorrentPath()+"search_engine"+QDir::separator()+"engines"+QDir::separator()+engine->getName()+".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()+engine->getName()+".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(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;
|
||||
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());
|
||||
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
|
||||
}
|
||||
}
|
||||
// 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) {
|
||||
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)));
|
||||
bool engineSelectDlg::parseVersionsFile(QString versions_file, QString updateServer) {
|
||||
qDebug("Checking if update is needed");
|
||||
bool file_correct = false;
|
||||
QFile versions(versions_file);
|
||||
if(!versions.open(QIODevice::ReadOnly | QIODevice::Text)){
|
||||
qDebug("* Error: Could not read versions.txt file");
|
||||
return false;
|
||||
}
|
||||
bool updated = false;
|
||||
while(!versions.atEnd()) {
|
||||
QByteArray line = versions.readLine();
|
||||
line.replace("\n", "");
|
||||
line = line.trimmed();
|
||||
if(line.isEmpty()) continue;
|
||||
if(line.startsWith("#")) continue;
|
||||
QList<QByteArray> list = line.split(' ');
|
||||
if(list.size() != 2) continue;
|
||||
QString plugin_name = QString(list.first());
|
||||
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
|
||||
QFile::remove(filePath);
|
||||
return;
|
||||
// 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;
|
||||
}
|
||||
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");
|
||||
downloader->downloadUrl("http://hydr0g3n.free.fr/search_engine2/versions.txt");
|
||||
return;
|
||||
}
|
||||
QFile::remove(filePath);
|
||||
return;
|
||||
}
|
||||
if(url == "http://hydr0g3n.free.fr/search_engine2/versions.txt") {
|
||||
if(!parseVersionsFile(filePath, "http://hydr0g3n.free.fr/search_engine2/")) {
|
||||
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()));
|
||||
}
|
||||
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;
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
#include "ui_engineSelect.h"
|
||||
#include "supportedEngines.h"
|
||||
|
||||
class downloadThread;
|
||||
class QDropEvent;
|
||||
|
@ -40,12 +41,11 @@ class engineSelectDlg : public QDialog, public Ui::engineSelect{
|
|||
Q_OBJECT
|
||||
|
||||
private:
|
||||
// Search related
|
||||
QHash<QString, bool> installed_engines;
|
||||
downloadThread *downloader;
|
||||
SupportedEngines *supported_engines;
|
||||
|
||||
public:
|
||||
engineSelectDlg(QWidget *parent);
|
||||
engineSelectDlg(QWidget *parent, SupportedEngines *supported_engines);
|
||||
~engineSelectDlg();
|
||||
QList<QTreeWidgetItem*> findItemsWithUrl(QString url);
|
||||
QTreeWidgetItem* findItemWithID(QString id);
|
||||
|
@ -53,15 +53,14 @@ class engineSelectDlg : public QDialog, public Ui::engineSelect{
|
|||
protected:
|
||||
bool parseVersionsFile(QString versions_file, QString updateServer);
|
||||
bool isUpdateNeeded(QString plugin_name, float new_version) const;
|
||||
bool checkInstalled(QString plugin_name) const;
|
||||
|
||||
signals:
|
||||
void enginesChanged();
|
||||
|
||||
protected slots:
|
||||
void saveSettings();
|
||||
void on_closeButton_clicked();
|
||||
void loadSupportedSearchEngines(bool first=false);
|
||||
void loadSupportedSearchEngines();
|
||||
void addNewEngine(QString engine_name);
|
||||
void toggleEngineState(QTreeWidgetItem*, int);
|
||||
void setRowColor(int row, QString color);
|
||||
void processDownloadedFile(QString url, QString filePath);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file>Icons/rss32.png</file>
|
||||
<file>Icons/money.png</file>
|
||||
<file>Icons/sphere2.png</file>
|
||||
<file>Icons/downarrow.png</file>
|
||||
<file>Icons/url.png</file>
|
||||
|
@ -95,6 +94,7 @@
|
|||
<file>Icons/oxygen/bt_settings.png</file>
|
||||
<file>Icons/oxygen/document-new.png</file>
|
||||
<file>Icons/oxygen/tab-close.png</file>
|
||||
<file>Icons/oxygen/wallet.png</file>
|
||||
<file>Icons/oxygen/webui.png</file>
|
||||
<file>Icons/oxygen/list-remove.png</file>
|
||||
<file>Icons/oxygen/connection.png</file>
|
||||
|
|
|
@ -30,53 +30,7 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<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>
|
||||
<widget class="QComboBox" name="comboCategory"/>
|
||||
</item>
|
||||
<item>
|
||||
<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)));
|
||||
searchTimeout = new QTimer(this);
|
||||
searchTimeout->setSingleShot(true);
|
||||
connect(searchTimeout, SIGNAL(timeout()), this, SLOT(on_stop_search_button_clicked()));
|
||||
// Check last enabled search engines
|
||||
loadEngineSettings();
|
||||
connect(searchTimeout, SIGNAL(timeout()), this, SLOT(on_search_button_clicked()));
|
||||
// Update nova.py search plugin if necessary
|
||||
updateNova();
|
||||
supported_engines = new SupportedEngines();
|
||||
// Fill in category combobox
|
||||
fillCatCombobox();
|
||||
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(){
|
||||
qDebug("Search destruction");
|
||||
// save the searchHistory for later uses
|
||||
saveSearchHistory();
|
||||
searchProcess->kill();
|
||||
searchProcess->waitForFinished();
|
||||
foreach(QProcess *downloader, downloaders) {
|
||||
downloader->kill();
|
||||
downloader->waitForFinished();
|
||||
delete downloader;
|
||||
}
|
||||
foreach(QProcess *downloader, downloaders) {
|
||||
downloader->kill();
|
||||
downloader->waitForFinished();
|
||||
delete downloader;
|
||||
}
|
||||
delete searchTimeout;
|
||||
delete searchProcess;
|
||||
delete supported_engines;
|
||||
if(searchCompleter)
|
||||
delete searchCompleter;
|
||||
}
|
||||
|
@ -145,20 +161,19 @@ void SearchEngine::displayPatternContextMenu(QPoint) {
|
|||
|
||||
void SearchEngine::tab_changed(int t)
|
||||
{//when we switch from a tab that is not empty to another that is empty the download button
|
||||
//doesn't have to be available
|
||||
if(t>-1)
|
||||
{//-1 = no more tab
|
||||
//doesn't have to be available
|
||||
if(t>-1)
|
||||
{//-1 = no more tab
|
||||
if(all_tab.at(tabWidget->currentIndex())->getCurrentSearchListModel()->rowCount()) {
|
||||
download_button->setEnabled(true);
|
||||
download_button->setEnabled(true);
|
||||
} else {
|
||||
download_button->setEnabled(false);
|
||||
download_button->setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SearchEngine::on_enginesButton_clicked() {
|
||||
engineSelectDlg *dlg = new engineSelectDlg(this);
|
||||
connect(dlg, SIGNAL(enginesChanged()), this, SLOT(loadEngineSettings()));
|
||||
new engineSelectDlg(this, supported_engines);
|
||||
}
|
||||
|
||||
// get the last searchs from a QSettings to a QStringList
|
||||
|
@ -169,23 +184,6 @@ void SearchEngine::startSearchHistory(){
|
|||
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
|
||||
void SearchEngine::saveSearchHistory()
|
||||
{
|
||||
|
@ -198,14 +196,14 @@ void SearchEngine::saveSearchHistory()
|
|||
// Function called when we click on search button
|
||||
void SearchEngine::on_search_button_clicked(){
|
||||
if(searchProcess->state() != QProcess::NotRunning){
|
||||
searchProcess->kill();
|
||||
searchProcess->waitForFinished();
|
||||
searchProcess->terminate();
|
||||
search_stopped = true;
|
||||
if(searchTimeout->isActive()) {
|
||||
searchTimeout->stop();
|
||||
}
|
||||
search_button->setText("Search");
|
||||
return;
|
||||
}
|
||||
if(searchTimeout->isActive()) {
|
||||
searchTimeout->stop();
|
||||
}
|
||||
QString pattern = search_pattern->text().trimmed();
|
||||
// No search pattern entered
|
||||
if(pattern.isEmpty()){
|
||||
|
@ -230,12 +228,13 @@ void SearchEngine::on_search_button_clicked(){
|
|||
}
|
||||
|
||||
// Getting checked search engines
|
||||
Q_ASSERT(!enabled_engines.empty());
|
||||
QStringList params;
|
||||
QStringList engineNames;
|
||||
search_stopped = false;
|
||||
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(" ");
|
||||
// Update SearchEngine widgets
|
||||
no_search_results = true;
|
||||
|
@ -293,15 +292,15 @@ void SearchEngine::saveResultsColumnsWidth() {
|
|||
}
|
||||
|
||||
void SearchEngine::downloadTorrent(QString engine_url, QString torrent_url) {
|
||||
QProcess *downloadProcess = new QProcess(this);
|
||||
connect(downloadProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(downloadFinished(int,QProcess::ExitStatus)));
|
||||
downloaders << downloadProcess;
|
||||
QStringList params;
|
||||
params << misc::qBittorrentPath()+"search_engine"+QDir::separator()+"nova2dl.py";
|
||||
params << engine_url;
|
||||
params << torrent_url;
|
||||
// Launch search
|
||||
downloadProcess->start("python", params, QIODevice::ReadOnly);
|
||||
QProcess *downloadProcess = new QProcess(this);
|
||||
connect(downloadProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(downloadFinished(int,QProcess::ExitStatus)));
|
||||
downloaders << downloadProcess;
|
||||
QStringList params;
|
||||
params << misc::qBittorrentPath()+"search_engine"+QDir::separator()+"nova2dl.py";
|
||||
params << engine_url;
|
||||
params << torrent_url;
|
||||
// Launch search
|
||||
downloadProcess->start("python", params, QIODevice::ReadOnly);
|
||||
}
|
||||
|
||||
void SearchEngine::searchStarted(){
|
||||
|
@ -316,7 +315,7 @@ void SearchEngine::downloadSelectedItem(const QModelIndex& index){
|
|||
int row = index.row();
|
||||
// Get Item url
|
||||
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();
|
||||
// Download from url
|
||||
downloadTorrent(engine_url, torrent_url);
|
||||
|
@ -343,19 +342,19 @@ void SearchEngine::readSearchOutput(){
|
|||
}
|
||||
|
||||
void SearchEngine::downloadFinished(int exitcode, QProcess::ExitStatus) {
|
||||
QProcess *downloadProcess = (QProcess*)sender();
|
||||
if(exitcode == 0) {
|
||||
QString line = QString::fromUtf8(downloadProcess->readAllStandardOutput()).trimmed();
|
||||
QStringList parts = line.split(' ');
|
||||
if(parts.size() == 2) {
|
||||
QString path = parts[0];
|
||||
QString url = parts[1];
|
||||
BTSession->processDownloadedFile(url, path);
|
||||
}
|
||||
}
|
||||
qDebug("Deleting downloadProcess");
|
||||
downloaders.removeAll(downloadProcess);
|
||||
delete downloadProcess;
|
||||
QProcess *downloadProcess = (QProcess*)sender();
|
||||
if(exitcode == 0) {
|
||||
QString line = QString::fromUtf8(downloadProcess->readAllStandardOutput()).trimmed();
|
||||
QStringList parts = line.split(' ');
|
||||
if(parts.size() == 2) {
|
||||
QString path = parts[0];
|
||||
QString url = parts[1];
|
||||
BTSession->processDownloadedFile(url, path);
|
||||
}
|
||||
}
|
||||
qDebug("Deleting downloadProcess");
|
||||
downloaders.removeAll(downloadProcess);
|
||||
delete downloadProcess;
|
||||
}
|
||||
|
||||
// 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(misc::qBittorrentPath()+"search_engine"+QDir::separator()+"nova2.py").setPermissions(perm);
|
||||
|
||||
filePath = misc::qBittorrentPath()+"search_engine"+QDir::separator()+"nova2dl.py";
|
||||
if(misc::getPluginVersion(":/search_engine/nova2dl.py") > misc::getPluginVersion(filePath)) {
|
||||
filePath = misc::qBittorrentPath()+"search_engine"+QDir::separator()+"nova2dl.py";
|
||||
if(misc::getPluginVersion(":/search_engine/nova2dl.py") > misc::getPluginVersion(filePath)) {
|
||||
if(QFile::exists(filePath)){
|
||||
QFile::remove(filePath);
|
||||
}
|
||||
|
@ -409,7 +408,7 @@ void SearchEngine::updateNova() {
|
|||
}
|
||||
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();
|
||||
QDir shipped_subDir(":/search_engine/engines/");
|
||||
QStringList files = shipped_subDir.entryList();
|
||||
|
@ -462,6 +461,9 @@ void SearchEngine::searchFinished(int exitcode,QProcess::ExitStatus){
|
|||
if(currentSearchTab)
|
||||
currentSearchTab->getCurrentLabel()->setText(tr("Results", "i.e: Search results")+QString::fromUtf8(" <i>(")+misc::toQString(nb_search_results)+QString::fromUtf8(")</i>:"));
|
||||
search_button->setText("Search");
|
||||
if(searchTimeout->isActive()) {
|
||||
searchTimeout->stop();
|
||||
}
|
||||
}
|
||||
|
||||
// SLOT to append one line to search results list
|
||||
|
@ -491,34 +493,26 @@ void SearchEngine::appendSearchResult(QString line){
|
|||
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
|
||||
void SearchEngine::closeTab_button_clicked(){
|
||||
if(all_tab.size()) {
|
||||
qDebug("currentTab rank: %d", tabWidget->currentIndex());
|
||||
qDebug("currentSearchTab rank: %d", tabWidget->indexOf(currentSearchTab));
|
||||
if(tabWidget->currentIndex() == tabWidget->indexOf(currentSearchTab)) {
|
||||
qDebug("Deleted current search Tab");
|
||||
if(searchProcess->state() != QProcess::NotRunning){
|
||||
searchProcess->terminate();
|
||||
}
|
||||
if(searchTimeout->isActive()) {
|
||||
searchTimeout->stop();
|
||||
}
|
||||
search_stopped = true;
|
||||
currentSearchTab = 0;
|
||||
qDebug("Deleted current search Tab");
|
||||
if(searchProcess->state() != QProcess::NotRunning){
|
||||
searchProcess->terminate();
|
||||
}
|
||||
if(searchTimeout->isActive()) {
|
||||
searchTimeout->stop();
|
||||
}
|
||||
search_stopped = true;
|
||||
currentSearchTab = 0;
|
||||
}
|
||||
delete all_tab.takeAt(tabWidget->currentIndex());
|
||||
if(!all_tab.size()) {
|
||||
closeTab_button->setEnabled(false);
|
||||
download_button->setEnabled(false);
|
||||
closeTab_button->setEnabled(false);
|
||||
download_button->setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -532,7 +526,7 @@ void SearchEngine::on_download_button_clicked(){
|
|||
// Get Item url
|
||||
QStandardItemModel *model = all_tab.at(tabWidget->currentIndex())->getCurrentSearchListModel();
|
||||
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);
|
||||
all_tab.at(tabWidget->currentIndex())->setRowColor(index.row(), "red");
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "ui_search.h"
|
||||
#include "engineSelectDlg.h"
|
||||
#include "SearchTab.h"
|
||||
#include "supportedEngines.h"
|
||||
|
||||
class bittorrent;
|
||||
class QSystemTrayIcon;
|
||||
|
@ -50,52 +51,55 @@ class SearchEngine;
|
|||
class SearchEngine : public QWidget, public Ui::search_engine{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
// Search related
|
||||
QProcess *searchProcess;
|
||||
QList<QProcess*> downloaders;
|
||||
bool search_stopped;
|
||||
bool no_search_results;
|
||||
QByteArray search_result_line_truncated;
|
||||
unsigned long nb_search_results;
|
||||
QPointer<QCompleter> searchCompleter;
|
||||
QStringList searchHistory;
|
||||
bittorrent *BTSession;
|
||||
QSystemTrayIcon *myTrayIcon;
|
||||
bool systrayIntegration;
|
||||
QStringList enabled_engines;
|
||||
QTimer *searchTimeout;
|
||||
SearchTab *currentSearchTab;
|
||||
QPushButton *closeTab_button;
|
||||
QList<SearchTab*> all_tab; // To store all tabs
|
||||
public:
|
||||
SearchEngine(bittorrent *BTSession, QSystemTrayIcon *myTrayIcon, bool systrayIntegration);
|
||||
~SearchEngine();
|
||||
float getPluginVersion(QString filePath) const;
|
||||
public slots:
|
||||
void on_download_button_clicked();
|
||||
void downloadSelectedItem(const QModelIndex& index);
|
||||
protected slots:
|
||||
// Search slots
|
||||
void tab_changed(int);//to prevent the use of the download button when the tab is empty
|
||||
void on_search_button_clicked();
|
||||
void on_stop_search_button_clicked();
|
||||
void closeTab_button_clicked();
|
||||
void appendSearchResult(QString line);
|
||||
void searchFinished(int exitcode,QProcess::ExitStatus);
|
||||
void readSearchOutput();
|
||||
void loadEngineSettings();
|
||||
void searchStarted();
|
||||
void startSearchHistory();
|
||||
void updateNova();
|
||||
void saveSearchHistory();
|
||||
void on_enginesButton_clicked();
|
||||
void propagateSectionResized(int index, int oldsize , int newsize);
|
||||
void saveResultsColumnsWidth();
|
||||
void downloadFinished(int exitcode, QProcess::ExitStatus);
|
||||
void downloadTorrent(QString engine_url, QString torrent_url);
|
||||
void displayPatternContextMenu(QPoint);
|
||||
void createCompleter();
|
||||
private:
|
||||
// Search related
|
||||
QProcess *searchProcess;
|
||||
QList<QProcess*> downloaders;
|
||||
bool search_stopped;
|
||||
bool no_search_results;
|
||||
QByteArray search_result_line_truncated;
|
||||
unsigned long nb_search_results;
|
||||
QPointer<QCompleter> searchCompleter;
|
||||
QStringList searchHistory;
|
||||
bittorrent *BTSession;
|
||||
QSystemTrayIcon *myTrayIcon;
|
||||
bool systrayIntegration;
|
||||
SupportedEngines *supported_engines;
|
||||
QTimer *searchTimeout;
|
||||
SearchTab *currentSearchTab;
|
||||
QPushButton *closeTab_button;
|
||||
QList<SearchTab*> all_tab; // To store all tabs
|
||||
const SearchCategories full_cat_names;
|
||||
public:
|
||||
SearchEngine(bittorrent *BTSession, QSystemTrayIcon *myTrayIcon, bool systrayIntegration);
|
||||
~SearchEngine();
|
||||
float getPluginVersion(QString filePath) const;
|
||||
QString selectedCategory() const;
|
||||
|
||||
public slots:
|
||||
void on_download_button_clicked();
|
||||
void downloadSelectedItem(const QModelIndex& index);
|
||||
|
||||
protected slots:
|
||||
// Search slots
|
||||
void tab_changed(int);//to prevent the use of the download button when the tab is empty
|
||||
void on_search_button_clicked();
|
||||
void closeTab_button_clicked();
|
||||
void appendSearchResult(QString line);
|
||||
void searchFinished(int exitcode,QProcess::ExitStatus);
|
||||
void readSearchOutput();
|
||||
void searchStarted();
|
||||
void startSearchHistory();
|
||||
void updateNova();
|
||||
void saveSearchHistory();
|
||||
void on_enginesButton_clicked();
|
||||
void propagateSectionResized(int index, int oldsize , int newsize);
|
||||
void saveResultsColumnsWidth();
|
||||
void downloadFinished(int exitcode, QProcess::ExitStatus);
|
||||
void downloadTorrent(QString engine_url, QString torrent_url);
|
||||
void displayPatternContextMenu(QPoint);
|
||||
void createCompleter();
|
||||
void fillCatCombobox();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#VERSION: 1.23
|
||||
#VERSION: 1.31
|
||||
#AUTHORS: Fabien Devaux (fab@gnux.info)
|
||||
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
|
@ -31,14 +31,15 @@ from xml.dom import minidom
|
|||
import re
|
||||
|
||||
class mininova(object):
|
||||
# Mandatory properties
|
||||
url = 'http://www.mininova.org'
|
||||
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):
|
||||
print download_file(info)
|
||||
|
||||
def search(self, what):
|
||||
def search(self, what, cat='all'):
|
||||
|
||||
def get_link(lnk):
|
||||
lnks = lnk.getElementsByTagName('a')
|
||||
|
@ -71,10 +72,15 @@ class mininova(object):
|
|||
return txt.toxml()
|
||||
else:
|
||||
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
|
||||
while True and page<11:
|
||||
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("<=", "<=", dat)
|
||||
dat = re.sub("&\s", "& ", dat)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
isohunt: 1.21
|
||||
torrentreactor: 1.11
|
||||
btjunkie: 2.11
|
||||
mininova: 1.23
|
||||
mininova: 1.31
|
||||
piratebay: 1.11
|
||||
|
|
|
@ -64,15 +64,15 @@ def retrieve_url(url):
|
|||
return dat.encode('utf-8', 'replace')
|
||||
|
||||
def download_file(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 = os.fdopen(file, "wb")
|
||||
# Download url
|
||||
req = urllib2.Request(url)
|
||||
response = urllib2.urlopen(req)
|
||||
dat = response.read()
|
||||
# Write it to a file
|
||||
file.write(dat)
|
||||
file.close()
|
||||
# return file path
|
||||
return path+" "+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 = os.fdopen(file, "wb")
|
||||
# Download url
|
||||
req = urllib2.Request(url)
|
||||
response = urllib2.urlopen(req)
|
||||
dat = response.read()
|
||||
# Write it to a file
|
||||
file.write(dat)
|
||||
file.close()
|
||||
# return file path
|
||||
return path+" "+url
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
#VERSION: 1.10
|
||||
#VERSION: 1.23
|
||||
|
||||
# Author:
|
||||
# Fabien Devaux <fab AT gnux DOT info>
|
||||
|
@ -43,6 +43,7 @@ import os
|
|||
import glob
|
||||
|
||||
THREADED = True
|
||||
CATEGORIES = ('all', 'movies', 'tv', 'music', 'games', 'anime', 'software', 'pictures', 'books')
|
||||
|
||||
################################################################################
|
||||
# Every engine should have a "search" method taking
|
||||
|
@ -65,48 +66,90 @@ for engine in engines:
|
|||
except:
|
||||
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):
|
||||
def __init__(self, engine, what):
|
||||
def __init__(self, engine, what, cat='all'):
|
||||
threading.Thread.__init__(self)
|
||||
self.engine = engine
|
||||
self.what = what
|
||||
self.cat = cat
|
||||
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 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)))
|
||||
|
||||
if len(sys.argv) == 2:
|
||||
if sys.argv[1] == "--supported_engines":
|
||||
print ','.join(supported_engines)
|
||||
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)
|
||||
if sys.argv[1] == "--capabilities":
|
||||
displayCapabilities()
|
||||
sys.exit(0)
|
||||
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)))
|
||||
|
||||
engines_list = [e.lower() for e in sys.argv[1].strip().split(',')]
|
||||
|
||||
if 'all' in engines_list:
|
||||
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 = []
|
||||
for engine in engines_list:
|
||||
try:
|
||||
if THREADED:
|
||||
exec "l = EngineLauncher(%s(), what)" % engine
|
||||
exec "l = EngineLauncher(%s(), what, cat)"%engine
|
||||
threads.append(l)
|
||||
l.start()
|
||||
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:
|
||||
pass
|
||||
if THREADED:
|
||||
|
|
|
@ -118,7 +118,7 @@
|
|||
<action name="actionBuy_it">
|
||||
<property name="icon">
|
||||
<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 name="text">
|
||||
<string>Buy it</string>
|
||||
|
|
|
@ -185,7 +185,8 @@ HEADERS += GUI.h \
|
|||
stacktrace.h \
|
||||
torrentPersistentData.h \
|
||||
FeedDownloader.h \
|
||||
feedList.h
|
||||
feedList.h \
|
||||
supportedEngines.h
|
||||
FORMS += MainWindow.ui \
|
||||
options.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