diff --git a/src/SearchTab.h b/src/SearchTab.h index adf46ed4e..f19774ade 100644 --- a/src/SearchTab.h +++ b/src/SearchTab.h @@ -24,6 +24,7 @@ #include "ui_search.h" +#define ENGINE_URL_COLUMN 4 #define URL_COLUMN 5 class SearchListDelegate; diff --git a/src/bittorrent.h b/src/bittorrent.h index a03f92571..66cd895f9 100644 --- a/src/bittorrent.h +++ b/src/bittorrent.h @@ -152,11 +152,11 @@ class bittorrent : public QObject { bool enableDHT(bool b); void addConsoleMessage(QString msg, QColor color=QApplication::palette().color(QPalette::WindowText)); void addPeerBanMessage(QString msg, bool from_ipfilter); + void processDownloadedFile(QString, QString); protected slots: void scanDirectory(QString); void readAlerts(); - void processDownloadedFile(QString, QString); bool loadTrackerFile(QString hash); void saveTrackerFile(QString hash); void deleteBigRatios(); diff --git a/src/search.qrc b/src/search.qrc index 735122372..b7c46c86e 100644 --- a/src/search.qrc +++ b/src/search.qrc @@ -1,6 +1,7 @@ search_engine/nova2.py + search_engine/nova2dl.py search_engine/novaprinter.py search_engine/helpers.py search_engine/engines/btjunkie.png diff --git a/src/searchEngine.cpp b/src/searchEngine.cpp index d0267957f..2dba721e8 100644 --- a/src/searchEngine.cpp +++ b/src/searchEngine.cpp @@ -78,6 +78,11 @@ SearchEngine::~SearchEngine(){ saveSearchHistory(); searchProcess->kill(); searchProcess->waitForFinished(); + foreach(QProcess *downloader, downloaders) { + downloader->kill(); + downloader->waitForFinished(); + delete downloader; + } delete searchTimeout; delete searchProcess; delete searchCompleter; @@ -188,6 +193,18 @@ void SearchEngine::on_search_button_clicked(){ searchTimeout->start(180000); // 3min } +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); +} + void SearchEngine::searchStarted(){ // Update SearchEngine widgets search_status->setText(tr("Searching...")); @@ -205,9 +222,10 @@ void SearchEngine::downloadSelectedItem(const QModelIndex& index){ int row = index.row(); // Get Item url QStandardItemModel *model = all_tab.at(tabWidget->currentIndex())->getCurrentSearchListModel(); - QString url = model->data(model->index(index.row(), 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 - BTSession->downloadFromUrl(url); + downloadTorrent(engine_url, torrent_url); // Set item color to RED all_tab.at(tabWidget->currentIndex())->setRowColor(row, "red"); } @@ -230,6 +248,22 @@ void SearchEngine::readSearchOutput(){ currentSearchTab->getCurrentLabel()->setText(tr("Results")+QString::fromUtf8(" (")+misc::toQString(nb_search_results)+QString::fromUtf8("):")); } +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.length() == 2) { + QString path = parts[0]; + QString url = parts[1]; + BTSession->processDownloadedFile(url, path); + } + } + qDebug("Deleting downloadProcess"); + downloaders.removeOne(downloadProcess); + delete downloadProcess; +} + // Update nova.py search plugin if necessary void SearchEngine::updateNova() { qDebug("Updating nova"); @@ -257,6 +291,14 @@ void SearchEngine::updateNova() { // Set permissions 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)) { + if(QFile::exists(filePath)){ + QFile::remove(filePath); + } + QFile::copy(":/search_engine/nova2dl.py", filePath); + } + QFile(misc::qBittorrentPath()+"search_engine"+QDir::separator()+"nova2dl.py").setPermissions(perm); filePath = misc::qBittorrentPath()+"search_engine"+QDir::separator()+"novaprinter.py"; if(misc::getPluginVersion(":/search_engine/novaprinter.py") > misc::getPluginVersion(filePath)) { if(QFile::exists(filePath)){ @@ -264,7 +306,7 @@ void SearchEngine::updateNova() { } QFile::copy(":/search_engine/novaprinter.py", filePath); } - QFile(misc::qBittorrentPath()+"search_engine"+QDir::separator()+"helpers.py").setPermissions(perm); + QFile(misc::qBittorrentPath()+"search_engine"+QDir::separator()+"novaprinter.py").setPermissions(perm); filePath = misc::qBittorrentPath()+"search_engine"+QDir::separator()+"helpers.py"; if(misc::getPluginVersion(":/search_engine/helpers.py") > misc::getPluginVersion(filePath)) { if(QFile::exists(filePath)){ @@ -272,6 +314,7 @@ void SearchEngine::updateNova() { } QFile::copy(":/search_engine/helpers.py", filePath); } + 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(); @@ -399,8 +442,9 @@ void SearchEngine::on_download_button_clicked(){ if(index.column() == NAME){ // Get Item url QStandardItemModel *model = all_tab.at(tabWidget->currentIndex())->getCurrentSearchListModel(); - QString url = model->data(model->index(index.row(), URL_COLUMN)).toString(); - BTSession->downloadFromUrl(url); + 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(); + downloadTorrent(engine_url, torrent_url); all_tab.at(tabWidget->currentIndex())->setRowColor(index.row(), "red"); } } diff --git a/src/searchEngine.h b/src/searchEngine.h index 5322f4e21..180a2e145 100644 --- a/src/searchEngine.h +++ b/src/searchEngine.h @@ -26,6 +26,7 @@ #include #include +#include #include "ui_search.h" #include "engineSelectDlg.h" #include "SearchTab.h" @@ -42,6 +43,7 @@ class SearchEngine : public QWidget, public Ui::search_engine{ private: // Search related QProcess *searchProcess; + QList downloaders; bool search_stopped; bool no_search_results; QByteArray search_result_line_truncated; @@ -79,6 +81,8 @@ class SearchEngine : public QWidget, public Ui::search_engine{ void saveSearchHistory(); void on_enginesButton_clicked(); void on_clearPatternButton_clicked(); + void downloadFinished(int exitcode, QProcess::ExitStatus); + void downloadTorrent(QString engine_url, QString torrent_url); }; #endif diff --git a/src/search_engine/engines/btjunkie.py b/src/search_engine/engines/btjunkie.py index 57d663509..ffa820771 100644 --- a/src/search_engine/engines/btjunkie.py +++ b/src/search_engine/engines/btjunkie.py @@ -1,4 +1,4 @@ -#VERSION: 2.1 +#VERSION: 2.11 #AUTHORS: Christophe Dumez (chris@qbittorrent.org) # Redistribution and use in source and binary forms, with or without @@ -27,7 +27,7 @@ from novaprinter import prettyPrinter -from helpers import retrieve_url +from helpers import retrieve_url, download_file import sgmllib import re @@ -38,7 +38,10 @@ class btjunkie(object): def __init__(self): self.results = [] self.parser = self.SimpleSGMLParser(self.results, self.url) - + + def download_torrent(self, info): + print download_file(info) + class SimpleSGMLParser(sgmllib.SGMLParser): def __init__(self, results, url, *args): sgmllib.SGMLParser.__init__(self) diff --git a/src/search_engine/engines/isohunt.py b/src/search_engine/engines/isohunt.py index 90da20406..e8edc2db8 100644 --- a/src/search_engine/engines/isohunt.py +++ b/src/search_engine/engines/isohunt.py @@ -1,4 +1,4 @@ -#VERSION: 1.2 +#VERSION: 1.21 #AUTHORS: Christophe Dumez (chris@qbittorrent.org) # Redistribution and use in source and binary forms, with or without @@ -27,12 +27,15 @@ from novaprinter import prettyPrinter import re -from helpers import retrieve_url +from helpers import retrieve_url, download_file class isohunt(object): url = 'http://isohunt.com' name = 'isoHunt' + def download_torrent(self, info): + print download_file(info) + def search(self, what): i = 1 while True and i<11: diff --git a/src/search_engine/engines/mininova.py b/src/search_engine/engines/mininova.py index 7f19b559a..c519149af 100644 --- a/src/search_engine/engines/mininova.py +++ b/src/search_engine/engines/mininova.py @@ -1,4 +1,4 @@ -#VERSION: 1.21 +#VERSION: 1.22 #AUTHORS: Fabien Devaux (fab@gnux.info) # Redistribution and use in source and binary forms, with or without @@ -26,7 +26,7 @@ # POSSIBILITY OF SUCH DAMAGE. from novaprinter import prettyPrinter -from helpers import retrieve_url +from helpers import retrieve_url, download_file from xml.dom import minidom import re @@ -34,6 +34,9 @@ class mininova(object): url = 'http://www.mininova.org' name = 'Mininova' table_items = 'added cat name size seeds leech'.split() + + def download_torrent(self, info): + print download_file(info) def search(self, what): diff --git a/src/search_engine/engines/piratebay.py b/src/search_engine/engines/piratebay.py index a87f46ea8..baa47a02c 100644 --- a/src/search_engine/engines/piratebay.py +++ b/src/search_engine/engines/piratebay.py @@ -1,4 +1,4 @@ -#VERSION: 1.1 +#VERSION: 1.11 #AUTHORS: Fabien Devaux (fab@gnux.info) # Redistribution and use in source and binary forms, with or without @@ -27,7 +27,7 @@ from novaprinter import prettyPrinter import sgmllib -from helpers import retrieve_url +from helpers import retrieve_url, download_file class piratebay(object): url = 'http://thepiratebay.org' @@ -36,6 +36,9 @@ class piratebay(object): def __init__(self): self.results = [] self.parser = self.SimpleSGMLParser(self.results, self.url) + + def download_torrent(self, info): + print download_file(info) class SimpleSGMLParser(sgmllib.SGMLParser): def __init__(self, results, url, *args): diff --git a/src/search_engine/engines/torrentreactor.py b/src/search_engine/engines/torrentreactor.py index 9593d3ecf..c6d01cfec 100644 --- a/src/search_engine/engines/torrentreactor.py +++ b/src/search_engine/engines/torrentreactor.py @@ -1,4 +1,4 @@ -#VERSION: 1.1 +#VERSION: 1.11 #AUTHORS: Gekko Dam Beer (gekko04@users.sourceforge.net) # Redistribution and use in source and binary forms, with or without @@ -27,12 +27,15 @@ from novaprinter import prettyPrinter import sgmllib -from helpers import retrieve_url +from helpers import retrieve_url, download_file class torrentreactor(object): url = 'http://www.torrentreactor.net' name = 'TorrentReactor.Net' + def download_torrent(self, info): + print download_file(info) + class SimpleSGMLParser(sgmllib.SGMLParser): def __init__(self, results, url, *args): sgmllib.SGMLParser.__init__(self) diff --git a/src/search_engine/engines/versions.txt b/src/search_engine/engines/versions.txt index 4b6b8d8c3..e189f2413 100644 --- a/src/search_engine/engines/versions.txt +++ b/src/search_engine/engines/versions.txt @@ -1,5 +1,5 @@ -isohunt: 1.2 -torrentreactor: 1.1 -btjunkie: 2.1 -mininova: 1.21 -piratebay: 1.1 +isohunt: 1.21 +torrentreactor: 1.11 +btjunkie: 2.11 +mininova: 1.22 +piratebay: 1.11 diff --git a/src/search_engine/helpers.py b/src/search_engine/helpers.py index b64d4d697..1a01cf522 100644 --- a/src/search_engine/helpers.py +++ b/src/search_engine/helpers.py @@ -26,6 +26,8 @@ import re, htmlentitydefs import urllib2 +import tempfile +import os def htmlentitydecode(s): # First convert alpha entities (such as é) @@ -57,3 +59,17 @@ def retrieve_url(url): dat = dat.decode(charset, 'replace') dat = htmlentitydecode(dat) 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(url) + dat = response.read() + # Write it to a file + file.write(dat) + file.close() + # return file path + return path+" "+url diff --git a/src/search_engine/nova2.py b/src/search_engine/nova2.py index ad74f5ed2..401b1f0d6 100755 --- a/src/search_engine/nova2.py +++ b/src/search_engine/nova2.py @@ -75,7 +75,7 @@ class EngineLauncher(threading.Thread): if __name__ == '__main__': if len(sys.argv) < 2: - raise SystemExit('./nova.py [all|engine1[,engine2]*] \navailable engines: %s'% + raise SystemExit('./nova2.py [all|engine1[,engine2]*] \navailable engines: %s'% (','.join(supported_engines))) if len(sys.argv) == 2: diff --git a/src/search_engine/nova2dl.py b/src/search_engine/nova2dl.py new file mode 100755 index 000000000..4f505b2dd --- /dev/null +++ b/src/search_engine/nova2dl.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +#VERSION: 1.00 + +# Author: +# Christophe DUMEZ (chris@qbittorrent.org) + +import sys +import os +import glob + +supported_engines = dict() + +engines = glob.glob(os.path.join(os.path.dirname(__file__), 'engines','*.py')) +for engine in engines: + e = engine.split(os.sep)[-1][:-3] + if len(e.strip()) == 0: continue + if e.startswith('_'): continue + try: + exec "from engines.%s import %s"%(e,e) + exec "engine_url = %s.url"%e + supported_engines[engine_url] = e + except: + pass + +if __name__ == '__main__': + if len(sys.argv) < 3: + raise SystemExit('./nova2dl.py engine_url download_parameter') + engine_url = sys.argv[1].strip() + download_param = sys.argv[2].strip() + if engine_url not in supported_engines.keys(): + raise SystemExit('./nova2dl.py: this engine_url was not recognized') + exec "engine = %s()"%supported_engines[engine_url] + engine.download_torrent(download_param) + sys.exit(0) \ No newline at end of file