Browse Source

- Torrent downloading is now handled by search engine plugins to allow for more flexibility

adaptive-webui-19844
Christophe Dumez 16 years ago
parent
commit
c2244f746e
  1. 16
      src/GUI.cpp
  2. 3
      src/GUI.h
  3. 1
      src/SearchTab.h
  4. 1
      src/bittorrent.cpp
  5. 2
      src/bittorrent.h
  6. 1
      src/search.qrc
  7. 54
      src/searchEngine.cpp
  8. 4
      src/searchEngine.h
  9. 9
      src/search_engine/engines/btjunkie.py
  10. 7
      src/search_engine/engines/isohunt.py
  11. 7
      src/search_engine/engines/mininova.py
  12. 7
      src/search_engine/engines/piratebay.py
  13. 7
      src/search_engine/engines/torrentreactor.py
  14. 10
      src/search_engine/engines/versions.txt
  15. 16
      src/search_engine/helpers.py
  16. 2
      src/search_engine/nova2.py
  17. 60
      src/search_engine/nova2dl.py

16
src/GUI.cpp

@ -139,7 +139,7 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), dis @@ -139,7 +139,7 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), dis
downloadingTorrentTab = new DownloadingTorrents(this, BTSession);
tabs->addTab(downloadingTorrentTab, tr("Downloads") + QString::fromUtf8(" (0/0)"));
tabs->setTabIcon(0, QIcon(QString::fromUtf8(":/Icons/skin/downloading.png")));
vboxLayout->addWidget(tabs);
propertiesSplitter->insertWidget(0, tabs);
connect(downloadingTorrentTab, SIGNAL(unfinishedTorrentsNumberChanged(unsigned int)), this, SLOT(updateUnfinishedTorrentNumber(unsigned int)));
connect(downloadingTorrentTab, SIGNAL(torrentDoubleClicked(QString, bool)), this, SLOT(torrentDoubleClicked(QString, bool)));
// Finished torrents tab
@ -237,6 +237,10 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), dis @@ -237,6 +237,10 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), dis
QMainWindow::statusBar()->addPermanentWidget(upSpeedLbl);
QMainWindow::statusBar()->addPermanentWidget(statusSep4);
QMainWindow::statusBar()->addPermanentWidget(ratioLbl);
// Properties code
propertiesSplitter->handle(1)->setVisible(false);
stackedProperties->setVisible(false);
// Display window if necessary
if(!settings.value(QString::fromUtf8("Preferences/General/StartMinimized"), false).toBool()) {
show();
}
@ -294,6 +298,16 @@ GUI::~GUI() { @@ -294,6 +298,16 @@ GUI::~GUI() {
qDebug("5");
}
void GUI::on_prop_infos_button_clicked() {
if(stackedProperties->isVisible()) {
propertiesSplitter->handle(1)->setVisible(false);
stackedProperties->setVisible(false);
} else {
stackedProperties->setVisible(true);
propertiesSplitter->handle(1)->setVisible(true);
}
}
void GUI::displayRSSTab(bool enable) {
if(enable) {
// RSS tab

3
src/GUI.h

@ -173,7 +173,8 @@ class GUI : public QMainWindow, private Ui::MainWindow{ @@ -173,7 +173,8 @@ class GUI : public QMainWindow, private Ui::MainWindow{
void OptionsSaved(bool deleteOptions);
// HTTP slots
void on_actionDownload_from_URL_triggered();
// Properties
void on_prop_infos_button_clicked();
public slots:
void trackerAuthenticationRequired(QTorrentHandle& h);

1
src/SearchTab.h

@ -24,6 +24,7 @@ @@ -24,6 +24,7 @@
#include "ui_search.h"
#define ENGINE_URL_COLUMN 4
#define URL_COLUMN 5
class SearchListDelegate;

1
src/bittorrent.cpp

@ -910,6 +910,7 @@ void bittorrent::setDefaultTempPath(QString temppath) { @@ -910,6 +910,7 @@ void bittorrent::setDefaultTempPath(QString temppath) {
for(torrentIT = torrents.begin(); torrentIT != torrents.end(); torrentIT++) {
QTorrentHandle h = QTorrentHandle(*torrentIT);
if(!h.is_valid()) continue;
std::cout << "Moving storage for " << h.hash().toUtf8().data() << ", from " << h.save_path().toUtf8().data() << " to " << getSavePath(h.hash()).toUtf8().data() << std::endl;
h.move_storage(getSavePath(h.hash()));
}
} else {

2
src/bittorrent.h

@ -154,11 +154,11 @@ class bittorrent : public QObject { @@ -154,11 +154,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();

1
src/search.qrc

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>search_engine/nova2.py</file>
<file>search_engine/nova2dl.py</file>
<file>search_engine/novaprinter.py</file>
<file>search_engine/helpers.py</file>
<file>search_engine/engines/btjunkie.png</file>

54
src/searchEngine.cpp

@ -78,6 +78,11 @@ SearchEngine::~SearchEngine(){ @@ -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;
@ -225,6 +230,18 @@ void SearchEngine::saveResultsColumnsWidth() { @@ -225,6 +230,18 @@ 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);
}
void SearchEngine::searchStarted(){
// Update SearchEngine widgets
search_status->setText(tr("Searching..."));
@ -242,9 +259,10 @@ void SearchEngine::downloadSelectedItem(const QModelIndex& index){ @@ -242,9 +259,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");
}
@ -267,6 +285,22 @@ void SearchEngine::readSearchOutput(){ @@ -267,6 +285,22 @@ void SearchEngine::readSearchOutput(){
currentSearchTab->getCurrentLabel()->setText(tr("Results")+QString::fromUtf8(" <i>(")+misc::toQString(nb_search_results)+QString::fromUtf8(")</i>:"));
}
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");
@ -294,6 +328,14 @@ void SearchEngine::updateNova() { @@ -294,6 +328,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)){
@ -301,7 +343,7 @@ void SearchEngine::updateNova() { @@ -301,7 +343,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)){
@ -309,6 +351,7 @@ void SearchEngine::updateNova() { @@ -309,6 +351,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();
@ -436,8 +479,9 @@ void SearchEngine::on_download_button_clicked(){ @@ -436,8 +479,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");
}
}

4
src/searchEngine.h

@ -26,6 +26,7 @@ @@ -26,6 +26,7 @@
#include <QProcess>
#include <QList>
#include <QPair>
#include "ui_search.h"
#include "engineSelectDlg.h"
#include "SearchTab.h"
@ -42,6 +43,7 @@ class SearchEngine : public QWidget, public Ui::search_engine{ @@ -42,6 +43,7 @@ class SearchEngine : public QWidget, public Ui::search_engine{
private:
// Search related
QProcess *searchProcess;
QList<QProcess*> downloaders;
bool search_stopped;
bool no_search_results;
QByteArray search_result_line_truncated;
@ -81,6 +83,8 @@ class SearchEngine : public QWidget, public Ui::search_engine{ @@ -81,6 +83,8 @@ class SearchEngine : public QWidget, public Ui::search_engine{
void on_clearPatternButton_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);
};
#endif

9
src/search_engine/engines/btjunkie.py

@ -1,4 +1,4 @@ @@ -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 @@ @@ -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): @@ -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)

7
src/search_engine/engines/isohunt.py

@ -1,4 +1,4 @@ @@ -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 @@ @@ -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:

7
src/search_engine/engines/mininova.py

@ -1,4 +1,4 @@ @@ -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 @@ @@ -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): @@ -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):

7
src/search_engine/engines/piratebay.py

@ -1,4 +1,4 @@ @@ -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 @@ @@ -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): @@ -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):

7
src/search_engine/engines/torrentreactor.py

@ -1,4 +1,4 @@ @@ -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 @@ @@ -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)

10
src/search_engine/engines/versions.txt

@ -1,5 +1,5 @@ @@ -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

16
src/search_engine/helpers.py

@ -26,6 +26,8 @@ @@ -26,6 +26,8 @@
import re, htmlentitydefs
import urllib2
import tempfile
import os
def htmlentitydecode(s):
# First convert alpha entities (such as &eacute;)
@ -57,3 +59,17 @@ def retrieve_url(url): @@ -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

2
src/search_engine/nova2.py

@ -75,7 +75,7 @@ class EngineLauncher(threading.Thread): @@ -75,7 +75,7 @@ class EngineLauncher(threading.Thread):
if __name__ == '__main__':
if len(sys.argv) < 2:
raise SystemExit('./nova.py [all|engine1[,engine2]*] <keywords>\navailable engines: %s'%
raise SystemExit('./nova2.py [all|engine1[,engine2]*] <keywords>\navailable engines: %s'%
(','.join(supported_engines)))
if len(sys.argv) == 2:

60
src/search_engine/nova2dl.py

@ -0,0 +1,60 @@ @@ -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)
Loading…
Cancel
Save