1
mirror of https://github.com/qbittorrent/qBittorrent synced 2025-10-21 13:52:16 +02:00

Compare commits

...

24 Commits

Author SHA1 Message Date
sledgehammer999
99a596ab8d Bump to 3.1.11 2014-10-22 22:32:25 +03:00
sledgehammer999
9a74b27a85 Update Changelog. 2014-10-22 22:28:00 +03:00
sledgehammer999
b12f250642 Use boost:bind() as the docs show. Allows compilation with older gcc versions.
Conflicts:
	src/torrentcreator/torrentcreatorthread.cpp
2014-10-22 22:02:08 +03:00
sledgehammer999
2dede108e7 Don't show multiple unlock UI dialogs. Closes #2040. 2014-10-22 22:00:41 +03:00
Ivan Sorokin
7cf1e7b8ca Optimize misc::naturalSort()
Previous implementation used QRegExp to find a first digit. That is
utterly ineffective.

When torrent list is sorted by name (a column that uses the naturalSort() for
comparison), naturalSort could take 18.6% of the time of the UI thread. Optimize it
so now it takes 1% of the time of the UI thread.
2014-10-22 22:00:27 +03:00
sledgehammer999
e1934e8c16 Use the correct character encoding for exceptions coming from libtorrent.
Conflicts:
	src/qtlibtorrent/qbtsession.cpp
2014-10-22 21:59:26 +03:00
Gabriele
14b958216b Increase maximum size of system icons
System icons were limited to a size 24x24 pixels, while the embedded
icons are 32x32 pixels big.
2014-10-22 21:56:58 +03:00
Gabriele
1120c14890 Make Windows icons suitable for high dpi screens
The maximum size of the icons is now 256x256 pixels so that
Windows can correctly scale them.

The 256x256 layer for the main icon was created upscaling the
192x192 png available in the source tree. Hence, the icon might
not be perfect at the maximum size.

The icon for the file association was made from scratch and it's
visually similar to the previous icon.
2014-10-22 21:56:44 +03:00
Gabriele
88075d9226 Allow relative torrent paths when qBittorrent is already running
Adding new torrents from the command line while qBittorrent was
already running was possible only providing the absolute path to
the file.
2014-10-22 21:56:29 +03:00
Gabriele
36464fcd59 Set minimum width of the left panel in the preferences
Change also the default width and set it to the minimum.
This minimum width prevents the horizontal scrollbar from appearing.

The size of the items in the list depends on the Qt style, so the
left panel could be few pixels larger than required with some of them.
2014-10-22 21:56:10 +03:00
Gabriele
f7f1c81238 Don't stretch the last section in the transfer list
Since the content of some sections is right aligned, automatically
resizing the width of the last one to fill the header could be
sometimes undesired.

Let the user choose the width of each section and never change his
preference.
2014-10-22 21:55:56 +03:00
Bruno Barbieri
b8da4bcf74 Fix search inconsistency between Python versions
Closes #2012
2014-10-22 21:55:41 +03:00
Gabriele
bf7a6aceb0 Remove unneeded tooltip 2014-10-22 21:55:24 +03:00
DoumanAsh
3ef2da898b Pirate bay search engine update 2014-10-22 21:55:10 +03:00
Bruno Barbieri
d0cd939143 Fix search engine encoding issues with python3 on Windows
Closes #1996
2014-10-22 21:54:50 +03:00
Bruno Barbieri
e36d76d457 Replace deprecated sgmllib with HTMLParser/html.parser 2014-10-22 21:54:38 +03:00
Bruno Barbieri
daa4314093 Fix TorrentReactor search plugin 2014-10-22 21:54:25 +03:00
sledgehammer999
f707d6c9d5 Merge pull request #2052 from pmzqla/v3_1_x-charset
WebUI: Set correct HTTP Content-Type in case of forbidden access
2014-10-19 17:27:20 +03:00
Gabriele
83b6619b16 WebUI: Set correct HTTP Content-Type in case of forbidden access
The error message is an utf-8 string. With no charset specified,
web browsers will likely use the wrong one making reading the message
in some languages impossibile.
2014-10-19 16:13:18 +02:00
sledgehammer999
8b322648c8 Change the program updater's URL for Windows and Mac OS X. Closes #1954.
Conflicts:
	src/programupdater.cpp
2014-10-12 16:43:27 +03:00
sledgehammer999
d159117965 WINDOWS: Fix magnet link association. Closes #1952. 2014-10-12 15:59:39 +03:00
sledgehammer999
1fd2dce0bd Fix Mac OS X compilation. 2014-10-06 02:36:03 +03:00
Ivan Sorokin
f97238e1c9 Fix heap-buffer-overrun in PropertiesWidget::displayFilesListMenu 2014-10-04 21:39:47 +03:00
paolo-sz
67355810ae Correctly detect python in PATH 2014-10-04 21:39:26 +03:00
33 changed files with 370 additions and 258 deletions

View File

@@ -1,3 +1,25 @@
* Wed Oct 22 2014 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.1.11
- FEATURE: Allow relative torrent paths when qBittorrent is already running (pmzqla)
- FEATURE: Make Windows icons suitable for high dpi screens (pmzqla)
- FEATURE: Increase maximum size of system icons (pmzqla)
- BUGFIX: Fix crash in the "Content" widget when user would right click in it without a torrent selected (Ivan Sorokin)
- BUGFIX: Don't show multiple unlock UI dialogs. Closes #2040. (sledgehammer999)
- SEARCH: Fix bug where python would falsely be detected and nothing worked (paolo-sz)
- SEARCH: Fix TorrentReactor search plugin (Bruno Barbieri)
- SEARCH: Fix search engine encoding issues with python3 on Windows (Bruno Barbieri)
- SEARCH: Pirate bay search engine update (DoumanAsh)
- SEARCH: Internal improvements in the python code (Bruno Barbieri)
- WINDOWS: Fix magnet link association. Closes #1952. (sledgehammer999)
- WINDOWS and OSX: Fix again the program updater. The url was changed by sourceforge.net. Closes #1954. (sledgehammer999)
- OSX: Fix compilation (sledgehammer999)
- WEBUI: Set correct HTTP Content-Type in case of forbidden access. (pmzqla)
- COSMETIC: Remove unneeded tooltip (pmzqla)
- COSMETIC: Don't stretch the last section in the transfer list (pmzqla)
- COSMETIC: Set minimum width of the left panel in the preferences (pmzqla)
- OTHER: Optimize sorting of rows. This should have less CPU impact when many torrents are present. (Ivan Sorokin)
- OTHER: Use the correct character encoding for exceptions coming from libtorrent. (sledgehammer999)
- OTHER: Use boost:bind() as the docs show. Allows compilation with older gcc versions. (sledgehammer999)
* Sun Sep 21 2014 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v3.1.10
- FEATURE: Allow disabling of OS cache. This will prevent RAM increases on Windows when seeding many files. Closes #1699. (sledgehammer999)
- FEATURE: Add 'Completed' column. Closes #1241. (sledgehammer999)

View File

@@ -197,7 +197,7 @@ bool AddNewTorrentDialog::loadTorrent(const QString& torrent_path, const QString
m_torrentInfo = new torrent_info(m_filePath.toUtf8().data());
m_hash = misc::toQString(m_torrentInfo->info_hash());
} catch(const std::exception& e) {
MessageBoxRaised::critical(0, tr("Invalid torrent"), tr("Failed to load the torrent: %1").arg(e.what()));
MessageBoxRaised::critical(0, tr("Invalid torrent"), tr("Failed to load the torrent: %1").arg(misc::toQStringU(e.what())));
return false;
}

View File

@@ -81,7 +81,7 @@ QIcon IconProvider::generateDifferentSizes(const QIcon& icon)
{
QIcon new_icon;
QList<QSize> required_sizes;
required_sizes << QSize(16, 16) << QSize(24, 24);
required_sizes << QSize(16, 16) << QSize(24, 24) << QSize(32, 32);
QList<QIcon::Mode> modes;
modes << QIcon::Normal << QIcon::Active << QIcon::Selected << QIcon::Disabled;
foreach (const QSize& size, required_sizes) {

View File

@@ -45,7 +45,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>3.1.10</string>
<string>3.1.11</string>
<key>CFBundleSignature</key>
<string>qBit</string>
<key>CFBundleExecutable</key>

View File

@@ -228,9 +228,14 @@ int main(int argc, char *argv[]) {
QStringList torrentCmdLine = app.arguments();
//Pass program parameters if any
QString message;
QFileInfo torrentPath;
for (int a = 1; a < torrentCmdLine.size(); ++a) {
if (torrentCmdLine[a].startsWith("--")) continue;
message += torrentCmdLine[a];
torrentPath.setFile(torrentCmdLine[a]);
if (torrentPath.exists())
message += torrentPath.absoluteFilePath();
else
message += torrentCmdLine[a];
if (a < argc-1)
message += "|";
}

10
src/mainwindow.cpp Normal file → Executable file
View File

@@ -101,7 +101,7 @@ using namespace libtorrent;
*****************************************************/
// Constructor
MainWindow::MainWindow(QWidget *parent, const QStringList& torrentCmdLine) : QMainWindow(parent), m_posInitialized(false), force_exit(false)
MainWindow::MainWindow(QWidget *parent, const QStringList& torrentCmdLine) : QMainWindow(parent), m_posInitialized(false), force_exit(false), unlockDlgShowing(false)
#ifdef Q_OS_WIN
, has_python(false)
#endif
@@ -697,8 +697,14 @@ void MainWindow::setTabText(int index, QString text) const {
}
bool MainWindow::unlockUI() {
if (unlockDlgShowing)
return false;
else
unlockDlgShowing = true;
bool ok = false;
QString clear_password = AutoExpandableDialog::getText(this, tr("UI lock password"), tr("Please type the UI lock password:"), QLineEdit::Password, "", &ok);
unlockDlgShowing = false;
if (!ok) return false;
Preferences pref;
QString real_pass_md5 = pref.getUILockPasswordMD5();
@@ -1343,7 +1349,7 @@ void MainWindow::on_actionSearch_engine_triggered() {
bool res = false;
// Check if python is already in PATH
if (misc::pythonVersion())
if (misc::pythonVersion() > 0)
res = true;
else
res = addPythonPathToEnv();

View File

@@ -183,6 +183,7 @@ private:
bool displaySpeedInTitle;
bool force_exit;
bool ui_locked;
bool unlockDlgShowing;
LineEdit *search_filter;
// Keyboard shortcuts
QShortcut *switchSearchShortcut;

View File

@@ -136,8 +136,8 @@ void misc::shutdownComputer(shutDownAction action) {
}
#endif
#ifdef Q_WS_MAC
AEEventID EventToSend;
if (action != SHUTDOWN_COMPUTER)
if (sleep)
EventToSend = kAESleep;
else
EventToSend = kAEShutDown;
@@ -556,15 +556,29 @@ QString misc::toQString(time_t t)
bool misc::naturalSort(QString left, QString right, bool &result) { // uses lessThan comparison
// Return value indicates if functions was successful
// result argument will contain actual comparison result if function was successful
int posL = 0;
int posR = 0;
do {
int posL = left.indexOf(QRegExp("[0-9]"));
int posR = right.indexOf(QRegExp("[0-9]"));
if (posL == -1 || posR == -1)
break; // No data
else if (posL != posR)
break; // Digit positions mismatch
else if (left.left(posL) != right.left(posR))
break; // Strings' subsets before digit do not match
for (;;) {
if (posL == left.size() || posR == right.size())
return false; // No data
QChar leftChar = left.at(posL);
QChar rightChar = right.at(posR);
bool leftCharIsDigit = leftChar.isDigit();
bool rightCharIsDigit = rightChar.isDigit();
if (leftCharIsDigit != rightCharIsDigit)
return false; // Digit positions mismatch
if (leftCharIsDigit)
break; // Both are digit, break this loop and compare numbers
if (leftChar != rightChar)
return false; // Strings' subsets before digit do not match
++posL;
++posR;
}
QString temp;
while (posL < left.size()) {
@@ -593,8 +607,6 @@ bool misc::naturalSort(QString left, QString right, bool &result) { // uses less
// Strings + digits do match and we haven't hit string end
// Do another round
left.remove(0, posL);
right.remove(0, posR);
} while (true);

View File

@@ -32,6 +32,12 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>116</width>
<height>0</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
@@ -78,9 +84,6 @@
<property name="text">
<string>Behavior</string>
</property>
<property name="toolTip">
<string>Behavior</string>
</property>
<property name="textAlignment">
<set>AlignHCenter|AlignVCenter|AlignCenter</set>
</property>

View File

@@ -310,8 +310,8 @@ void options_imp::loadWindowState() {
sizes << sizes_str.first().toInt();
sizes << sizes_str.last().toInt();
} else {
sizes << 130;
sizes << hsplitter->width()-130;
sizes << 116;
sizes << hsplitter->width()-116;
}
hsplitter->setSizes(sizes);
}

View File

@@ -1277,7 +1277,7 @@ public:
return false;
QString assoc_exe = exe_reg.cap(1);
qDebug("exe: %s", qPrintable(assoc_exe));
if (assoc_exe.compare(qApp->applicationFilePath(), Qt::CaseInsensitive) != 0)
if (assoc_exe.compare(qApp->applicationFilePath().replace("/", "\\"), Qt::CaseInsensitive) != 0)
return false;
return true;
}
@@ -1303,8 +1303,8 @@ public:
// Magnet association
if (set) {
const QString command_str = "\""+qApp->applicationFilePath()+"\" \"%1\"";
const QString icon_str = "\""+qApp->applicationFilePath()+"\",1";
const QString command_str = "\""+qApp->applicationFilePath().replace("/", "\\")+"\" \"%1\"";
const QString icon_str = "\""+qApp->applicationFilePath().replace("/", "\\")+"\",1";
settings.setValue("magnet/Default", "URL:Magnet link");
settings.setValue("magnet/Content Type", "application/x-magnet");

View File

@@ -40,10 +40,10 @@
#include "preferences.h"
#ifdef Q_WS_MAC
const QUrl RSS_URL("http://sourceforge.net/api/file/index/project-id/163414/mtime/desc/rss?path=/qbittorrent-mac");
const QUrl RSS_URL("http://sourceforge.net/projects/qbittorrent/rss?path=/qbittorrent-mac");
const QString FILE_EXT = "DMG";
#else
const QUrl RSS_URL("http://sourceforge.net/api/file/index/project-id/163414/mtime/desc/rss?path=/qbittorrent-win32");
const QUrl RSS_URL("http://sourceforge.net/projects/qbittorrent/rss?path=/qbittorrent-win32");
const QString FILE_EXT = "EXE";
#endif

View File

@@ -384,7 +384,7 @@ void PropertiesWidget::loadDynamicData() {
}
}
} catch(const invalid_handle& e) {
qWarning() << "Caught exception in PropertiesWidget::loadDynamicData(): " << e.what();
qWarning() << "Caught exception in PropertiesWidget::loadDynamicData(): " << misc::toQStringU(e.what());
}
}
@@ -453,8 +453,10 @@ void PropertiesWidget::openFolder(const QModelIndex &index, bool containing_fold
void PropertiesWidget::displayFilesListMenu(const QPoint&) {
if (!h.is_valid())
return;
QMenu myFilesLlistMenu;
QModelIndexList selectedRows = filesList->selectionModel()->selectedRows(0);
if (selectedRows.empty())
return;
QMenu myFilesLlistMenu;
QAction *actOpen = 0;
QAction *actOpenContainingFolder = 0;
QAction *actRename = 0;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 172 KiB

View File

@@ -1110,7 +1110,7 @@ QTorrentHandle QBtSession::addTorrent(QString path, bool fromScanDir, QString fr
} catch(std::exception& e) {
if (!from_url.isNull()) {
addConsoleMessage(tr("Unable to decode torrent file: '%1'", "e.g: Unable to decode torrent file: '/home/y/xxx.torrent'").arg(from_url), QString::fromUtf8("red"));
addConsoleMessage(misc::toQString(e.what()), "red");
addConsoleMessage(misc::toQStringU(e.what()), "red");
//emit invalidTorrent(from_url);
fsutils::forceRemove(path);
}else{

View File

@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#
#VERSION: 1.22
#VERSION: 1.23
#AUTHORS: BTDigg team (research@btdigg.org)
#
# GNU GENERAL PUBLIC LICENSE
@@ -66,7 +66,7 @@ class btdigg(object):
pass
def search(self, what, cat='all'):
req = what.replace('+', ' ')
req = urllib.unquote(what)
u = urllib2.urlopen('https://api.btdigg.org/api/public-8e9a50f8335b964f/s01?%s' % (urllib.urlencode(dict(q = req)),))
try:

View File

@@ -1,6 +1,7 @@
#VERSION: 1.53
#VERSION: 2.00
#AUTHORS: Fabien Devaux (fab@gnux.info)
#CONTRIBUTORS: Christophe Dumez (chris@qbittorrent.org)
# Arthur (custparasite@gmx.se)
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
@@ -27,94 +28,112 @@
# POSSIBILITY OF SUCH DAMAGE.
from novaprinter import prettyPrinter
import sgmllib
from helpers import retrieve_url, download_file
from HTMLParser import HTMLParser
from helpers import download_file
import urllib2
PREVIOUS_IDS = set()
class piratebay(object):
url = 'https://thepiratebay.se'
name = 'The Pirate Bay'
supported_categories = {'all': '0', 'movies': '200', 'music': '100', 'games': '400', 'software': '300'}
url = 'http://thepiratebay.se'
name = 'The Pirate Bay'
supported_categories = {'all': '0', 'music': '100', 'movies': '200', 'games': '400', 'software': '300'}
def __init__(self):
self.results = []
self.parser = self.SimpleSGMLParser(self.results, self.url)
def download_torrent(self, info):
print(download_file(info))
def download_torrent(self, info):
print download_file(info)
class MyHtmlParseWithBlackJack(HTMLParser):
def __init__(self, results, url):
HTMLParser.__init__(self)
self.url = url
self.results = results
self.current_item = None
self.size_found = False
self.unit_found = False
self.seed_found = False
self.skip_td = False
self.leech_found = False
self.dispatcher = {'a' : self.handle_tag_a_ref,
'font' : self.handle_tag_font_size,
'td' : self.handle_tag_td_sl }
class SimpleSGMLParser(sgmllib.SGMLParser):
def __init__(self, results, url, *args):
sgmllib.SGMLParser.__init__(self)
self.td_counter = None
self.current_item = None
self.results = results
self.url = url
self.code = 0
self.in_name = None
def handle_tag_a_ref(self, attrs):
params = dict(attrs)
#1
if params['href'].startswith('/torrent/'):
get_id = params['href'].split('/')[2]
if not get_id in PREVIOUS_IDS:
self.current_item = {}
self.current_item['desc_link'] = self.url + params['href'].strip()
self.current_item['name'] = params['title'][12:].strip()
self.current_item['id'] = get_id
#2
elif (not self.current_item is None) and (params['href'].startswith('magnet:')):
self.current_item['link'] = params['href'].strip()
def start_a(self, attr):
params = dict(attr)
if params['href'].startswith('/torrent/'):
self.current_item = {}
self.td_counter = 0
self.current_item['desc_link'] = self.url + params['href'].strip()
self.in_name = True
self.current_item['id'] = params['href'].split('/')[2]
elif params['href'].startswith('magnet:'):
self.current_item['link']=params['href'].strip()
self.in_name = False
def handle_tag_font_size(self, attrs):
if not self.current_item is None:
params = dict(attrs)
#3
if params['class'] == "detDesc":
self.size_found = True
def handle_data(self, data):
if self.td_counter == 0:
if self.in_name:
if not self.current_item.has_key('name'):
self.current_item['name'] = ''
self.current_item['name']+= data.strip()
else:
#Parse size
if 'Size' in data:
self.current_item['size'] = data[data.index("Size")+5:]
self.current_item['size'] = self.current_item['size'][:self.current_item['size'].index(',')]
elif self.td_counter == 1:
if not self.current_item.has_key('seeds'):
self.current_item['seeds'] = ''
self.current_item['seeds']+= data.strip()
elif self.td_counter == 2:
if not self.current_item.has_key('leech'):
self.current_item['leech'] = ''
self.current_item['leech']+= data.strip()
def handle_tag_td_sl(self, attrs):
if not self.current_item is None:
params = dict(attrs)
if not self.current_item is None:
if self.seed_found:
#5
self.current_item['leech'] = ''
self.leech_found = True
self.seed_found = False
else:
#4
self.current_item['seeds'] = ''
self.seed_found = True
def start_td(self,attr):
if isinstance(self.td_counter,int):
self.td_counter += 1
if self.td_counter > 3:
self.td_counter = None
# Display item
if self.current_item:
if self.current_item['id'] in PREVIOUS_IDS:
self.results = []
self.reset()
return
self.current_item['engine_url'] = self.url
if not self.current_item['seeds'].isdigit():
self.current_item['seeds'] = 0
if not self.current_item['leech'].isdigit():
self.current_item['leech'] = 0
prettyPrinter(self.current_item)
PREVIOUS_IDS.add(self.current_item['id'])
self.results.append('a')
def search(self, what, cat='all'):
ret = []
i = 0
order = 'se'
while True and i<11:
results = []
parser = self.SimpleSGMLParser(results, self.url)
dat = retrieve_url(self.url+'/search/%s/%d/7/%s' % (what, i, self.supported_categories[cat]))
parser.feed(dat)
parser.close()
if len(results) <= 0:
break
i += 1
def handle_starttag(self, tag, attrs):
if tag in self.dispatcher:
self.dispatcher[tag](attrs)
def handle_data(self, data):
if not self.current_item is None:
if self.size_found:
#with utf-8 you're going to have something like that: ['Uploaded', '10-02'], ['15:31,', 'Size', '240.34'], ['MiB,', 'ULed', 'by']
temp = data.split()
if 'Size' in temp:
sizeIn = temp.index('Size')
self.current_item['size'] = temp[sizeIn + 1]
self.size_found = False
self.unit_found = True
elif self.unit_found:
temp = data.split()
self.current_item['size'] = ' '.join((self.current_item['size'], temp[0]))
self.unit_found = False
elif self.seed_found:
self.current_item['seeds'] += data.rstrip()
elif self.leech_found:
self.current_item['leech'] += data.rstrip()
self.current_item['engine_url'] = self.url
prettyPrinter(self.current_item)
PREVIOUS_IDS.add(self.current_item['id'])
self.results.append('a')
self.current_item = None
self.size_found = False
self.unit_found = False
self.seed_found = False
self.leech_found = False
def search(self, what, cat='all'):
ret = []
i = 0
while i < 11:
results = []
parser = self.MyHtmlParseWithBlackJack(results, self.url)
query = '%s/search/%s/%d/99/%s' % (self.url, what, i, self.supported_categories[cat])
dat = urllib2.urlopen(query)
parser.feed(dat.read().decode('utf-8'))
parser.close()
if len(results) <= 0:
break
i += 1

View File

@@ -1,6 +1,7 @@
#VERSION: 1.32
#VERSION: 1.33
#AUTHORS: Gekko Dam Beer (gekko04@users.sourceforge.net)
#CONTRIBUTORS: Christophe Dumez (chris@qbittorrent.org)
# Bruno Barbieri (brunorex@gmail.com)
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
@@ -27,8 +28,11 @@
# POSSIBILITY OF SUCH DAMAGE.
from novaprinter import prettyPrinter
import sgmllib
from helpers import retrieve_url, download_file
from urllib2 import HTTPError
from HTMLParser import HTMLParser
import urllib
import re
class torrentreactor(object):
url = 'http://www.torrentreactor.net'
@@ -37,30 +41,32 @@ class torrentreactor(object):
def download_torrent(self, info):
print download_file(info)
class SimpleSGMLParser(sgmllib.SGMLParser):
class SimpleHTMLParser(HTMLParser):
def __init__(self, results, url, *args):
sgmllib.SGMLParser.__init__(self)
HTMLParser.__init__(self)
self.td_counter = None
self.current_item = None
self.results = results
self.id = None
self.url = url
self.dispatcher = { 'a' : self.start_a, 'td' : self.start_td }
def handle_starttag(self, tag, attrs):
if tag in self.dispatcher:
self.dispatcher[tag](attrs)
def start_a(self, attr):
params = dict(attr)
if 'torrentreactor.net/download.php' in params['href']:
if re.match("/torrents/\d+.*", params['href']):
self.current_item = {}
self.current_item['desc_link'] = self.url+params['href'].strip()
elif 'torrentreactor.net/download.php' in params['href']:
self.td_counter = 0
self.current_item['link'] = params['href'].strip()
elif params['href'].startswith('/torrents/'):
self.current_item['desc_link'] = 'http://www.torrentreactor.net'+params['href'].strip()
self.current_item['name'] = urllib.unquote_plus(params['href'].split('&')[1].split('name=')[1])
def handle_data(self, data):
if self.td_counter == 0:
if not self.current_item.has_key('name'):
self.current_item['name'] = ''
self.current_item['name']+= data.strip()
if self.td_counter == 1:
if not self.current_item.has_key('size'):
self.current_item['size'] = ''
@@ -92,14 +98,20 @@ class torrentreactor(object):
def __init__(self):
self.results = []
self.parser = self.SimpleSGMLParser(self.results, self.url)
self.parser = self.SimpleHTMLParser(self.results, self.url)
def search(self, what, cat='all'):
i = 0
dat = ''
while True and i<11:
results = []
parser = self.SimpleSGMLParser(results, self.url)
dat = retrieve_url(self.url+'/ts.php?search=&words=%s&cid=%s&sid=&type=1&orderby=a.seeds&asc=0&skip=%s'%(what, self.supported_categories[cat], (i*35)))
parser = self.SimpleHTMLParser(results, self.url)
try:
dat = retrieve_url(self.url+'/torrent-search/%s/%s?sort=seeders.desc&type=all&period=none&categories=%s'%(what, (i*35), self.supported_categories[cat]))
except HTTPError:
break
parser.feed(dat)
parser.close()
if len(results) <= 0:

View File

@@ -1,8 +1,8 @@
torrentreactor: 1.32
torrentreactor: 1.33
mininova: 1.50
piratebay: 1.53
piratebay: 2.00
vertor: 1.3
extratorrent: 1.2
kickasstorrents: 1.24
btdigg: 1.22
btdigg: 1.23
legittorrents: 1.02

View File

@@ -26,7 +26,7 @@
# POSSIBILITY OF SUCH DAMAGE.
#VERSION: 1.31
#VERSION: 1.32
# Author:
# Fabien Devaux <fab AT gnux DOT info>
@@ -41,6 +41,7 @@ import sys
import threading
import os
import glob
import urllib
import fix_encoding
@@ -138,7 +139,7 @@ if __name__ == '__main__':
if cat not in CATEGORIES:
raise SystemExit('Invalid category!')
what = '+'.join(sys.argv[3:])
what = urllib.quote(' '.join(sys.argv[3:]))
threads = []
for engine in engines_list:

View File

@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#
#VERSION: 1.21
#VERSION: 1.23
#AUTHORS: BTDigg team (research@btdigg.org)
#
# GNU GENERAL PUBLIC LICENSE
@@ -36,7 +36,7 @@ class btdigg(object):
pass
def search(self, what, cat='all'):
req = urllib.parse.unquote(what).replace('+', ' ')
req = urllib.parse.unquote(what)
u = urllib.request.urlopen('https://api.btdigg.org/api/public-8e9a50f8335b964f/s01?%s' % (urllib.parse.urlencode(dict(q = req)),))
try:

View File

@@ -1,6 +1,7 @@
#VERSION: 1.53
#VERSION: 2.00
#AUTHORS: Fabien Devaux (fab@gnux.info)
#CONTRIBUTORS: Christophe Dumez (chris@qbittorrent.org)
# Arthur (custparasite@gmx.se)
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
@@ -27,94 +28,112 @@
# POSSIBILITY OF SUCH DAMAGE.
from novaprinter import prettyPrinter
import sgmllib3
from helpers import retrieve_url, download_file
from html.parser import HTMLParser
from helpers import download_file
import urllib.request
PREVIOUS_IDS = set()
class piratebay(object):
url = 'https://thepiratebay.se'
name = 'The Pirate Bay'
supported_categories = {'all': '0', 'movies': '200', 'music': '100', 'games': '400', 'software': '300'}
url = 'http://thepiratebay.se'
name = 'The Pirate Bay'
supported_categories = {'all': '0', 'music': '100', 'movies': '200', 'games': '400', 'software': '300'}
def __init__(self):
self.results = []
self.parser = self.SimpleSGMLParser(self.results, self.url)
def download_torrent(self, info):
print(download_file(info))
def download_torrent(self, info):
print(download_file(info))
class MyHtmlParseWithBlackJack(HTMLParser):
def __init__(self, results, url):
super().__init__()
self.url = url
self.results = results
self.current_item = None
self.size_found = False
self.unit_found = False
self.seed_found = False
self.skip_td = False
self.leech_found = False
self.dispatcher = {'a' : self.handle_tag_a_ref,
'font' : self.handle_tag_font_size,
'td' : self.handle_tag_td_sl }
class SimpleSGMLParser(sgmllib3.SGMLParser):
def __init__(self, results, url, *args):
sgmllib3.SGMLParser.__init__(self)
self.td_counter = None
self.current_item = None
self.results = results
self.url = url
self.code = 0
self.in_name = None
def handle_tag_a_ref(self, attrs):
params = dict(attrs)
#1
if params['href'].startswith('/torrent/'):
get_id = params['href'].split('/')[2]
if not get_id in PREVIOUS_IDS:
self.current_item = {}
self.current_item['desc_link'] = self.url + params['href'].strip()
self.current_item['name'] = params['title'][12:].strip()
self.current_item['id'] = get_id
#2
elif (not self.current_item is None) and (params['href'].startswith('magnet:')):
self.current_item['link'] = params['href'].strip()
def start_a(self, attr):
params = dict(attr)
if params['href'].startswith('/torrent/'):
self.current_item = {}
self.td_counter = 0
self.current_item['desc_link'] = self.url + params['href'].strip()
self.in_name = True
self.current_item['id'] = params['href'].split('/')[2]
elif params['href'].startswith('magnet:'):
self.current_item['link']=params['href'].strip()
self.in_name = False
def handle_tag_font_size(self, attrs):
if not self.current_item is None:
params = dict(attrs)
#3
if params['class'] == "detDesc":
self.size_found = True
def handle_data(self, data):
if self.td_counter == 0:
if self.in_name:
if 'name' not in self.current_item:
self.current_item['name'] = ''
self.current_item['name']+= data.strip()
else:
#Parse size
if 'Size' in data:
self.current_item['size'] = data[data.index("Size")+5:]
self.current_item['size'] = self.current_item['size'][:self.current_item['size'].index(',')]
elif self.td_counter == 1:
if 'seeds' not in self.current_item:
self.current_item['seeds'] = ''
self.current_item['seeds']+= data.strip()
elif self.td_counter == 2:
if 'leech' not in self.current_item:
self.current_item['leech'] = ''
self.current_item['leech']+= data.strip()
def handle_tag_td_sl(self, attrs):
if not self.current_item is None:
params = dict(attrs)
if not self.current_item is None:
if self.seed_found:
#5
self.current_item['leech'] = ''
self.leech_found = True
self.seed_found = False
else:
#4
self.current_item['seeds'] = ''
self.seed_found = True
def start_td(self,attr):
if isinstance(self.td_counter,int):
self.td_counter += 1
if self.td_counter > 3:
self.td_counter = None
# Display item
if self.current_item:
if self.current_item['id'] in PREVIOUS_IDS:
self.results = []
self.reset()
return
self.current_item['engine_url'] = self.url
if not self.current_item['seeds'].isdigit():
self.current_item['seeds'] = 0
if not self.current_item['leech'].isdigit():
self.current_item['leech'] = 0
prettyPrinter(self.current_item)
PREVIOUS_IDS.add(self.current_item['id'])
self.results.append('a')
def search(self, what, cat='all'):
ret = []
i = 0
order = 'se'
while True and i<11:
results = []
parser = self.SimpleSGMLParser(results, self.url)
dat = retrieve_url(self.url+'/search/%s/%d/7/%s' % (what, i, self.supported_categories[cat]))
parser.feed(dat)
parser.close()
if len(results) <= 0:
break
i += 1
def handle_starttag(self, tag, attrs):
if tag in self.dispatcher:
self.dispatcher[tag](attrs)
def handle_data(self, data):
if not self.current_item is None:
if self.size_found:
#with utf-8 you're going to have something like that: ['Uploaded', '10-02'], ['15:31,', 'Size', '240.34'], ['MiB,', 'ULed', 'by']
temp = data.split()
if 'Size' in temp:
sizeIn = temp.index('Size')
self.current_item['size'] = temp[sizeIn + 1]
self.size_found = False
self.unit_found = True
elif self.unit_found:
temp = data.split()
self.current_item['size'] = ' '.join((self.current_item['size'], temp[0]))
self.unit_found = False
elif self.seed_found:
self.current_item['seeds'] += data.rstrip()
elif self.leech_found:
self.current_item['leech'] += data.rstrip()
self.current_item['engine_url'] = self.url
prettyPrinter(self.current_item)
PREVIOUS_IDS.add(self.current_item['id'])
self.results.append('a')
self.current_item = None
self.size_found = False
self.unit_found = False
self.seed_found = False
self.leech_found = False
def search(self, what, cat='all'):
ret = []
i = 0
while i < 11:
results = []
parser = self.MyHtmlParseWithBlackJack(results, self.url)
query = '%s/search/%s/%d/99/%s' % (self.url, what, i, self.supported_categories[cat])
dat = urllib.request.urlopen(query)
parser.feed(dat.read().decode('utf-8'))
parser.close()
if len(results) <= 0:
break
i += 1

View File

@@ -1,6 +1,7 @@
#VERSION: 1.32
#VERSION: 1.33
#AUTHORS: Gekko Dam Beer (gekko04@users.sourceforge.net)
#CONTRIBUTORS: Christophe Dumez (chris@qbittorrent.org)
# Bruno Barbieri (brunorex@gmail.com)
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
@@ -27,8 +28,10 @@
# POSSIBILITY OF SUCH DAMAGE.
from novaprinter import prettyPrinter
import sgmllib3
from helpers import retrieve_url, download_file
from urllib import error, parse
from html.parser import HTMLParser
import re
class torrentreactor(object):
url = 'http://www.torrentreactor.net'
@@ -37,30 +40,32 @@ class torrentreactor(object):
def download_torrent(self, info):
print(download_file(info))
class SimpleSGMLParser(sgmllib3.SGMLParser):
class SimpleHTMLParser(HTMLParser):
def __init__(self, results, url, *args):
sgmllib3.SGMLParser.__init__(self)
HTMLParser.__init__(self)
self.td_counter = None
self.current_item = None
self.results = results
self.id = None
self.url = url
self.dispatcher = { 'a' : self.start_a, 'td' : self.start_td }
def handle_starttag(self, tag, attrs):
if tag in self.dispatcher:
self.dispatcher[tag](attrs)
def start_a(self, attr):
params = dict(attr)
if 'torrentreactor.net/download.php' in params['href']:
if re.match("/torrents/\d+.*", params['href']):
self.current_item = {}
self.current_item['desc_link'] = self.url+params['href'].strip()
elif 'torrentreactor.net/download.php' in params['href']:
self.td_counter = 0
self.current_item['link'] = params['href'].strip()
elif params['href'].startswith('/torrents/'):
self.current_item['desc_link'] = 'http://www.torrentreactor.net'+params['href'].strip()
self.current_item['name'] = parse.unquote_plus(params['href'].split('&')[1].split('name=')[1])
def handle_data(self, data):
if self.td_counter == 0:
if 'name' not in self.current_item:
self.current_item['name'] = ''
self.current_item['name']+= data.strip()
if self.td_counter == 1:
if 'size' not in self.current_item:
self.current_item['size'] = ''
@@ -92,14 +97,20 @@ class torrentreactor(object):
def __init__(self):
self.results = []
self.parser = self.SimpleSGMLParser(self.results, self.url)
self.parser = self.SimpleHTMLParser(self.results, self.url)
def search(self, what, cat='all'):
i = 0
dat = ''
while True and i<11:
results = []
parser = self.SimpleSGMLParser(results, self.url)
dat = retrieve_url(self.url+'/ts.php?search=&words=%s&cid=%s&sid=&type=1&orderby=a.seeds&asc=0&skip=%s'%(what, self.supported_categories[cat], (i*35)))
parser = self.SimpleHTMLParser(results, self.url)
try:
dat = retrieve_url(self.url+'/torrent-search/%s/%s?sort=seeders.desc&type=all&period=none&categories=%s'%(what, (i*35), self.supported_categories[cat]))
except error.HTTPError:
break
parser.feed(dat)
parser.close()
if len(results) <= 0:

View File

@@ -1,8 +1,8 @@
torrentreactor: 1.32
torrentreactor: 1.33
mininova: 1.50
piratebay: 1.53
piratebay: 2.00
vertor: 1.3
extratorrent: 1.2
kickasstorrents: 1.24
btdigg: 1.21
btdigg: 1.23
legittorrents: 1.02

View File

@@ -26,7 +26,7 @@
# POSSIBILITY OF SUCH DAMAGE.
#VERSION: 1.23
#VERSION: 1.24
# Author:
# Fabien Devaux <fab AT gnux DOT info>
@@ -134,7 +134,7 @@ if __name__ == '__main__':
if cat not in CATEGORIES:
raise SystemExit('Invalid category!')
what = urllib.parse.quote('+'.join(sys.argv[3:]))
what = urllib.parse.quote(' '.join(sys.argv[3:]))
threads = []
for engine in engines_list:

View File

@@ -1,4 +1,4 @@
#VERSION: 1.43
#VERSION: 1.44
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
@@ -24,22 +24,18 @@
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import sys
#import codecs
# Force UTF-8 printing
#sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
def prettyPrinter(dictionary):
# Convert everything to unicode for safe printing
#for key,value in list(dictionary.items()):
#if isinstance(dictionary[key], str):
# dictionary[key] = str(dictionary[key], 'utf-8')
outtext = ''
dictionary['size'] = anySizeToBytes(dictionary['size'])
if 'desc_link' in dictionary:
print("%s|%s|%s|%s|%s|%s|%s"%(dictionary['link'],dictionary['name'].replace('|',' '),dictionary['size'],dictionary['seeds'],dictionary['leech'],dictionary['engine_url'],dictionary['desc_link']))
outtext = '%s|%s|%s|%s|%s|%s|%s'%(dictionary['link'],dictionary['name'].replace('|',' '),dictionary['size'],dictionary['seeds'],dictionary['leech'],dictionary['engine_url'],dictionary['desc_link'])
else:
print("%s|%s|%s|%s|%s|%s"%(dictionary['link'],dictionary['name'].replace('|',' '),dictionary['size'],dictionary['seeds'],dictionary['leech'],dictionary['engine_url']))
outtext = '%s|%s|%s|%s|%s|%s'%(dictionary['link'],dictionary['name'].replace('|',' '),dictionary['size'],dictionary['seeds'],dictionary['leech'],dictionary['engine_url'])
# fd 1 is stdout
with open(1, 'w', encoding='utf-8', closefd=False) as utf8stdout:
print(outtext, file=utf8stdout)
def anySizeToBytes(size_string):
"""

View File

@@ -42,6 +42,7 @@
#include "torrentcreatorthread.h"
#include "fs_utils.h"
#include "misc.h"
#if LIBTORRENT_VERSION_NUM < 1600
#include <boost/filesystem/operations.hpp>
@@ -130,7 +131,7 @@ void TorrentCreatorThread::run() {
if (abort) return;
// calculate the hash for all pieces
const QString parent_path = fsutils::branchPath(input_path) + QDir::separator();
set_piece_hashes(t, parent_path.toUtf8().constData(), boost::bind<void>(&sendProgressUpdateSignal, _1, t.num_pieces(), this));
set_piece_hashes(t, parent_path.toUtf8().constData(), boost::bind(sendProgressUpdateSignal, _1, t.num_pieces(), this));
// Set qBittorrent as creator and add user comment to
// torrent_info structure
t.set_creator(creator_str.toUtf8().constData());
@@ -156,6 +157,6 @@ void TorrentCreatorThread::run() {
emit updateProgress(100);
emit creationSuccess(save_path, parent_path);
} catch (std::exception& e) {
emit creationFailure(QString::fromLocal8Bit(e.what()));
emit creationFailure(misc::toQStringU(e.what()));
}
}

View File

@@ -112,6 +112,7 @@ TransferListWidget::TransferListWidget(QWidget *parent, MainWindow *main_window,
#if defined(Q_WS_MAC)
setAttribute(Qt::WA_MacShowFocusRect, false);
#endif
header()->setStretchLastSection(false);
// Default hidden columns
if (!column_loaded) {

View File

@@ -257,7 +257,7 @@ QByteArray btjson::getTrackersForTorrent(const QString& hash)
tracker_list.append(tracker_dict);
}
} catch(const std::exception& e) {
qWarning() << Q_FUNC_INFO << "Invalid torrent: " << e.what();
qWarning() << Q_FUNC_INFO << "Invalid torrent: " << misc::toQStringU(e.what());
return QByteArray();
}
@@ -318,7 +318,7 @@ QByteArray btjson::getPropertiesForTorrent(const QString& hash)
const qreal ratio = QBtSession::instance()->getRealRatio(h.hash());
data[KEY_PROP_RATIO] = ratio > 100. ? QString::fromUtf8("∞") : misc::accurateDoubleToString(ratio, 1, false);
} catch(const std::exception& e) {
qWarning() << Q_FUNC_INFO << "Invalid torrent: " << e.what();
qWarning() << Q_FUNC_INFO << "Invalid torrent: " << misc::toQStringU(e.what());
return QByteArray();
}
@@ -363,7 +363,7 @@ QByteArray btjson::getFilesForTorrent(const QString& hash)
file_list.append(file_dict);
}
} catch (const std::exception& e) {
qWarning() << Q_FUNC_INFO << "Invalid torrent: " << e.what();
qWarning() << Q_FUNC_INFO << "Invalid torrent: " << misc::toQStringU(e.what());
return QByteArray();
}

View File

@@ -193,6 +193,7 @@ void HttpConnection::respond() {
if (nb_fail >= MAX_AUTH_FAILED_ATTEMPTS) {
m_generator.setStatusLine(403, "Forbidden");
m_generator.setMessage(tr("Your IP address has been banned after too many failed authentication attempts."));
m_generator.setContentType("text/plain; charset=utf-8");
m_generator.setContentEncoding(m_parser.acceptsEncoding());
write();
return;

View File

@@ -19,7 +19,7 @@ XPStyle on
!define CSIDL_APPDATA '0x1A' ;Application Data path
!define CSIDL_LOCALAPPDATA '0x1C' ;Local Application Data path
!define PROG_VERSION "3.1.10"
!define PROG_VERSION "3.1.11"
!define MUI_FINISHPAGE_RUN
!define MUI_FINISHPAGE_RUN_FUNCTION PageFinishRun
!define MUI_FINISHPAGE_RUN_TEXT $(launch_qbt)

Some files were not shown because too many files have changed in this diff Show More