mirror of
https://github.com/d47081/qBittorrent.git
synced 2025-01-28 23:44:32 +00:00
Merge pull request #1703 from sorokin/alerts
Use torrent_status to be more efficient.
This commit is contained in:
commit
c8035dff1e
@ -316,28 +316,31 @@ void PropertiesWidget::loadDynamicData() {
|
|||||||
// Refresh only if the torrent handle is valid and if visible
|
// Refresh only if the torrent handle is valid and if visible
|
||||||
if (!h.is_valid() || main_window->getCurrentTabWidget() != transferList || state != VISIBLE) return;
|
if (!h.is_valid() || main_window->getCurrentTabWidget() != transferList || state != VISIBLE) return;
|
||||||
try {
|
try {
|
||||||
|
libtorrent::torrent_status status = h.status(torrent_handle::query_accurate_download_counters
|
||||||
|
| torrent_handle::query_distributed_copies
|
||||||
|
| torrent_handle::query_pieces);
|
||||||
// Transfer infos
|
// Transfer infos
|
||||||
if (stackedProperties->currentIndex() == PropTabBar::MAIN_TAB) {
|
if (stackedProperties->currentIndex() == PropTabBar::MAIN_TAB) {
|
||||||
wasted->setText(misc::friendlyUnit(h.total_failed_bytes()+h.total_redundant_bytes()));
|
wasted->setText(misc::friendlyUnit(status.total_failed_bytes+status.total_redundant_bytes));
|
||||||
upTotal->setText(misc::friendlyUnit(h.all_time_upload()) + " ("+misc::friendlyUnit(h.total_payload_upload())+" "+tr("this session")+")");
|
upTotal->setText(misc::friendlyUnit(status.all_time_upload) + " ("+misc::friendlyUnit(status.total_payload_upload)+" "+tr("this session")+")");
|
||||||
dlTotal->setText(misc::friendlyUnit(h.all_time_download()) + " ("+misc::friendlyUnit(h.total_payload_download())+" "+tr("this session")+")");
|
dlTotal->setText(misc::friendlyUnit(status.all_time_download) + " ("+misc::friendlyUnit(status.total_payload_download)+" "+tr("this session")+")");
|
||||||
lbl_uplimit->setText(h.upload_limit() <= 0 ? QString::fromUtf8("∞") : misc::friendlyUnit(h.upload_limit())+tr("/s", "/second (i.e. per second)"));
|
lbl_uplimit->setText(h.upload_limit() <= 0 ? QString::fromUtf8("∞") : misc::friendlyUnit(h.upload_limit())+tr("/s", "/second (i.e. per second)"));
|
||||||
lbl_dllimit->setText(h.download_limit() <= 0 ? QString::fromUtf8("∞") : misc::friendlyUnit(h.download_limit())+tr("/s", "/second (i.e. per second)"));
|
lbl_dllimit->setText(h.download_limit() <= 0 ? QString::fromUtf8("∞") : misc::friendlyUnit(h.download_limit())+tr("/s", "/second (i.e. per second)"));
|
||||||
QString elapsed_txt = misc::userFriendlyDuration(h.active_time());
|
QString elapsed_txt = misc::userFriendlyDuration(status.active_time);
|
||||||
if (h.is_seed()) {
|
if (h.is_seed(status)) {
|
||||||
elapsed_txt += " ("+tr("Seeded for %1", "e.g. Seeded for 3m10s").arg(misc::userFriendlyDuration(h.seeding_time()))+")";
|
elapsed_txt += " ("+tr("Seeded for %1", "e.g. Seeded for 3m10s").arg(misc::userFriendlyDuration(status.seeding_time))+")";
|
||||||
}
|
}
|
||||||
lbl_elapsed->setText(elapsed_txt);
|
lbl_elapsed->setText(elapsed_txt);
|
||||||
if (h.connections_limit() > 0)
|
if (status.connections_limit > 0)
|
||||||
lbl_connections->setText(QString::number(h.num_connections())+" ("+tr("%1 max", "e.g. 10 max").arg(QString::number(h.connections_limit()))+")");
|
lbl_connections->setText(QString::number(status.num_connections)+" ("+tr("%1 max", "e.g. 10 max").arg(QString::number(status.connections_limit))+")");
|
||||||
else
|
else
|
||||||
lbl_connections->setText(QString::number(h.num_connections()));
|
lbl_connections->setText(QString::number(status.num_connections));
|
||||||
// Update next announce time
|
// Update next announce time
|
||||||
reannounce_lbl->setText(h.next_announce());
|
reannounce_lbl->setText(misc::userFriendlyDuration(status.next_announce.total_seconds()));
|
||||||
// Update ratio info
|
// Update ratio info
|
||||||
const qreal ratio = QBtSession::instance()->getRealRatio(h.hash());
|
const qreal ratio = QBtSession::instance()->getRealRatio(status);
|
||||||
shareRatio->setText(ratio > QBtSession::MAX_RATIO ? QString::fromUtf8("∞") : misc::accurateDoubleToString(ratio, 2));
|
shareRatio->setText(ratio > QBtSession::MAX_RATIO ? QString::fromUtf8("∞") : misc::accurateDoubleToString(ratio, 2));
|
||||||
if (!h.is_seed() && h.has_metadata()) {
|
if (!h.is_seed(status) && status.has_metadata) {
|
||||||
showPiecesDownloaded(true);
|
showPiecesDownloaded(true);
|
||||||
// Downloaded pieces
|
// Downloaded pieces
|
||||||
#if LIBTORRENT_VERSION_NUM < 10000
|
#if LIBTORRENT_VERSION_NUM < 10000
|
||||||
@ -346,19 +349,19 @@ void PropertiesWidget::loadDynamicData() {
|
|||||||
bitfield bf(h.torrent_file()->num_pieces(), 0);
|
bitfield bf(h.torrent_file()->num_pieces(), 0);
|
||||||
#endif
|
#endif
|
||||||
h.downloading_pieces(bf);
|
h.downloading_pieces(bf);
|
||||||
downloaded_pieces->setProgress(h.pieces(), bf);
|
downloaded_pieces->setProgress(status.pieces, bf);
|
||||||
// Pieces availability
|
// Pieces availability
|
||||||
if (!h.is_paused() && !h.is_queued() && !h.is_checking()) {
|
if (!h.is_paused(status) && !h.is_queued(status) && !h.is_checking(status)) {
|
||||||
showPiecesAvailability(true);
|
showPiecesAvailability(true);
|
||||||
std::vector<int> avail;
|
std::vector<int> avail;
|
||||||
h.piece_availability(avail);
|
h.piece_availability(avail);
|
||||||
pieces_availability->setAvailability(avail);
|
pieces_availability->setAvailability(avail);
|
||||||
avail_average_lbl->setText(misc::accurateDoubleToString(h.distributed_copies(), 3));
|
avail_average_lbl->setText(misc::accurateDoubleToString(status.distributed_copies, 3));
|
||||||
} else {
|
} else {
|
||||||
showPiecesAvailability(false);
|
showPiecesAvailability(false);
|
||||||
}
|
}
|
||||||
// Progress
|
// Progress
|
||||||
qreal progress = h.progress()*100.;
|
qreal progress = h.progress(status)*100.;
|
||||||
progress_lbl->setText(misc::accurateDoubleToString(progress, 1)+"%");
|
progress_lbl->setText(misc::accurateDoubleToString(progress, 1)+"%");
|
||||||
} else {
|
} else {
|
||||||
showPiecesAvailability(false);
|
showPiecesAvailability(false);
|
||||||
@ -378,7 +381,7 @@ void PropertiesWidget::loadDynamicData() {
|
|||||||
}
|
}
|
||||||
if (stackedProperties->currentIndex() == PropTabBar::FILES_TAB) {
|
if (stackedProperties->currentIndex() == PropTabBar::FILES_TAB) {
|
||||||
// Files progress
|
// Files progress
|
||||||
if (h.is_valid() && h.has_metadata()) {
|
if (h.is_valid() && status.has_metadata) {
|
||||||
qDebug("Updating priorities in files tab");
|
qDebug("Updating priorities in files tab");
|
||||||
filesList->setUpdatesEnabled(false);
|
filesList->setUpdatesEnabled(false);
|
||||||
std::vector<size_type> fp;
|
std::vector<size_type> fp;
|
||||||
|
93
src/qtlibtorrent/alertdispatcher.cpp
Normal file
93
src/qtlibtorrent/alertdispatcher.cpp
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#include "alertdispatcher.h"
|
||||||
|
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
#include <boost/make_shared.hpp>
|
||||||
|
#include <QMutexLocker>
|
||||||
|
|
||||||
|
QAlertDispatcher::QAlertDispatcher(libtorrent::session *session, QObject* parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, session(session)
|
||||||
|
, current_tag(new QAtomicPointer<QAlertDispatcher>(this))
|
||||||
|
, event_posted(false) {
|
||||||
|
session->set_alert_dispatch(boost::bind(&QAlertDispatcher::dispatch, current_tag, _1));
|
||||||
|
}
|
||||||
|
|
||||||
|
QAlertDispatcher::~QAlertDispatcher() {
|
||||||
|
// When QAlertDispatcher is destoyed, libtorrent still can call
|
||||||
|
// QAlertDispatcher::dispatch a few times after destruction. This is
|
||||||
|
// handled by passing a "tag". A tag is a object that references QAlertDispatch.
|
||||||
|
// Tag could be invalidated. So on destruction QAlertDispatcher invalidates a tag
|
||||||
|
// and then unsubscribes from alerts. When QAlertDispatcher::dispatch is called
|
||||||
|
// with invalid tag it simply discard an alert.
|
||||||
|
|
||||||
|
{
|
||||||
|
QMutexLocker lock(&(alerts_mutex));
|
||||||
|
*current_tag = 0;
|
||||||
|
current_tag.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef boost::function<void (std::auto_ptr<libtorrent::alert>)> dispatch_function_t;
|
||||||
|
session->set_alert_dispatch(dispatch_function_t());
|
||||||
|
}
|
||||||
|
|
||||||
|
void QAlertDispatcher::getPendingAlertsNoWait(std::deque<libtorrent::alert*>& out) {
|
||||||
|
Q_ASSERT(out.empty());
|
||||||
|
|
||||||
|
QMutexLocker lock(&(alerts_mutex));
|
||||||
|
std::swap(alerts, out);
|
||||||
|
event_posted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QAlertDispatcher::getPendingAlerts(std::deque<libtorrent::alert*>& out) {
|
||||||
|
assert(out.empty());
|
||||||
|
|
||||||
|
QMutexLocker lock(&(alerts_mutex));
|
||||||
|
|
||||||
|
while (alerts.empty())
|
||||||
|
alerts_condvar.wait(&(alerts_mutex));
|
||||||
|
|
||||||
|
std::swap(alerts, out);
|
||||||
|
event_posted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QAlertDispatcher::dispatch(QSharedPointer<QAtomicPointer<QAlertDispatcher> > tag,
|
||||||
|
std::auto_ptr<libtorrent::alert> alert_ptr) {
|
||||||
|
QAlertDispatcher* that = *tag;
|
||||||
|
if (!that)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QMutexLocker lock(&(that->alerts_mutex));
|
||||||
|
|
||||||
|
that = *tag;
|
||||||
|
if (!that)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool was_empty = that->alerts.empty();
|
||||||
|
|
||||||
|
that->alerts.push_back(alert_ptr.get());
|
||||||
|
alert_ptr.release();
|
||||||
|
|
||||||
|
if (was_empty)
|
||||||
|
that->alerts_condvar.wakeAll();
|
||||||
|
|
||||||
|
that->enqueueToMainThread();
|
||||||
|
|
||||||
|
Q_ASSERT(that->current_tag == tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QAlertDispatcher::enqueueToMainThread() {
|
||||||
|
if (!event_posted) {
|
||||||
|
event_posted = true;
|
||||||
|
QMetaObject::invokeMethod(this, "deliverSignal", Qt::QueuedConnection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QAlertDispatcher::deliverSignal() {
|
||||||
|
emit alertsReceived();
|
||||||
|
|
||||||
|
QMutexLocker lock(&(alerts_mutex));
|
||||||
|
event_posted = false;
|
||||||
|
|
||||||
|
if (!alerts.empty())
|
||||||
|
enqueueToMainThread();
|
||||||
|
}
|
43
src/qtlibtorrent/alertdispatcher.h
Normal file
43
src/qtlibtorrent/alertdispatcher.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#ifndef ALERTDISPATCHER_H
|
||||||
|
#define ALERTDISPATCHER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QWaitCondition>
|
||||||
|
#include <QAtomicPointer>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
#include <libtorrent/session.hpp>
|
||||||
|
|
||||||
|
class QAlertDispatcher : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_DISABLE_COPY(QAlertDispatcher)
|
||||||
|
|
||||||
|
public:
|
||||||
|
QAlertDispatcher(libtorrent::session *session, QObject* parent);
|
||||||
|
~QAlertDispatcher();
|
||||||
|
|
||||||
|
void getPendingAlertsNoWait(std::deque<libtorrent::alert*>&);
|
||||||
|
void getPendingAlerts(std::deque<libtorrent::alert*>&);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void alertsReceived();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void dispatch(QSharedPointer<QAtomicPointer<QAlertDispatcher> >,
|
||||||
|
std::auto_ptr<libtorrent::alert>);
|
||||||
|
void enqueueToMainThread();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void deliverSignal();
|
||||||
|
|
||||||
|
private:
|
||||||
|
libtorrent::session *session;
|
||||||
|
QMutex alerts_mutex;
|
||||||
|
QWaitCondition alerts_condvar;
|
||||||
|
std::deque<libtorrent::alert*> alerts;
|
||||||
|
QSharedPointer<QAtomicPointer<QAlertDispatcher> > current_tag;
|
||||||
|
bool event_posted;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ALERTDISPATCHER_H
|
File diff suppressed because it is too large
Load Diff
@ -47,10 +47,12 @@
|
|||||||
#include <libtorrent/version.hpp>
|
#include <libtorrent/version.hpp>
|
||||||
#include <libtorrent/session.hpp>
|
#include <libtorrent/session.hpp>
|
||||||
#include <libtorrent/ip_filter.hpp>
|
#include <libtorrent/ip_filter.hpp>
|
||||||
|
#include <libtorrent/alert_types.hpp>
|
||||||
|
|
||||||
#include "qtracker.h"
|
#include "qtracker.h"
|
||||||
#include "qtorrenthandle.h"
|
#include "qtorrenthandle.h"
|
||||||
#include "trackerinfos.h"
|
#include "trackerinfos.h"
|
||||||
|
#include "alertdispatcher.h"
|
||||||
|
|
||||||
#define MAX_SAMPLES 20
|
#define MAX_SAMPLES 20
|
||||||
|
|
||||||
@ -60,6 +62,7 @@ class HttpServer;
|
|||||||
class BandwidthScheduler;
|
class BandwidthScheduler;
|
||||||
class ScanFoldersModel;
|
class ScanFoldersModel;
|
||||||
class TorrentSpeedMonitor;
|
class TorrentSpeedMonitor;
|
||||||
|
class TorrentStatistics;
|
||||||
class DNSUpdater;
|
class DNSUpdater;
|
||||||
|
|
||||||
const int MAX_LOG_MESSAGES = 1000;
|
const int MAX_LOG_MESSAGES = 1000;
|
||||||
@ -92,7 +95,7 @@ public:
|
|||||||
qreal getPayloadUploadRate() const;
|
qreal getPayloadUploadRate() const;
|
||||||
libtorrent::session_status getSessionStatus() const;
|
libtorrent::session_status getSessionStatus() const;
|
||||||
int getListenPort() const;
|
int getListenPort() const;
|
||||||
qreal getRealRatio(const QString& hash) const;
|
qreal getRealRatio(const libtorrent::torrent_status &status) const;
|
||||||
QHash<QString, TrackerInfos> getTrackersInfo(const QString &hash) const;
|
QHash<QString, TrackerInfos> getTrackersInfo(const QString &hash) const;
|
||||||
bool hasActiveTorrents() const;
|
bool hasActiveTorrents() const;
|
||||||
bool hasDownloadingTorrents() const;
|
bool hasDownloadingTorrents() const;
|
||||||
@ -110,6 +113,7 @@ public:
|
|||||||
inline bool isQueueingEnabled() const { return queueingEnabled; }
|
inline bool isQueueingEnabled() const { return queueingEnabled; }
|
||||||
quint64 getAlltimeDL() const;
|
quint64 getAlltimeDL() const;
|
||||||
quint64 getAlltimeUL() const;
|
quint64 getAlltimeUL() const;
|
||||||
|
void postTorrentUpdate();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
QTorrentHandle addTorrent(QString path, bool fromScanDir = false, QString from_url = QString(), bool resumed = false);
|
QTorrentHandle addTorrent(QString path, bool fromScanDir = false, QString from_url = QString(), bool resumed = false);
|
||||||
@ -121,7 +125,7 @@ public slots:
|
|||||||
void startUpTorrents();
|
void startUpTorrents();
|
||||||
void recheckTorrent(const QString &hash);
|
void recheckTorrent(const QString &hash);
|
||||||
void useAlternativeSpeedsLimit(bool alternative);
|
void useAlternativeSpeedsLimit(bool alternative);
|
||||||
qlonglong getETA(const QString& hash) const;
|
qlonglong getETA(const QString& hash, const libtorrent::torrent_status &status) const;
|
||||||
/* Needed by Web UI */
|
/* Needed by Web UI */
|
||||||
void pauseAllTorrents();
|
void pauseAllTorrents();
|
||||||
void pauseTorrent(const QString &hash);
|
void pauseTorrent(const QString &hash);
|
||||||
@ -190,6 +194,7 @@ private:
|
|||||||
void updateRatioTimer();
|
void updateRatioTimer();
|
||||||
void recoverPersistentData(const QString &hash, const std::vector<char> &buf);
|
void recoverPersistentData(const QString &hash, const std::vector<char> &buf);
|
||||||
void backupPersistentData(const QString &hash, boost::shared_ptr<libtorrent::entry> data);
|
void backupPersistentData(const QString &hash, boost::shared_ptr<libtorrent::entry> data);
|
||||||
|
void handleAlert(libtorrent::alert* a);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void addTorrentsFromScanFolder(QStringList&);
|
void addTorrentsFromScanFolder(QStringList&);
|
||||||
@ -230,11 +235,12 @@ signals:
|
|||||||
void recursiveTorrentDownloadPossible(const QTorrentHandle &h);
|
void recursiveTorrentDownloadPossible(const QTorrentHandle &h);
|
||||||
void ipFilterParsed(bool error, int ruleCount);
|
void ipFilterParsed(bool error, int ruleCount);
|
||||||
void metadataReceivedHidden(const QTorrentHandle &h);
|
void metadataReceivedHidden(const QTorrentHandle &h);
|
||||||
|
void stateUpdate(const std::vector<libtorrent::torrent_status> &statuses);
|
||||||
|
void statsReceived(const libtorrent::stats_alert&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Bittorrent
|
// Bittorrent
|
||||||
libtorrent::session *s;
|
libtorrent::session *s;
|
||||||
QPointer<QTimer> timerAlerts;
|
|
||||||
QPointer<BandwidthScheduler> bd_scheduler;
|
QPointer<BandwidthScheduler> bd_scheduler;
|
||||||
QMap<QUrl, QPair<QString, QString> > savepathLabel_fromurl; // Use QMap for compatibility with Qt < 4.7: qHash(QUrl)
|
QMap<QUrl, QPair<QString, QString> > savepathLabel_fromurl; // Use QMap for compatibility with Qt < 4.7: qHash(QUrl)
|
||||||
QHash<QString, QHash<QString, TrackerInfos> > trackersInfos;
|
QHash<QString, QHash<QString, TrackerInfos> > trackersInfos;
|
||||||
@ -287,6 +293,8 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
// DynDNS
|
// DynDNS
|
||||||
DNSUpdater *m_dynDNSUpdater;
|
DNSUpdater *m_dynDNSUpdater;
|
||||||
|
QAlertDispatcher* m_alertDispatcher;
|
||||||
|
TorrentStatistics* m_torrentStatistics;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -5,11 +5,15 @@ HEADERS += $$PWD/qbtsession.h \
|
|||||||
$$PWD/bandwidthscheduler.h \
|
$$PWD/bandwidthscheduler.h \
|
||||||
$$PWD/trackerinfos.h \
|
$$PWD/trackerinfos.h \
|
||||||
$$PWD/torrentspeedmonitor.h \
|
$$PWD/torrentspeedmonitor.h \
|
||||||
$$PWD/filterparserthread.h
|
$$PWD/filterparserthread.h \
|
||||||
|
$$PWD/alertdispatcher.h \
|
||||||
|
$$PWD/torrentstatistics.h
|
||||||
|
|
||||||
SOURCES += $$PWD/qbtsession.cpp \
|
SOURCES += $$PWD/qbtsession.cpp \
|
||||||
$$PWD/qtorrenthandle.cpp \
|
$$PWD/qtorrenthandle.cpp \
|
||||||
$$PWD/torrentspeedmonitor.cpp
|
$$PWD/torrentspeedmonitor.cpp \
|
||||||
|
$$PWD/alertdispatcher.cpp \
|
||||||
|
$$PWD/torrentstatistics.cpp
|
||||||
|
|
||||||
!contains(DEFINES, DISABLE_GUI) {
|
!contains(DEFINES, DISABLE_GUI) {
|
||||||
HEADERS += $$PWD/torrentmodel.h \
|
HEADERS += $$PWD/torrentmodel.h \
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
|
#include <QDateTime>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "fs_utils.h"
|
#include "fs_utils.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
@ -87,7 +88,7 @@ QString QTorrentHandle::name() const {
|
|||||||
#if LIBTORRENT_VERSION_NUM < 10000
|
#if LIBTORRENT_VERSION_NUM < 10000
|
||||||
name = misc::toQStringU(torrent_handle::name());
|
name = misc::toQStringU(torrent_handle::name());
|
||||||
#else
|
#else
|
||||||
name = misc::toQStringU(torrent_handle::status(torrent_handle::query_name).name);
|
name = misc::toQStringU(status(query_name).name);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
return name;
|
return name;
|
||||||
@ -102,41 +103,16 @@ QString QTorrentHandle::creation_date() const {
|
|||||||
return t ? misc::toQString(*t) : "";
|
return t ? misc::toQString(*t) : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QTorrentHandle::next_announce() const {
|
|
||||||
return misc::userFriendlyDuration(torrent_handle::status(0x0).next_announce.total_seconds());
|
|
||||||
}
|
|
||||||
|
|
||||||
qlonglong QTorrentHandle::next_announce_s() const {
|
|
||||||
return torrent_handle::status(0x0).next_announce.total_seconds();
|
|
||||||
}
|
|
||||||
|
|
||||||
float QTorrentHandle::progress() const {
|
|
||||||
torrent_status st = torrent_handle::status(query_accurate_download_counters);
|
|
||||||
if (!st.total_wanted)
|
|
||||||
return 0.;
|
|
||||||
if (st.total_wanted_done == st.total_wanted)
|
|
||||||
return 1.;
|
|
||||||
float progress = (float) st.total_wanted_done / (float) st.total_wanted;
|
|
||||||
Q_ASSERT(progress >= 0. && progress <= 1.);
|
|
||||||
return progress;
|
|
||||||
}
|
|
||||||
|
|
||||||
bitfield QTorrentHandle::pieces() const {
|
|
||||||
return torrent_handle::status(torrent_handle::query_pieces).pieces;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString QTorrentHandle::current_tracker() const {
|
QString QTorrentHandle::current_tracker() const {
|
||||||
return misc::toQString(torrent_handle::status(0x0).current_tracker);
|
return misc::toQString(status(0x0).current_tracker);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QTorrentHandle::is_paused() const {
|
bool QTorrentHandle::is_paused() const {
|
||||||
torrent_status st = torrent_handle::status(0x0);
|
return is_paused(status(0x0));
|
||||||
return st.paused && !st.auto_managed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QTorrentHandle::is_queued() const {
|
bool QTorrentHandle::is_queued() const {
|
||||||
torrent_status st = torrent_handle::status(0x0);
|
return is_queued(status(0x0));
|
||||||
return st.paused && st.auto_managed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type QTorrentHandle::total_size() const {
|
size_type QTorrentHandle::total_size() const {
|
||||||
@ -189,38 +165,6 @@ bool QTorrentHandle::first_last_piece_first() const {
|
|||||||
&& (torrent_handle::piece_priority(extremities.second) == 7);
|
&& (torrent_handle::piece_priority(extremities.second) == 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type QTorrentHandle::total_wanted_done() const {
|
|
||||||
return torrent_handle::status(query_accurate_download_counters).total_wanted_done;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type QTorrentHandle::total_wanted() const {
|
|
||||||
return torrent_handle::status(0x0).total_wanted;
|
|
||||||
}
|
|
||||||
|
|
||||||
qreal QTorrentHandle::download_payload_rate() const {
|
|
||||||
return torrent_handle::status(0x0).download_payload_rate;
|
|
||||||
}
|
|
||||||
|
|
||||||
qreal QTorrentHandle::upload_payload_rate() const {
|
|
||||||
return torrent_handle::status(0x0).upload_payload_rate;
|
|
||||||
}
|
|
||||||
|
|
||||||
int QTorrentHandle::num_peers() const {
|
|
||||||
return torrent_handle::status(0x0).num_peers;
|
|
||||||
}
|
|
||||||
|
|
||||||
int QTorrentHandle::num_seeds() const {
|
|
||||||
return torrent_handle::status(0x0).num_seeds;
|
|
||||||
}
|
|
||||||
|
|
||||||
int QTorrentHandle::num_complete() const {
|
|
||||||
return torrent_handle::status(0x0).num_complete;
|
|
||||||
}
|
|
||||||
|
|
||||||
int QTorrentHandle::num_incomplete() const {
|
|
||||||
return torrent_handle::status(0x0).num_incomplete;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString QTorrentHandle::save_path() const {
|
QString QTorrentHandle::save_path() const {
|
||||||
#if LIBTORRENT_VERSION_NUM < 10000
|
#if LIBTORRENT_VERSION_NUM < 10000
|
||||||
return fsutils::fromNativePath(misc::toQStringU(torrent_handle::save_path()));
|
return fsutils::fromNativePath(misc::toQStringU(torrent_handle::save_path()));
|
||||||
@ -260,7 +204,7 @@ QStringList QTorrentHandle::url_seeds() const {
|
|||||||
|
|
||||||
// get the size of the torrent without the filtered files
|
// get the size of the torrent without the filtered files
|
||||||
size_type QTorrentHandle::actual_size() const {
|
size_type QTorrentHandle::actual_size() const {
|
||||||
return torrent_handle::status(query_accurate_download_counters).total_wanted;
|
return status(query_accurate_download_counters).total_wanted;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QTorrentHandle::has_filtered_pieces() const {
|
bool QTorrentHandle::has_filtered_pieces() const {
|
||||||
@ -317,7 +261,7 @@ QString QTorrentHandle::orig_filepath_at(unsigned int index) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
torrent_status::state_t QTorrentHandle::state() const {
|
torrent_status::state_t QTorrentHandle::state() const {
|
||||||
return torrent_handle::status(0x0).state;
|
return status(0x0).state;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QTorrentHandle::creator() const {
|
QString QTorrentHandle::creator() const {
|
||||||
@ -336,37 +280,8 @@ QString QTorrentHandle::comment() const {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type QTorrentHandle::total_failed_bytes() const {
|
|
||||||
return torrent_handle::status(0x0).total_failed_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type QTorrentHandle::total_redundant_bytes() const {
|
|
||||||
return torrent_handle::status(0x0).total_redundant_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QTorrentHandle::is_checking() const {
|
bool QTorrentHandle::is_checking() const {
|
||||||
torrent_status st = torrent_handle::status(0x0);
|
return is_checking(status(0x0));
|
||||||
return st.state == torrent_status::checking_files || st.state == torrent_status::checking_resume_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type QTorrentHandle::total_done() const {
|
|
||||||
return torrent_handle::status(query_accurate_download_counters).total_done;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type QTorrentHandle::all_time_download() const {
|
|
||||||
return torrent_handle::status(0x0).all_time_download;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type QTorrentHandle::all_time_upload() const {
|
|
||||||
return torrent_handle::status(0x0).all_time_upload;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type QTorrentHandle::total_payload_download() const {
|
|
||||||
return torrent_handle::status(0x0).total_payload_download;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type QTorrentHandle::total_payload_upload() const {
|
|
||||||
return torrent_handle::status(0x0).total_payload_upload;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a list of absolute paths corresponding
|
// Return a list of absolute paths corresponding
|
||||||
@ -408,44 +323,17 @@ int QTorrentHandle::queue_position() const {
|
|||||||
return torrent_handle::queue_position()+1;
|
return torrent_handle::queue_position()+1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int QTorrentHandle::num_uploads() const {
|
|
||||||
return torrent_handle::status(0x0).num_uploads;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QTorrentHandle::is_seed() const {
|
bool QTorrentHandle::is_seed() const {
|
||||||
// Affected by bug http://code.rasterbar.com/libtorrent/ticket/402
|
// Affected by bug http://code.rasterbar.com/libtorrent/ticket/402
|
||||||
//return torrent_handle::is_seed();
|
//return torrent_handle::is_seed();
|
||||||
// May suffer from approximation problems
|
// May suffer from approximation problems
|
||||||
//return (progress() == 1.);
|
//return (progress() == 1.);
|
||||||
// This looks safe
|
// This looks safe
|
||||||
torrent_status::state_t st = state();
|
return is_seed(status(0x0));
|
||||||
return (st == torrent_status::finished || st == torrent_status::seeding);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QTorrentHandle::is_auto_managed() const {
|
|
||||||
torrent_status status = torrent_handle::status(0x0);
|
|
||||||
return status.auto_managed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QTorrentHandle::is_sequential_download() const {
|
bool QTorrentHandle::is_sequential_download() const {
|
||||||
torrent_status status = torrent_handle::status(0x0);
|
return status(0x0).sequential_download;
|
||||||
return status.sequential_download;
|
|
||||||
}
|
|
||||||
|
|
||||||
qlonglong QTorrentHandle::active_time() const {
|
|
||||||
return torrent_handle::status(0x0).active_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
qlonglong QTorrentHandle::seeding_time() const {
|
|
||||||
return torrent_handle::status(0x0).seeding_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
int QTorrentHandle::num_connections() const {
|
|
||||||
return torrent_handle::status(0x0).num_connections;
|
|
||||||
}
|
|
||||||
|
|
||||||
int QTorrentHandle::connections_limit() const {
|
|
||||||
return torrent_handle::status(0x0).connections_limit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QTorrentHandle::priv() const {
|
bool QTorrentHandle::priv() const {
|
||||||
@ -482,12 +370,11 @@ QString QTorrentHandle::root_path() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool QTorrentHandle::has_error() const {
|
bool QTorrentHandle::has_error() const {
|
||||||
torrent_status st = torrent_handle::status(0x0);
|
return has_error(status(0x0));
|
||||||
return st.paused && !st.error.empty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QTorrentHandle::error() const {
|
QString QTorrentHandle::error() const {
|
||||||
return misc::toQString(torrent_handle::status(0x0).error);
|
return misc::toQString(status(0x0).error);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QTorrentHandle::downloading_pieces(bitfield &bf) const {
|
void QTorrentHandle::downloading_pieces(bitfield &bf) const {
|
||||||
@ -503,11 +390,7 @@ void QTorrentHandle::downloading_pieces(bitfield &bf) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool QTorrentHandle::has_metadata() const {
|
bool QTorrentHandle::has_metadata() const {
|
||||||
return torrent_handle::status(0x0).has_metadata;
|
return status(0x0).has_metadata;
|
||||||
}
|
|
||||||
|
|
||||||
float QTorrentHandle::distributed_copies() const {
|
|
||||||
return torrent_handle::status(query_distributed_copies).distributed_copies;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QTorrentHandle::file_progress(std::vector<size_type>& fp) const {
|
void QTorrentHandle::file_progress(std::vector<size_type>& fp) const {
|
||||||
@ -732,3 +615,41 @@ void QTorrentHandle::rename_file(int index, const QString& name) const {
|
|||||||
bool QTorrentHandle::operator ==(const QTorrentHandle& new_h) const {
|
bool QTorrentHandle::operator ==(const QTorrentHandle& new_h) const {
|
||||||
return info_hash() == new_h.info_hash();
|
return info_hash() == new_h.info_hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QTorrentHandle::is_paused(const libtorrent::torrent_status &status)
|
||||||
|
{
|
||||||
|
return status.paused && !status.auto_managed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QTorrentHandle::is_queued(const libtorrent::torrent_status &status)
|
||||||
|
{
|
||||||
|
return status.paused && status.auto_managed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QTorrentHandle::is_seed(const libtorrent::torrent_status &status)
|
||||||
|
{
|
||||||
|
return status.state == torrent_status::finished
|
||||||
|
|| status.state == torrent_status::seeding;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QTorrentHandle::is_checking(const libtorrent::torrent_status &status)
|
||||||
|
{
|
||||||
|
return status.state == torrent_status::checking_files
|
||||||
|
|| status.state == torrent_status::checking_resume_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QTorrentHandle::has_error(const libtorrent::torrent_status &status)
|
||||||
|
{
|
||||||
|
return status.paused && !status.error.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
float QTorrentHandle::progress(const libtorrent::torrent_status &status)
|
||||||
|
{
|
||||||
|
if (!status.total_wanted)
|
||||||
|
return 0.;
|
||||||
|
if (status.total_wanted_done == status.total_wanted)
|
||||||
|
return 1.;
|
||||||
|
float progress = (float) status.total_wanted_done / (float) status.total_wanted;
|
||||||
|
Q_ASSERT(progress >= 0.f && progress <= 1.f);
|
||||||
|
return progress;
|
||||||
|
}
|
||||||
|
@ -59,24 +59,12 @@ public:
|
|||||||
//
|
//
|
||||||
QString hash() const;
|
QString hash() const;
|
||||||
QString name() const;
|
QString name() const;
|
||||||
float progress() const;
|
|
||||||
libtorrent::bitfield pieces() const;
|
|
||||||
QString current_tracker() const;
|
QString current_tracker() const;
|
||||||
bool is_paused() const;
|
bool is_paused() const;
|
||||||
bool has_filtered_pieces() const;
|
bool has_filtered_pieces() const;
|
||||||
libtorrent::size_type total_size() const;
|
libtorrent::size_type total_size() const;
|
||||||
libtorrent::size_type piece_length() const;
|
libtorrent::size_type piece_length() const;
|
||||||
int num_pieces() const;
|
int num_pieces() const;
|
||||||
libtorrent::size_type total_wanted_done() const;
|
|
||||||
libtorrent::size_type total_wanted() const;
|
|
||||||
qreal download_payload_rate() const;
|
|
||||||
qreal upload_payload_rate() const;
|
|
||||||
int num_connections() const;
|
|
||||||
int connections_limit() const;
|
|
||||||
int num_peers() const;
|
|
||||||
int num_seeds() const;
|
|
||||||
int num_complete() const;
|
|
||||||
int num_incomplete() const;
|
|
||||||
QString save_path() const;
|
QString save_path() const;
|
||||||
QString save_path_parsed() const;
|
QString save_path_parsed() const;
|
||||||
QStringList url_seeds() const;
|
QStringList url_seeds() const;
|
||||||
@ -91,26 +79,13 @@ public:
|
|||||||
libtorrent::torrent_status::state_t state() const;
|
libtorrent::torrent_status::state_t state() const;
|
||||||
QString creator() const;
|
QString creator() const;
|
||||||
QString comment() const;
|
QString comment() const;
|
||||||
libtorrent::size_type total_failed_bytes() const;
|
|
||||||
libtorrent::size_type total_redundant_bytes() const;
|
|
||||||
libtorrent::size_type total_payload_download() const;
|
|
||||||
libtorrent::size_type total_payload_upload() const;
|
|
||||||
libtorrent::size_type all_time_upload() const;
|
|
||||||
libtorrent::size_type all_time_download() const;
|
|
||||||
libtorrent::size_type total_done() const;
|
|
||||||
QStringList absolute_files_path() const;
|
QStringList absolute_files_path() const;
|
||||||
QStringList absolute_files_path_uneeded() const;
|
QStringList absolute_files_path_uneeded() const;
|
||||||
bool has_missing_files() const;
|
bool has_missing_files() const;
|
||||||
int num_uploads() const;
|
|
||||||
bool is_seed() const;
|
bool is_seed() const;
|
||||||
bool is_checking() const;
|
bool is_checking() const;
|
||||||
bool is_auto_managed() const;
|
|
||||||
bool is_sequential_download() const;
|
bool is_sequential_download() const;
|
||||||
qlonglong active_time() const;
|
|
||||||
qlonglong seeding_time() const;
|
|
||||||
QString creation_date() const;
|
QString creation_date() const;
|
||||||
QString next_announce() const;
|
|
||||||
qlonglong next_announce_s() const;
|
|
||||||
bool priv() const;
|
bool priv() const;
|
||||||
bool first_last_piece_first() const;
|
bool first_last_piece_first() const;
|
||||||
QString root_path() const;
|
QString root_path() const;
|
||||||
@ -119,7 +94,6 @@ public:
|
|||||||
QString error() const;
|
QString error() const;
|
||||||
void downloading_pieces(libtorrent::bitfield& bf) const;
|
void downloading_pieces(libtorrent::bitfield& bf) const;
|
||||||
bool has_metadata() const;
|
bool has_metadata() const;
|
||||||
float distributed_copies() const;
|
|
||||||
void file_progress(std::vector<libtorrent::size_type>& fp) const;
|
void file_progress(std::vector<libtorrent::size_type>& fp) const;
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -142,6 +116,13 @@ public:
|
|||||||
//
|
//
|
||||||
bool operator ==(const QTorrentHandle& new_h) const;
|
bool operator ==(const QTorrentHandle& new_h) const;
|
||||||
|
|
||||||
|
static bool is_paused(const libtorrent::torrent_status &status);
|
||||||
|
static bool is_queued(const libtorrent::torrent_status &status);
|
||||||
|
static bool is_seed(const libtorrent::torrent_status &status);
|
||||||
|
static bool is_checking(const libtorrent::torrent_status &status);
|
||||||
|
static bool has_error(const libtorrent::torrent_status &status);
|
||||||
|
static float progress(const libtorrent::torrent_status &status);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void prioritize_first_last_piece(int file_index, bool b) const;
|
void prioritize_first_last_piece(int file_index, bool b) const;
|
||||||
|
|
||||||
|
@ -37,8 +37,60 @@
|
|||||||
|
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
QIcon get_paused_icon()
|
||||||
|
{
|
||||||
|
static QIcon cached = QIcon(":/Icons/skin/paused.png");
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon get_queued_icon()
|
||||||
|
{
|
||||||
|
static QIcon cached = QIcon(":/Icons/skin/queued.png");
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon get_downloading_icon()
|
||||||
|
{
|
||||||
|
static QIcon cached = QIcon(":/Icons/skin/downloading.png");
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon get_stalled_downloading_icon()
|
||||||
|
{
|
||||||
|
static QIcon cached = QIcon(":/Icons/skin/stalledDL.png");
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon get_uploading_icon()
|
||||||
|
{
|
||||||
|
static QIcon cached = QIcon(":/Icons/skin/uploading.png");
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon get_stalled_uploading_icon()
|
||||||
|
{
|
||||||
|
static QIcon cached = QIcon(":/Icons/skin/stalledUP.png");
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon get_checking_icon()
|
||||||
|
{
|
||||||
|
static QIcon cached = QIcon(":/Icons/skin/checking.png");
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon get_error_icon()
|
||||||
|
{
|
||||||
|
static QIcon cached = QIcon(":/Icons/skin/error.png");
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TorrentModelItem::TorrentModelItem(const QTorrentHandle &h)
|
TorrentModelItem::TorrentModelItem(const QTorrentHandle &h)
|
||||||
: m_torrent(h)
|
: m_torrent(h)
|
||||||
|
, m_lastStatus(h.status(torrent_handle::query_accurate_download_counters))
|
||||||
, m_addedTime(TorrentPersistentData::getAddedDate(h.hash()))
|
, m_addedTime(TorrentPersistentData::getAddedDate(h.hash()))
|
||||||
, m_seedTime(TorrentPersistentData::getSeedDate(h.hash()))
|
, m_seedTime(TorrentPersistentData::getSeedDate(h.hash()))
|
||||||
, m_label(TorrentPersistentData::getLabel(h.hash()))
|
, m_label(TorrentPersistentData::getLabel(h.hash()))
|
||||||
@ -49,75 +101,80 @@ TorrentModelItem::TorrentModelItem(const QTorrentHandle &h)
|
|||||||
m_name = h.name();
|
m_name = h.name();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TorrentModelItem::refreshStatus(libtorrent::torrent_status const& status)
|
||||||
|
{
|
||||||
|
m_lastStatus = status;
|
||||||
|
}
|
||||||
|
|
||||||
TorrentModelItem::State TorrentModelItem::state() const
|
TorrentModelItem::State TorrentModelItem::state() const
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
// Pause or Queued
|
// Pause or Queued
|
||||||
if (m_torrent.is_paused()) {
|
if (m_torrent.is_paused(m_lastStatus)) {
|
||||||
m_icon = QIcon(":/Icons/skin/paused.png");
|
m_icon = get_paused_icon();
|
||||||
m_fgColor = QColor("red");
|
m_fgColor = QColor("red");
|
||||||
return m_torrent.is_seed() ? STATE_PAUSED_UP : STATE_PAUSED_DL;
|
return m_torrent.is_seed(m_lastStatus) ? STATE_PAUSED_UP : STATE_PAUSED_DL;
|
||||||
}
|
}
|
||||||
if (m_torrent.is_queued()) {
|
if (m_torrent.is_queued(m_lastStatus)) {
|
||||||
if (m_torrent.state() != torrent_status::queued_for_checking
|
if (m_lastStatus.state != torrent_status::queued_for_checking
|
||||||
&& m_torrent.state() != torrent_status::checking_resume_data
|
&& m_lastStatus.state != torrent_status::checking_resume_data
|
||||||
&& m_torrent.state() != torrent_status::checking_files) {
|
&& m_lastStatus.state != torrent_status::checking_files) {
|
||||||
m_icon = QIcon(":/Icons/skin/queued.png");
|
m_icon = get_queued_icon();
|
||||||
m_fgColor = QColor("grey");
|
m_fgColor = QColor("grey");
|
||||||
return m_torrent.is_seed() ? STATE_QUEUED_UP : STATE_QUEUED_DL;
|
return m_torrent.is_seed(m_lastStatus) ? STATE_QUEUED_UP : STATE_QUEUED_DL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Other states
|
// Other states
|
||||||
switch(m_torrent.state()) {
|
switch(m_lastStatus.state) {
|
||||||
case torrent_status::allocating:
|
case torrent_status::allocating:
|
||||||
m_icon = QIcon(":/Icons/skin/stalledDL.png");
|
m_icon = get_stalled_downloading_icon();
|
||||||
m_fgColor = QColor("grey");
|
m_fgColor = QColor("grey");
|
||||||
return STATE_ALLOCATING;
|
return STATE_ALLOCATING;
|
||||||
case torrent_status::downloading_metadata:
|
case torrent_status::downloading_metadata:
|
||||||
m_icon = QIcon(":/Icons/skin/downloading.png");
|
m_icon = get_downloading_icon();
|
||||||
m_fgColor = QColor("green");
|
m_fgColor = QColor("green");
|
||||||
return STATE_DOWNLOADING_META;
|
return STATE_DOWNLOADING_META;
|
||||||
case torrent_status::downloading: {
|
case torrent_status::downloading: {
|
||||||
if (m_torrent.download_payload_rate() > 0) {
|
if (m_lastStatus.download_payload_rate > 0) {
|
||||||
m_icon = QIcon(":/Icons/skin/downloading.png");
|
m_icon = get_downloading_icon();
|
||||||
m_fgColor = QColor("green");
|
m_fgColor = QColor("green");
|
||||||
return STATE_DOWNLOADING;
|
return STATE_DOWNLOADING;
|
||||||
} else {
|
} else {
|
||||||
m_icon = QIcon(":/Icons/skin/stalledDL.png");
|
m_icon = get_stalled_downloading_icon();
|
||||||
m_fgColor = QColor("grey");
|
m_fgColor = QColor("grey");
|
||||||
return STATE_STALLED_DL;
|
return STATE_STALLED_DL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case torrent_status::finished:
|
case torrent_status::finished:
|
||||||
case torrent_status::seeding:
|
case torrent_status::seeding:
|
||||||
if (m_torrent.upload_payload_rate() > 0) {
|
if (m_lastStatus.upload_payload_rate > 0) {
|
||||||
m_icon = QIcon(":/Icons/skin/uploading.png");
|
m_icon = get_uploading_icon();
|
||||||
m_fgColor = QColor("orange");
|
m_fgColor = QColor("orange");
|
||||||
return STATE_SEEDING;
|
return STATE_SEEDING;
|
||||||
} else {
|
} else {
|
||||||
m_icon = QIcon(":/Icons/skin/stalledUP.png");
|
m_icon = get_stalled_uploading_icon();
|
||||||
m_fgColor = QColor("grey");
|
m_fgColor = QColor("grey");
|
||||||
return STATE_STALLED_UP;
|
return STATE_STALLED_UP;
|
||||||
}
|
}
|
||||||
case torrent_status::queued_for_checking:
|
case torrent_status::queued_for_checking:
|
||||||
m_icon = QIcon(":/Icons/skin/checking.png");
|
m_icon = get_checking_icon();
|
||||||
m_fgColor = QColor("grey");
|
m_fgColor = QColor("grey");
|
||||||
return STATE_QUEUED_CHECK;
|
return STATE_QUEUED_CHECK;
|
||||||
case torrent_status::checking_resume_data:
|
case torrent_status::checking_resume_data:
|
||||||
m_icon = QIcon(":/Icons/skin/checking.png");
|
m_icon = get_checking_icon();
|
||||||
m_fgColor = QColor("grey");
|
m_fgColor = QColor("grey");
|
||||||
return STATE_QUEUED_FASTCHECK;
|
return STATE_QUEUED_FASTCHECK;
|
||||||
case torrent_status::checking_files:
|
case torrent_status::checking_files:
|
||||||
m_icon = QIcon(":/Icons/skin/checking.png");
|
m_icon = get_checking_icon();
|
||||||
m_fgColor = QColor("grey");
|
m_fgColor = QColor("grey");
|
||||||
return m_torrent.is_seed() ? STATE_CHECKING_UP : STATE_CHECKING_DL;
|
return m_torrent.is_seed(m_lastStatus) ? STATE_CHECKING_UP : STATE_CHECKING_DL;
|
||||||
default:
|
default:
|
||||||
m_icon = QIcon(":/Icons/skin/error.png");
|
m_icon = get_error_icon();
|
||||||
m_fgColor = QColor("red");
|
m_fgColor = QColor("red");
|
||||||
return STATE_INVALID;
|
return STATE_INVALID;
|
||||||
}
|
}
|
||||||
} catch(invalid_handle&) {
|
} catch(invalid_handle&) {
|
||||||
m_icon = QIcon(":/Icons/skin/error.png");
|
m_icon = get_error_icon();
|
||||||
m_fgColor = QColor("red");
|
m_fgColor = QColor("red");
|
||||||
return STATE_INVALID;
|
return STATE_INVALID;
|
||||||
}
|
}
|
||||||
@ -173,28 +230,28 @@ QVariant TorrentModelItem::data(int column, int role) const
|
|||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
case TR_SIZE:
|
case TR_SIZE:
|
||||||
return m_torrent.has_metadata() ? static_cast<qlonglong>(m_torrent.actual_size()) : -1;
|
return m_lastStatus.has_metadata ? static_cast<qlonglong>(m_lastStatus.total_wanted) : -1;
|
||||||
case TR_PROGRESS:
|
case TR_PROGRESS:
|
||||||
return m_torrent.progress();
|
return m_torrent.progress(m_lastStatus);
|
||||||
case TR_STATUS:
|
case TR_STATUS:
|
||||||
return state();
|
return state();
|
||||||
case TR_SEEDS: {
|
case TR_SEEDS: {
|
||||||
return (role == Qt::DisplayRole) ? m_torrent.num_seeds() : m_torrent.num_complete();
|
return (role == Qt::DisplayRole) ? m_lastStatus.num_seeds : m_lastStatus.num_complete;
|
||||||
}
|
}
|
||||||
case TR_PEERS: {
|
case TR_PEERS: {
|
||||||
return (role == Qt::DisplayRole) ? (m_torrent.num_peers()-m_torrent.num_seeds()) : m_torrent.num_incomplete();
|
return (role == Qt::DisplayRole) ? (m_lastStatus.num_peers-m_lastStatus.num_seeds) : m_lastStatus.num_incomplete;
|
||||||
}
|
}
|
||||||
case TR_DLSPEED:
|
case TR_DLSPEED:
|
||||||
return m_torrent.download_payload_rate();
|
return m_lastStatus.download_payload_rate;
|
||||||
case TR_UPSPEED:
|
case TR_UPSPEED:
|
||||||
return m_torrent.upload_payload_rate();
|
return m_lastStatus.upload_payload_rate;
|
||||||
case TR_ETA: {
|
case TR_ETA: {
|
||||||
// XXX: Is this correct?
|
// XXX: Is this correct?
|
||||||
if (m_torrent.is_paused() || m_torrent.is_queued()) return MAX_ETA;
|
if (m_torrent.is_paused(m_lastStatus) || m_torrent.is_queued(m_lastStatus)) return MAX_ETA;
|
||||||
return QBtSession::instance()->getETA(m_torrent.hash());
|
return QBtSession::instance()->getETA(m_hash, m_lastStatus);
|
||||||
}
|
}
|
||||||
case TR_RATIO:
|
case TR_RATIO:
|
||||||
return QBtSession::instance()->getRealRatio(m_torrent.hash());
|
return QBtSession::instance()->getRealRatio(m_lastStatus);
|
||||||
case TR_LABEL:
|
case TR_LABEL:
|
||||||
return m_label;
|
return m_label;
|
||||||
case TR_ADD_DATE:
|
case TR_ADD_DATE:
|
||||||
@ -202,19 +259,19 @@ QVariant TorrentModelItem::data(int column, int role) const
|
|||||||
case TR_SEED_DATE:
|
case TR_SEED_DATE:
|
||||||
return m_seedTime;
|
return m_seedTime;
|
||||||
case TR_TRACKER:
|
case TR_TRACKER:
|
||||||
return m_torrent.current_tracker();
|
return misc::toQString(m_lastStatus.current_tracker);
|
||||||
case TR_DLLIMIT:
|
case TR_DLLIMIT:
|
||||||
return m_torrent.download_limit();
|
return m_torrent.download_limit();
|
||||||
case TR_UPLIMIT:
|
case TR_UPLIMIT:
|
||||||
return m_torrent.upload_limit();
|
return m_torrent.upload_limit();
|
||||||
case TR_AMOUNT_DOWNLOADED:
|
case TR_AMOUNT_DOWNLOADED:
|
||||||
return static_cast<qlonglong>(m_torrent.all_time_download());
|
return static_cast<qlonglong>(m_lastStatus.all_time_download);
|
||||||
case TR_AMOUNT_UPLOADED:
|
case TR_AMOUNT_UPLOADED:
|
||||||
return static_cast<qlonglong>(m_torrent.all_time_upload());
|
return static_cast<qlonglong>(m_lastStatus.all_time_upload);
|
||||||
case TR_AMOUNT_LEFT:
|
case TR_AMOUNT_LEFT:
|
||||||
return static_cast<qlonglong>(m_torrent.total_wanted() - m_torrent.total_wanted_done());
|
return static_cast<qlonglong>(m_lastStatus.total_wanted - m_lastStatus.total_wanted_done);
|
||||||
case TR_TIME_ELAPSED:
|
case TR_TIME_ELAPSED:
|
||||||
return (role == Qt::DisplayRole) ? m_torrent.active_time() : m_torrent.seeding_time();
|
return (role == Qt::DisplayRole) ? m_lastStatus.active_time : m_lastStatus.seeding_time;
|
||||||
case TR_SAVE_PATH:
|
case TR_SAVE_PATH:
|
||||||
return fsutils::toNativePath(m_torrent.save_path_parsed());
|
return fsutils::toNativePath(m_torrent.save_path_parsed());
|
||||||
default:
|
default:
|
||||||
@ -250,6 +307,7 @@ void TorrentModel::populate() {
|
|||||||
connect(QBtSession::instance(), SIGNAL(resumedTorrent(QTorrentHandle)), SLOT(handleTorrentUpdate(QTorrentHandle)));
|
connect(QBtSession::instance(), SIGNAL(resumedTorrent(QTorrentHandle)), SLOT(handleTorrentUpdate(QTorrentHandle)));
|
||||||
connect(QBtSession::instance(), SIGNAL(pausedTorrent(QTorrentHandle)), SLOT(handleTorrentUpdate(QTorrentHandle)));
|
connect(QBtSession::instance(), SIGNAL(pausedTorrent(QTorrentHandle)), SLOT(handleTorrentUpdate(QTorrentHandle)));
|
||||||
connect(QBtSession::instance(), SIGNAL(torrentFinishedChecking(QTorrentHandle)), SLOT(handleTorrentUpdate(QTorrentHandle)));
|
connect(QBtSession::instance(), SIGNAL(torrentFinishedChecking(QTorrentHandle)), SLOT(handleTorrentUpdate(QTorrentHandle)));
|
||||||
|
connect(QBtSession::instance(), SIGNAL(stateUpdate(std::vector<libtorrent::torrent_status>)), SLOT(stateUpdated(std::vector<libtorrent::torrent_status>)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TorrentModel::~TorrentModel() {
|
TorrentModel::~TorrentModel() {
|
||||||
@ -382,6 +440,7 @@ void TorrentModel::handleTorrentUpdate(const QTorrentHandle &h)
|
|||||||
{
|
{
|
||||||
const int row = torrentRow(h.hash());
|
const int row = torrentRow(h.hash());
|
||||||
if (row >= 0) {
|
if (row >= 0) {
|
||||||
|
m_torrents[row]->refreshStatus(h.status(torrent_handle::query_accurate_download_counters));
|
||||||
notifyTorrentChanged(row);
|
notifyTorrentChanged(row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -394,6 +453,7 @@ void TorrentModel::handleFinishedTorrent(const QTorrentHandle& h)
|
|||||||
|
|
||||||
// Update completion date
|
// Update completion date
|
||||||
m_torrents[row]->setData(TorrentModelItem::TR_SEED_DATE, QDateTime::currentDateTime(), Qt::DisplayRole);
|
m_torrents[row]->setData(TorrentModelItem::TR_SEED_DATE, QDateTime::currentDateTime(), Qt::DisplayRole);
|
||||||
|
m_torrents[row]->refreshStatus(h.status(torrent_handle::query_accurate_download_counters));
|
||||||
notifyTorrentChanged(row);
|
notifyTorrentChanged(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,6 +474,7 @@ void TorrentModel::setRefreshInterval(int refreshInterval)
|
|||||||
void TorrentModel::forceModelRefresh()
|
void TorrentModel::forceModelRefresh()
|
||||||
{
|
{
|
||||||
emit dataChanged(index(0, 0), index(rowCount()-1, columnCount()-1));
|
emit dataChanged(index(0, 0), index(rowCount()-1, columnCount()-1));
|
||||||
|
QBtSession::instance()->postTorrentUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
TorrentStatusReport TorrentModel::getTorrentStatusReport() const
|
TorrentStatusReport TorrentModel::getTorrentStatusReport() const
|
||||||
@ -488,6 +549,20 @@ void TorrentModel::handleTorrentAboutToBeRemoved(const QTorrentHandle &h)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TorrentModel::stateUpdated(const std::vector<libtorrent::torrent_status> &statuses)
|
||||||
|
{
|
||||||
|
typedef std::vector<libtorrent::torrent_status> statuses_t;
|
||||||
|
|
||||||
|
for (statuses_t::const_iterator i = statuses.begin(), end = statuses.end(); i != end; ++i)
|
||||||
|
{
|
||||||
|
libtorrent::torrent_status const& status = *i;
|
||||||
|
|
||||||
|
const int row = torrentRow(misc::toQString(status.handle.info_hash()));
|
||||||
|
if (row >= 0)
|
||||||
|
m_torrents[row]->refreshStatus(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool TorrentModel::inhibitSystem()
|
bool TorrentModel::inhibitSystem()
|
||||||
{
|
{
|
||||||
QList<TorrentModelItem*>::const_iterator it = m_torrents.constBegin();
|
QList<TorrentModelItem*>::const_iterator it = m_torrents.constBegin();
|
||||||
|
@ -53,6 +53,7 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
TorrentModelItem(const QTorrentHandle& h);
|
TorrentModelItem(const QTorrentHandle& h);
|
||||||
|
void refreshStatus(libtorrent::torrent_status const& status);
|
||||||
inline int columnCount() const { return NB_COLUMNS; }
|
inline int columnCount() const { return NB_COLUMNS; }
|
||||||
QVariant data(int column, int role = Qt::DisplayRole) const;
|
QVariant data(int column, int role = Qt::DisplayRole) const;
|
||||||
bool setData(int column, const QVariant &value, int role = Qt::DisplayRole);
|
bool setData(int column, const QVariant &value, int role = Qt::DisplayRole);
|
||||||
@ -66,6 +67,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QTorrentHandle m_torrent;
|
QTorrentHandle m_torrent;
|
||||||
|
libtorrent::torrent_status m_lastStatus;
|
||||||
QDateTime m_addedTime;
|
QDateTime m_addedTime;
|
||||||
QDateTime m_seedTime;
|
QDateTime m_seedTime;
|
||||||
QString m_label;
|
QString m_label;
|
||||||
@ -110,6 +112,7 @@ private slots:
|
|||||||
void forceModelRefresh();
|
void forceModelRefresh();
|
||||||
void handleTorrentLabelChange(QString previous, QString current);
|
void handleTorrentLabelChange(QString previous, QString current);
|
||||||
void handleTorrentAboutToBeRemoved(const QTorrentHandle & h);
|
void handleTorrentAboutToBeRemoved(const QTorrentHandle & h);
|
||||||
|
void stateUpdated(const std::vector<libtorrent::torrent_status> &statuses);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void beginInsertTorrent(int row);
|
void beginInsertTorrent(int row);
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
* Contact : chris@qbittorrent.org
|
* Contact : chris@qbittorrent.org
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QMutexLocker>
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -61,34 +60,16 @@ private:
|
|||||||
QList<Sample<int> > m_speedSamples;
|
QList<Sample<int> > m_speedSamples;
|
||||||
};
|
};
|
||||||
|
|
||||||
TorrentSpeedMonitor::TorrentSpeedMonitor(QBtSession* session) :
|
TorrentSpeedMonitor::TorrentSpeedMonitor(QBtSession* session)
|
||||||
QThread(session), m_abort(false), m_session(session),
|
: m_session(session)
|
||||||
sessionUL(0), sessionDL(0), lastWrite(0), dirty(false)
|
|
||||||
{
|
{
|
||||||
connect(m_session, SIGNAL(deletedTorrent(QString)), SLOT(removeSamples(QString)));
|
connect(m_session, SIGNAL(deletedTorrent(QString)), SLOT(removeSamples(QString)));
|
||||||
connect(m_session, SIGNAL(pausedTorrent(QTorrentHandle)), SLOT(removeSamples(QTorrentHandle)));
|
connect(m_session, SIGNAL(pausedTorrent(QTorrentHandle)), SLOT(removeSamples(QTorrentHandle)));
|
||||||
loadStats();
|
connect(m_session, SIGNAL(statsReceived(libtorrent::stats_alert)), SLOT(statsReceived(libtorrent::stats_alert)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TorrentSpeedMonitor::~TorrentSpeedMonitor() {
|
TorrentSpeedMonitor::~TorrentSpeedMonitor()
|
||||||
m_abort = true;
|
{}
|
||||||
m_abortCond.wakeOne();
|
|
||||||
wait();
|
|
||||||
if (dirty)
|
|
||||||
lastWrite = 0;
|
|
||||||
saveStats();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TorrentSpeedMonitor::run()
|
|
||||||
{
|
|
||||||
do {
|
|
||||||
m_mutex.lock();
|
|
||||||
getSamples();
|
|
||||||
saveStats();
|
|
||||||
m_abortCond.wait(&m_mutex, 1000);
|
|
||||||
m_mutex.unlock();
|
|
||||||
} while(!m_abort);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpeedSample::addSample(int speedDL, int speedUL)
|
void SpeedSample::addSample(int speedDL, int speedUL)
|
||||||
{
|
{
|
||||||
@ -130,16 +111,14 @@ void TorrentSpeedMonitor::removeSamples(const QTorrentHandle& h) {
|
|||||||
} catch(invalid_handle&) {}
|
} catch(invalid_handle&) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
qlonglong TorrentSpeedMonitor::getETA(const QString &hash) const
|
qlonglong TorrentSpeedMonitor::getETA(const QString &hash, const libtorrent::torrent_status &status) const
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&m_mutex);
|
if (QTorrentHandle::is_paused(status) || !m_samples.contains(hash))
|
||||||
QTorrentHandle h = m_session->getTorrentHandle(hash);
|
|
||||||
if (h.is_paused() || !m_samples.contains(hash))
|
|
||||||
return MAX_ETA;
|
return MAX_ETA;
|
||||||
|
|
||||||
const Sample<qreal> speed_average = m_samples[hash].average();
|
const Sample<qreal> speed_average = m_samples[hash].average();
|
||||||
|
|
||||||
if (h.is_seed()) {
|
if (QTorrentHandle::is_seed(status)) {
|
||||||
if (!speed_average.upload)
|
if (!speed_average.upload)
|
||||||
return MAX_ETA;
|
return MAX_ETA;
|
||||||
|
|
||||||
@ -148,99 +127,21 @@ qlonglong TorrentSpeedMonitor::getETA(const QString &hash) const
|
|||||||
if (max_ratio < 0)
|
if (max_ratio < 0)
|
||||||
return MAX_ETA;
|
return MAX_ETA;
|
||||||
|
|
||||||
libtorrent::size_type realDL = h.all_time_download();
|
libtorrent::size_type realDL = status.all_time_download;
|
||||||
if (realDL <= 0)
|
if (realDL <= 0)
|
||||||
realDL = h.total_wanted();
|
realDL = status.total_wanted;
|
||||||
|
|
||||||
return (realDL * max_ratio - h.all_time_upload()) / speed_average.upload;
|
return (realDL * max_ratio - status.all_time_upload) / speed_average.upload;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!speed_average.download)
|
if (!speed_average.download)
|
||||||
return MAX_ETA;
|
return MAX_ETA;
|
||||||
|
|
||||||
return (h.total_wanted() - h.total_wanted_done()) / speed_average.download;
|
return (status.total_wanted - status.total_wanted_done) / speed_average.download;
|
||||||
}
|
}
|
||||||
|
|
||||||
quint64 TorrentSpeedMonitor::getAlltimeDL() const {
|
void TorrentSpeedMonitor::statsReceived(const stats_alert &stats)
|
||||||
QMutexLocker l(&m_mutex);
|
|
||||||
return alltimeDL + sessionDL;
|
|
||||||
}
|
|
||||||
|
|
||||||
quint64 TorrentSpeedMonitor::getAlltimeUL() const {
|
|
||||||
QMutexLocker l(&m_mutex);
|
|
||||||
return alltimeUL + sessionUL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TorrentSpeedMonitor::getSamples()
|
|
||||||
{
|
{
|
||||||
const std::vector<torrent_handle> torrents = m_session->getSession()->get_torrents();
|
m_samples[misc::toQString(stats.handle.info_hash())].addSample(stats.transferred[stats_alert::download_payload] * 1000 / stats.interval,
|
||||||
|
stats.transferred[stats_alert::upload_payload] * 1000 / stats.interval);
|
||||||
std::vector<torrent_handle>::const_iterator it = torrents.begin();
|
|
||||||
std::vector<torrent_handle>::const_iterator itend = torrents.end();
|
|
||||||
for ( ; it != itend; ++it) {
|
|
||||||
try {
|
|
||||||
torrent_status st = it->status(0x0);
|
|
||||||
if (!st.paused) {
|
|
||||||
int up = st.upload_payload_rate;
|
|
||||||
int down = st.download_payload_rate;
|
|
||||||
m_samples[misc::toQString(it->info_hash())].addSample(down, up);
|
|
||||||
}
|
|
||||||
} catch(invalid_handle&) {}
|
|
||||||
}
|
|
||||||
libtorrent::session_status ss = m_session->getSessionStatus();
|
|
||||||
if (ss.total_download > sessionDL) {
|
|
||||||
sessionDL = ss.total_download;
|
|
||||||
dirty = true;
|
|
||||||
}
|
|
||||||
if (ss.total_upload > sessionUL) {
|
|
||||||
sessionUL = ss.total_upload;
|
|
||||||
dirty = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TorrentSpeedMonitor::saveStats() const {
|
|
||||||
if (!(dirty && (QDateTime::currentMSecsSinceEpoch() - lastWrite >= 15*60*1000) ))
|
|
||||||
return;
|
|
||||||
QIniSettings s("qBittorrent", "qBittorrent-data");
|
|
||||||
QVariantHash v;
|
|
||||||
v.insert("AlltimeDL", alltimeDL + sessionDL);
|
|
||||||
v.insert("AlltimeUL", alltimeUL + sessionUL);
|
|
||||||
s.setValue("Stats/AllStats", v);
|
|
||||||
dirty = false;
|
|
||||||
lastWrite = QDateTime::currentMSecsSinceEpoch();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TorrentSpeedMonitor::loadStats() {
|
|
||||||
// Temp code. Versions v3.1.4 and v3.1.5 saved the data in the qbittorrent.ini file.
|
|
||||||
// This code reads the data from there, writes it to the new file, and removes the keys
|
|
||||||
// from the old file. This code should be removed after some time has passed.
|
|
||||||
// e.g. When we reach v3.3.0
|
|
||||||
QIniSettings s_old;
|
|
||||||
QIniSettings s("qBittorrent", "qBittorrent-data");
|
|
||||||
QVariantHash v;
|
|
||||||
|
|
||||||
// Let's test if the qbittorrent.ini holds the key
|
|
||||||
if (s_old.contains("Stats/AllStats")) {
|
|
||||||
v = s_old.value("Stats/AllStats").toHash();
|
|
||||||
dirty = true;
|
|
||||||
|
|
||||||
// If the user has used qbt > 3.1.5 and then reinstalled/used
|
|
||||||
// qbt < 3.1.6, there will be stats in qbittorrent-data.ini too
|
|
||||||
// so we need to merge those 2.
|
|
||||||
if (s.contains("Stats/AllStats")) {
|
|
||||||
QVariantHash tmp = s.value("Stats/AllStats").toHash();
|
|
||||||
v["AlltimeDL"] = v["AlltimeDL"].toULongLong() + tmp["AlltimeDL"].toULongLong();
|
|
||||||
v["AlltimeUL"] = v["AlltimeUL"].toULongLong() + tmp["AlltimeUL"].toULongLong();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
v = s.value("Stats/AllStats").toHash();
|
|
||||||
|
|
||||||
alltimeDL = v["AlltimeDL"].toULongLong();
|
|
||||||
alltimeUL = v["AlltimeUL"].toULongLong();
|
|
||||||
|
|
||||||
if (dirty) {
|
|
||||||
saveStats();
|
|
||||||
s_old.remove("Stats/AllStats");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -32,51 +32,31 @@
|
|||||||
#define TORRENTSPEEDMONITOR_H
|
#define TORRENTSPEEDMONITOR_H
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QThread>
|
|
||||||
#include <QWaitCondition>
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QMutex>
|
|
||||||
#include "qtorrenthandle.h"
|
#include "qtorrenthandle.h"
|
||||||
|
#include <libtorrent/alert_types.hpp>
|
||||||
|
|
||||||
class QBtSession;
|
class QBtSession;
|
||||||
class SpeedSample;
|
class SpeedSample;
|
||||||
|
|
||||||
class TorrentSpeedMonitor : public QThread
|
class TorrentSpeedMonitor : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_DISABLE_COPY(TorrentSpeedMonitor)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit TorrentSpeedMonitor(QBtSession* session);
|
explicit TorrentSpeedMonitor(QBtSession* session);
|
||||||
~TorrentSpeedMonitor();
|
~TorrentSpeedMonitor();
|
||||||
qlonglong getETA(const QString &hash) const;
|
qlonglong getETA(const QString &hash, const libtorrent::torrent_status &status) const;
|
||||||
quint64 getAlltimeDL() const;
|
|
||||||
quint64 getAlltimeUL() const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void run();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void getSamples();
|
|
||||||
void saveStats() const;
|
|
||||||
void loadStats();
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
void statsReceived(const libtorrent::stats_alert& stats);
|
||||||
void removeSamples(const QString& hash);
|
void removeSamples(const QString& hash);
|
||||||
void removeSamples(const QTorrentHandle& h);
|
void removeSamples(const QTorrentHandle& h);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_abort;
|
|
||||||
QWaitCondition m_abortCond;
|
|
||||||
QHash<QString, SpeedSample> m_samples;
|
QHash<QString, SpeedSample> m_samples;
|
||||||
mutable QMutex m_mutex;
|
|
||||||
QBtSession *m_session;
|
QBtSession *m_session;
|
||||||
// Will overflow at 15.9 EiB
|
|
||||||
quint64 alltimeUL;
|
|
||||||
quint64 alltimeDL;
|
|
||||||
qint64 sessionUL;
|
|
||||||
qint64 sessionDL;
|
|
||||||
mutable qint64 lastWrite;
|
|
||||||
mutable bool dirty;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TORRENTSPEEDMONITOR_H
|
#endif // TORRENTSPEEDMONITOR_H
|
||||||
|
95
src/qtlibtorrent/torrentstatistics.cpp
Normal file
95
src/qtlibtorrent/torrentstatistics.cpp
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#include "torrentstatistics.h"
|
||||||
|
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
|
#include <libtorrent/session.hpp>
|
||||||
|
|
||||||
|
#include "qbtsession.h"
|
||||||
|
#include "qinisettings.h"
|
||||||
|
|
||||||
|
TorrentStatistics::TorrentStatistics(QBtSession* session, QObject* parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, m_session(session)
|
||||||
|
, m_sessionUL(0)
|
||||||
|
, m_sessionDL(0)
|
||||||
|
, m_lastWrite(0)
|
||||||
|
, m_dirty(false) {
|
||||||
|
loadStats();
|
||||||
|
connect(&m_timer, SIGNAL(timeout()), this, SLOT(gatherStats()));
|
||||||
|
m_timer.start(60 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
TorrentStatistics::~TorrentStatistics() {
|
||||||
|
if (m_dirty)
|
||||||
|
m_lastWrite = 0;
|
||||||
|
saveStats();
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 TorrentStatistics::getAlltimeDL() const {
|
||||||
|
return m_alltimeDL + m_sessionDL;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 TorrentStatistics::getAlltimeUL() const {
|
||||||
|
return m_alltimeUL + m_sessionUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TorrentStatistics::gatherStats() {
|
||||||
|
libtorrent::session_status ss = m_session->getSessionStatus();
|
||||||
|
if (ss.total_download > m_sessionDL) {
|
||||||
|
m_sessionDL = ss.total_download;
|
||||||
|
m_dirty = true;
|
||||||
|
}
|
||||||
|
if (ss.total_upload > m_sessionUL) {
|
||||||
|
m_sessionUL = ss.total_upload;
|
||||||
|
m_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
saveStats();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TorrentStatistics::saveStats() const {
|
||||||
|
if (!(m_dirty && (QDateTime::currentMSecsSinceEpoch() - m_lastWrite >= 15*60*1000) ))
|
||||||
|
return;
|
||||||
|
QIniSettings s("qBittorrent", "qBittorrent-data");
|
||||||
|
QVariantHash v;
|
||||||
|
v.insert("AlltimeDL", m_alltimeDL + m_sessionDL);
|
||||||
|
v.insert("AlltimeUL", m_alltimeUL + m_sessionUL);
|
||||||
|
s.setValue("Stats/AllStats", v);
|
||||||
|
m_dirty = false;
|
||||||
|
m_lastWrite = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TorrentStatistics::loadStats() {
|
||||||
|
// Temp code. Versions v3.1.4 and v3.1.5 saved the data in the qbittorrent.ini file.
|
||||||
|
// This code reads the data from there, writes it to the new file, and removes the keys
|
||||||
|
// from the old file. This code should be removed after some time has passed.
|
||||||
|
// e.g. When we reach v3.3.0
|
||||||
|
QIniSettings s_old;
|
||||||
|
QIniSettings s("qBittorrent", "qBittorrent-data");
|
||||||
|
QVariantHash v;
|
||||||
|
|
||||||
|
// Let's test if the qbittorrent.ini holds the key
|
||||||
|
if (s_old.contains("Stats/AllStats")) {
|
||||||
|
v = s_old.value("Stats/AllStats").toHash();
|
||||||
|
m_dirty = true;
|
||||||
|
|
||||||
|
// If the user has used qbt > 3.1.5 and then reinstalled/used
|
||||||
|
// qbt < 3.1.6, there will be stats in qbittorrent-data.ini too
|
||||||
|
// so we need to merge those 2.
|
||||||
|
if (s.contains("Stats/AllStats")) {
|
||||||
|
QVariantHash tmp = s.value("Stats/AllStats").toHash();
|
||||||
|
v["AlltimeDL"] = v["AlltimeDL"].toULongLong() + tmp["AlltimeDL"].toULongLong();
|
||||||
|
v["AlltimeUL"] = v["AlltimeUL"].toULongLong() + tmp["AlltimeUL"].toULongLong();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
v = s.value("Stats/AllStats").toHash();
|
||||||
|
|
||||||
|
m_alltimeDL = v["AlltimeDL"].toULongLong();
|
||||||
|
m_alltimeUL = v["AlltimeUL"].toULongLong();
|
||||||
|
|
||||||
|
if (m_dirty) {
|
||||||
|
saveStats();
|
||||||
|
s_old.remove("Stats/AllStats");
|
||||||
|
}
|
||||||
|
}
|
41
src/qtlibtorrent/torrentstatistics.h
Normal file
41
src/qtlibtorrent/torrentstatistics.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#ifndef TORRENTSTATISTICS_H
|
||||||
|
#define TORRENTSTATISTICS_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
class QBtSession;
|
||||||
|
|
||||||
|
class TorrentStatistics : QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_DISABLE_COPY(TorrentStatistics)
|
||||||
|
|
||||||
|
public:
|
||||||
|
TorrentStatistics(QBtSession* session, QObject* parent = 0);
|
||||||
|
~TorrentStatistics();
|
||||||
|
|
||||||
|
quint64 getAlltimeDL() const;
|
||||||
|
quint64 getAlltimeUL() const;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void gatherStats();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void saveStats() const;
|
||||||
|
void loadStats();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QBtSession* m_session;
|
||||||
|
// Will overflow at 15.9 EiB
|
||||||
|
quint64 m_alltimeUL;
|
||||||
|
quint64 m_alltimeDL;
|
||||||
|
qint64 m_sessionUL;
|
||||||
|
qint64 m_sessionDL;
|
||||||
|
mutable qint64 m_lastWrite;
|
||||||
|
mutable bool m_dirty;
|
||||||
|
|
||||||
|
QTimer m_timer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TORRENTSTATISTICS_H
|
@ -78,9 +78,10 @@ public:
|
|||||||
case TorrentModelItem::TR_SEEDS:
|
case TorrentModelItem::TR_SEEDS:
|
||||||
case TorrentModelItem::TR_PEERS: {
|
case TorrentModelItem::TR_PEERS: {
|
||||||
QString display = QString::number(index.data().toLongLong());
|
QString display = QString::number(index.data().toLongLong());
|
||||||
if (index.data(Qt::UserRole).toLongLong() > 0) {
|
qlonglong total = index.data(Qt::UserRole).toLongLong();
|
||||||
|
if (total > 0) {
|
||||||
// Scrape was successful, we have total values
|
// Scrape was successful, we have total values
|
||||||
display += " ("+QString::number(index.data(Qt::UserRole).toLongLong())+")";
|
display += " ("+QString::number(total)+")";
|
||||||
}
|
}
|
||||||
QItemDelegate::drawBackground(painter, opt, index);
|
QItemDelegate::drawBackground(painter, opt, index);
|
||||||
QItemDelegate::drawDisplay(painter, opt, opt.rect, display);
|
QItemDelegate::drawDisplay(painter, opt, opt.rect, display);
|
||||||
|
@ -124,53 +124,55 @@ static const char KEY_TRANSFER_UPSPEED[] = "up_info";
|
|||||||
|
|
||||||
static JsonDict toJson(const QTorrentHandle& h)
|
static JsonDict toJson(const QTorrentHandle& h)
|
||||||
{
|
{
|
||||||
|
libtorrent::torrent_status status = h.status(torrent_handle::query_accurate_download_counters);
|
||||||
|
|
||||||
JsonDict ret;
|
JsonDict ret;
|
||||||
ret.add(KEY_TORRENT_HASH, h.hash());
|
ret.add(KEY_TORRENT_HASH, h.hash());
|
||||||
ret.add(KEY_TORRENT_NAME, h.name());
|
ret.add(KEY_TORRENT_NAME, h.name());
|
||||||
ret.add(KEY_TORRENT_SIZE, misc::friendlyUnit(h.actual_size())); // FIXME: Should pass as Number, not formatted String (for sorting).
|
ret.add(KEY_TORRENT_SIZE, misc::friendlyUnit(status.total_wanted)); // FIXME: Should pass as Number, not formatted String (for sorting).
|
||||||
ret.add(KEY_TORRENT_PROGRESS, (double)h.progress());
|
ret.add(KEY_TORRENT_PROGRESS, (double)h.progress(status));
|
||||||
ret.add(KEY_TORRENT_DLSPEED, misc::friendlyUnit(h.download_payload_rate(), true)); // FIXME: Should be passed as a Number
|
ret.add(KEY_TORRENT_DLSPEED, misc::friendlyUnit(status.download_payload_rate, true)); // FIXME: Should be passed as a Number
|
||||||
ret.add(KEY_TORRENT_UPSPEED, misc::friendlyUnit(h.upload_payload_rate(), true)); // FIXME: Should be passed as a Number
|
ret.add(KEY_TORRENT_UPSPEED, misc::friendlyUnit(status.upload_payload_rate, true)); // FIXME: Should be passed as a Number
|
||||||
if (QBtSession::instance()->isQueueingEnabled() && h.queue_position() >= 0)
|
if (QBtSession::instance()->isQueueingEnabled() && h.queue_position() >= 0)
|
||||||
ret.add(KEY_TORRENT_PRIORITY, QString::number(h.queue_position()));
|
ret.add(KEY_TORRENT_PRIORITY, QString::number(h.queue_position()));
|
||||||
else
|
else
|
||||||
ret.add(KEY_TORRENT_PRIORITY, "*");
|
ret.add(KEY_TORRENT_PRIORITY, "*");
|
||||||
QString seeds = QString::number(h.num_seeds());
|
QString seeds = QString::number(status.num_seeds);
|
||||||
if (h.num_complete() > 0)
|
if (status.num_complete > 0)
|
||||||
seeds += " ("+QString::number(h.num_complete())+")";
|
seeds += " ("+QString::number(status.num_complete)+")";
|
||||||
ret.add(KEY_TORRENT_SEEDS, seeds);
|
ret.add(KEY_TORRENT_SEEDS, seeds);
|
||||||
QString leechs = QString::number(h.num_peers() - h.num_seeds());
|
QString leechs = QString::number(status.num_peers - status.num_seeds);
|
||||||
if (h.num_incomplete() > 0)
|
if (status.num_incomplete > 0)
|
||||||
leechs += " ("+QString::number(h.num_incomplete())+")";
|
leechs += " ("+QString::number(status.num_incomplete)+")";
|
||||||
ret.add(KEY_TORRENT_LEECHS, leechs);
|
ret.add(KEY_TORRENT_LEECHS, leechs);
|
||||||
const qreal ratio = QBtSession::instance()->getRealRatio(h.hash());
|
const qreal ratio = QBtSession::instance()->getRealRatio(status);
|
||||||
ret.add(KEY_TORRENT_RATIO, (ratio > 100.) ? QString::fromUtf8("∞") : misc::accurateDoubleToString(ratio, 1));
|
ret.add(KEY_TORRENT_RATIO, (ratio > 100.) ? QString::fromUtf8("∞") : misc::accurateDoubleToString(ratio, 1));
|
||||||
QString eta;
|
QString eta;
|
||||||
QString state;
|
QString state;
|
||||||
if (h.is_paused()) {
|
if (h.is_paused(status)) {
|
||||||
if (h.has_error())
|
if (h.has_error(status))
|
||||||
state = "error";
|
state = "error";
|
||||||
else
|
else
|
||||||
state = h.is_seed() ? "pausedUP" : "pausedDL";
|
state = h.is_seed(status) ? "pausedUP" : "pausedDL";
|
||||||
} else {
|
} else {
|
||||||
if (QBtSession::instance()->isQueueingEnabled() && h.is_queued())
|
if (QBtSession::instance()->isQueueingEnabled() && h.is_queued(status))
|
||||||
state = h.is_seed() ? "queuedUP" : "queuedDL";
|
state = h.is_seed(status) ? "queuedUP" : "queuedDL";
|
||||||
else {
|
else {
|
||||||
switch (h.state()) {
|
switch (status.state) {
|
||||||
case torrent_status::finished:
|
case torrent_status::finished:
|
||||||
case torrent_status::seeding:
|
case torrent_status::seeding:
|
||||||
state = h.upload_payload_rate() > 0 ? "uploading" : "stalledUP";
|
state = status.upload_payload_rate > 0 ? "uploading" : "stalledUP";
|
||||||
break;
|
break;
|
||||||
case torrent_status::allocating:
|
case torrent_status::allocating:
|
||||||
case torrent_status::checking_files:
|
case torrent_status::checking_files:
|
||||||
case torrent_status::queued_for_checking:
|
case torrent_status::queued_for_checking:
|
||||||
case torrent_status::checking_resume_data:
|
case torrent_status::checking_resume_data:
|
||||||
state = h.is_seed() ? "checkingUP" : "checkingDL";
|
state = h.is_seed(status) ? "checkingUP" : "checkingDL";
|
||||||
break;
|
break;
|
||||||
case torrent_status::downloading:
|
case torrent_status::downloading:
|
||||||
case torrent_status::downloading_metadata:
|
case torrent_status::downloading_metadata:
|
||||||
state = h.download_payload_rate() > 0 ? "downloading" : "stalledDL";
|
state = status.download_payload_rate > 0 ? "downloading" : "stalledDL";
|
||||||
eta = misc::userFriendlyDuration(QBtSession::instance()->getETA(h.hash()));
|
eta = misc::userFriendlyDuration(QBtSession::instance()->getETA(h.hash(), status));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
qWarning("Unrecognized torrent status, should not happen!!! status was %d", h.state());
|
qWarning("Unrecognized torrent status, should not happen!!! status was %d", h.state());
|
||||||
@ -284,7 +286,9 @@ QString btjson::getPropertiesForTorrent(const QString& hash)
|
|||||||
try {
|
try {
|
||||||
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash);
|
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash);
|
||||||
|
|
||||||
if (!h.has_metadata())
|
libtorrent::torrent_status status = h.status(torrent_handle::query_accurate_download_counters);
|
||||||
|
|
||||||
|
if (!status.has_metadata)
|
||||||
return QString();
|
return QString();
|
||||||
|
|
||||||
// Save path
|
// Save path
|
||||||
@ -295,17 +299,17 @@ QString btjson::getPropertiesForTorrent(const QString& hash)
|
|||||||
data.add(KEY_PROP_CREATION_DATE, h.creation_date());
|
data.add(KEY_PROP_CREATION_DATE, h.creation_date());
|
||||||
data.add(KEY_PROP_PIECE_SIZE, misc::friendlyUnit(h.piece_length()));
|
data.add(KEY_PROP_PIECE_SIZE, misc::friendlyUnit(h.piece_length()));
|
||||||
data.add(KEY_PROP_COMMENT, h.comment());
|
data.add(KEY_PROP_COMMENT, h.comment());
|
||||||
data.add(KEY_PROP_WASTED, misc::friendlyUnit(h.total_failed_bytes() + h.total_redundant_bytes()));
|
data.add(KEY_PROP_WASTED, misc::friendlyUnit(status.total_failed_bytes + status.total_redundant_bytes));
|
||||||
data.add(KEY_PROP_UPLOADED, QString(misc::friendlyUnit(h.all_time_upload()) + " (" + misc::friendlyUnit(h.total_payload_upload()) + " " + tr("this session") + ")"));
|
data.add(KEY_PROP_UPLOADED, QString(misc::friendlyUnit(status.all_time_upload) + " (" + misc::friendlyUnit(status.total_payload_upload) + " " + tr("this session") + ")"));
|
||||||
data.add(KEY_PROP_DOWNLOADED, QString(misc::friendlyUnit(h.all_time_download()) + " (" + misc::friendlyUnit(h.total_payload_download()) + " " + tr("this session") + ")"));
|
data.add(KEY_PROP_DOWNLOADED, QString(misc::friendlyUnit(status.all_time_download) + " (" + misc::friendlyUnit(status.total_payload_download) + " " + tr("this session") + ")"));
|
||||||
data.add(KEY_PROP_UP_LIMIT, h.upload_limit() <= 0 ? QString::fromUtf8("∞") : misc::friendlyUnit(h.upload_limit(), true));
|
data.add(KEY_PROP_UP_LIMIT, h.upload_limit() <= 0 ? QString::fromUtf8("∞") : misc::friendlyUnit(h.upload_limit(), true));
|
||||||
data.add(KEY_PROP_DL_LIMIT, h.download_limit() <= 0 ? QString::fromUtf8("∞") : misc::friendlyUnit(h.download_limit(), true));
|
data.add(KEY_PROP_DL_LIMIT, h.download_limit() <= 0 ? QString::fromUtf8("∞") : misc::friendlyUnit(h.download_limit(), true));
|
||||||
QString elapsed_txt = misc::userFriendlyDuration(h.active_time());
|
QString elapsed_txt = misc::userFriendlyDuration(status.active_time);
|
||||||
if (h.is_seed())
|
if (h.is_seed(status))
|
||||||
elapsed_txt += " ("+tr("Seeded for %1", "e.g. Seeded for 3m10s").arg(misc::userFriendlyDuration(h.seeding_time()))+")";
|
elapsed_txt += " ("+tr("Seeded for %1", "e.g. Seeded for 3m10s").arg(misc::userFriendlyDuration(status.seeding_time))+")";
|
||||||
data.add(KEY_PROP_TIME_ELAPSED, elapsed_txt);
|
data.add(KEY_PROP_TIME_ELAPSED, elapsed_txt);
|
||||||
data.add(KEY_PROP_CONNECT_COUNT, QString(QString::number(h.num_connections()) + " (" + tr("%1 max", "e.g. 10 max").arg(QString::number(h.connections_limit())) + ")"));
|
data.add(KEY_PROP_CONNECT_COUNT, QString(QString::number(status.num_connections) + " (" + tr("%1 max", "e.g. 10 max").arg(QString::number(status.connections_limit)) + ")"));
|
||||||
const qreal ratio = QBtSession::instance()->getRealRatio(h.hash());
|
const qreal ratio = QBtSession::instance()->getRealRatio(status);
|
||||||
data.add(KEY_PROP_RATIO, ratio > 100. ? QString::fromUtf8("∞") : misc::accurateDoubleToString(ratio, 1));
|
data.add(KEY_PROP_RATIO, ratio > 100. ? QString::fromUtf8("∞") : misc::accurateDoubleToString(ratio, 1));
|
||||||
} catch(const std::exception& e) {
|
} catch(const std::exception& e) {
|
||||||
qWarning() << Q_FUNC_INFO << "Invalid torrent: " << e.what();
|
qWarning() << Q_FUNC_INFO << "Invalid torrent: " << e.what();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user