|
|
|
@ -29,12 +29,11 @@
@@ -29,12 +29,11 @@
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#include "btjson.h" |
|
|
|
|
#include "jsondict.h" |
|
|
|
|
#include "jsonlist.h" |
|
|
|
|
#include "misc.h" |
|
|
|
|
#include "fs_utils.h" |
|
|
|
|
#include "qbtsession.h" |
|
|
|
|
#include "torrentpersistentdata.h" |
|
|
|
|
#include "jsonutils.h" |
|
|
|
|
|
|
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) |
|
|
|
|
#include <QElapsedTimer> |
|
|
|
@ -49,20 +48,20 @@ using namespace libtorrent;
@@ -49,20 +48,20 @@ using namespace libtorrent;
|
|
|
|
|
static QElapsedTimer cacheTimer; \ |
|
|
|
|
static bool initialized = false; \ |
|
|
|
|
if (initialized && !cacheTimer.hasExpired(DUR)) \ |
|
|
|
|
return VAR.toString(); \ |
|
|
|
|
return json::toJson(VAR); \ |
|
|
|
|
initialized = true; \ |
|
|
|
|
cacheTimer.start(); \ |
|
|
|
|
VAR.clear() |
|
|
|
|
VAR = VARTYPE() |
|
|
|
|
|
|
|
|
|
#define CACHED_VARIABLE_FOR_HASH(VARTYPE, VAR, DUR, HASH) \ |
|
|
|
|
static VARTYPE VAR; \ |
|
|
|
|
static QString prev_hash; \ |
|
|
|
|
static QElapsedTimer cacheTimer; \ |
|
|
|
|
if (prev_hash == HASH && !cacheTimer.hasExpired(DUR)) \ |
|
|
|
|
return VAR.toString(); \ |
|
|
|
|
return json::toJson(VAR); \ |
|
|
|
|
prev_hash = HASH; \ |
|
|
|
|
cacheTimer.start(); \ |
|
|
|
|
VAR.clear() |
|
|
|
|
VAR = VARTYPE() |
|
|
|
|
|
|
|
|
|
#else |
|
|
|
|
// We don't support caching for Qt < 4.7 at the moment
|
|
|
|
@ -122,31 +121,31 @@ static const char KEY_FILE_IS_SEED[] = "is_seed";
@@ -122,31 +121,31 @@ static const char KEY_FILE_IS_SEED[] = "is_seed";
|
|
|
|
|
static const char KEY_TRANSFER_DLSPEED[] = "dl_info"; |
|
|
|
|
static const char KEY_TRANSFER_UPSPEED[] = "up_info"; |
|
|
|
|
|
|
|
|
|
static JsonDict toJson(const QTorrentHandle& h) |
|
|
|
|
static QVariantMap toMap(const QTorrentHandle& h) |
|
|
|
|
{ |
|
|
|
|
libtorrent::torrent_status status = h.status(torrent_handle::query_accurate_download_counters); |
|
|
|
|
|
|
|
|
|
JsonDict ret; |
|
|
|
|
ret.add(KEY_TORRENT_HASH, h.hash()); |
|
|
|
|
ret.add(KEY_TORRENT_NAME, h.name()); |
|
|
|
|
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(status)); |
|
|
|
|
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(status.upload_payload_rate, true)); // FIXME: Should be passed as a Number
|
|
|
|
|
QVariantMap ret; |
|
|
|
|
ret[KEY_TORRENT_HASH] = h.hash(); |
|
|
|
|
ret[KEY_TORRENT_NAME] = h.name(); |
|
|
|
|
ret[KEY_TORRENT_SIZE] = misc::friendlyUnit(h.actual_size()); // FIXME: Should pass as Number, not formatted String (for sorting).
|
|
|
|
|
ret[KEY_TORRENT_PROGRESS] = (double)h.progress(status); |
|
|
|
|
ret[KEY_TORRENT_DLSPEED] = misc::friendlyUnit(status.download_payload_rate, true); // FIXME: Should be passed as a Number
|
|
|
|
|
ret[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) |
|
|
|
|
ret.add(KEY_TORRENT_PRIORITY, QString::number(h.queue_position())); |
|
|
|
|
ret[KEY_TORRENT_PRIORITY] = QString::number(h.queue_position()); |
|
|
|
|
else |
|
|
|
|
ret.add(KEY_TORRENT_PRIORITY, "*"); |
|
|
|
|
ret[KEY_TORRENT_PRIORITY] = "*"; |
|
|
|
|
QString seeds = QString::number(status.num_seeds); |
|
|
|
|
if (status.num_complete > 0) |
|
|
|
|
seeds += " ("+QString::number(status.num_complete)+")"; |
|
|
|
|
ret.add(KEY_TORRENT_SEEDS, seeds); |
|
|
|
|
ret[KEY_TORRENT_SEEDS] = seeds; |
|
|
|
|
QString leechs = QString::number(status.num_peers - status.num_seeds); |
|
|
|
|
if (status.num_incomplete > 0) |
|
|
|
|
leechs += " ("+QString::number(status.num_incomplete)+")"; |
|
|
|
|
ret.add(KEY_TORRENT_LEECHS, leechs); |
|
|
|
|
ret[KEY_TORRENT_LEECHS] = leechs; |
|
|
|
|
const qreal ratio = QBtSession::instance()->getRealRatio(status); |
|
|
|
|
ret.add(KEY_TORRENT_RATIO, (ratio > 100.) ? QString::fromUtf8("∞") : misc::accurateDoubleToString(ratio, 1)); |
|
|
|
|
ret[KEY_TORRENT_RATIO] = (ratio > 100.) ? QString::fromUtf8("∞") : misc::accurateDoubleToString(ratio, 1); |
|
|
|
|
QString eta; |
|
|
|
|
QString state; |
|
|
|
|
if (h.is_paused(status)) { |
|
|
|
@ -179,8 +178,8 @@ static JsonDict toJson(const QTorrentHandle& h)
@@ -179,8 +178,8 @@ static JsonDict toJson(const QTorrentHandle& h)
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
ret.add(KEY_TORRENT_ETA, eta.isEmpty() ? QString::fromUtf8("∞") : eta); |
|
|
|
|
ret.add(KEY_TORRENT_STATE, state); |
|
|
|
|
ret[KEY_TORRENT_ETA] = eta.isEmpty() ? QString::fromUtf8("∞") : eta; |
|
|
|
|
ret[KEY_TORRENT_STATE] = state; |
|
|
|
|
|
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
@ -203,16 +202,16 @@ static JsonDict toJson(const QTorrentHandle& h)
@@ -203,16 +202,16 @@ static JsonDict toJson(const QTorrentHandle& h)
|
|
|
|
|
* - "eta": Torrent ETA |
|
|
|
|
* - "state": Torrent state |
|
|
|
|
*/ |
|
|
|
|
QString btjson::getTorrents() |
|
|
|
|
QByteArray btjson::getTorrents() |
|
|
|
|
{ |
|
|
|
|
CACHED_VARIABLE(JsonList, torrent_list, CACHE_DURATION_MS); |
|
|
|
|
CACHED_VARIABLE(QVariantList, torrent_list, CACHE_DURATION_MS); |
|
|
|
|
std::vector<torrent_handle> torrents = QBtSession::instance()->getTorrents(); |
|
|
|
|
std::vector<torrent_handle>::const_iterator it = torrents.begin(); |
|
|
|
|
std::vector<torrent_handle>::const_iterator end = torrents.end(); |
|
|
|
|
for( ; it != end; ++it) { |
|
|
|
|
torrent_list.append(toJson(QTorrentHandle(*it))); |
|
|
|
|
torrent_list.append(toMap(QTorrentHandle(*it))); |
|
|
|
|
} |
|
|
|
|
return torrent_list.toString(); |
|
|
|
|
return json::toJson(torrent_list); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -225,9 +224,9 @@ QString btjson::getTorrents()
@@ -225,9 +224,9 @@ QString btjson::getTorrents()
|
|
|
|
|
* - "num_peers": Tracker peer count |
|
|
|
|
* - "msg": Tracker message (last) |
|
|
|
|
*/ |
|
|
|
|
QString btjson::getTrackersForTorrent(const QString& hash) |
|
|
|
|
QByteArray btjson::getTrackersForTorrent(const QString& hash) |
|
|
|
|
{ |
|
|
|
|
CACHED_VARIABLE_FOR_HASH(JsonList, tracker_list, CACHE_DURATION_MS, hash); |
|
|
|
|
CACHED_VARIABLE_FOR_HASH(QVariantList, tracker_list, CACHE_DURATION_MS, hash); |
|
|
|
|
try { |
|
|
|
|
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
|
|
|
|
QHash<QString, TrackerInfos> trackers_data = QBtSession::instance()->getTrackersInfo(hash); |
|
|
|
@ -235,9 +234,9 @@ QString btjson::getTrackersForTorrent(const QString& hash)
@@ -235,9 +234,9 @@ QString btjson::getTrackersForTorrent(const QString& hash)
|
|
|
|
|
std::vector<announce_entry>::const_iterator it = vect_trackers.begin(); |
|
|
|
|
std::vector<announce_entry>::const_iterator end = vect_trackers.end(); |
|
|
|
|
for (; it != end; ++it) { |
|
|
|
|
JsonDict tracker_dict; |
|
|
|
|
QVariantMap tracker_dict; |
|
|
|
|
const QString tracker_url = misc::toQString(it->url); |
|
|
|
|
tracker_dict.add(KEY_TRACKER_URL, tracker_url); |
|
|
|
|
tracker_dict[KEY_TRACKER_URL] = tracker_url; |
|
|
|
|
const TrackerInfos data = trackers_data.value(tracker_url, TrackerInfos(tracker_url)); |
|
|
|
|
QString status; |
|
|
|
|
if (it->verified) |
|
|
|
@ -248,18 +247,18 @@ QString btjson::getTrackersForTorrent(const QString& hash)
@@ -248,18 +247,18 @@ QString btjson::getTrackersForTorrent(const QString& hash)
|
|
|
|
|
else |
|
|
|
|
status = it->fails > 0 ? tr("Not working") : tr("Not contacted yet"); |
|
|
|
|
} |
|
|
|
|
tracker_dict.add(KEY_TRACKER_STATUS, status); |
|
|
|
|
tracker_dict.add(KEY_TRACKER_PEERS, QString::number(trackers_data.value(tracker_url, TrackerInfos(tracker_url)).num_peers)); |
|
|
|
|
tracker_dict.add(KEY_TRACKER_MSG, data.last_message.trimmed()); |
|
|
|
|
tracker_dict[KEY_TRACKER_STATUS] = status; |
|
|
|
|
tracker_dict[KEY_TRACKER_PEERS] = QString::number(trackers_data.value(tracker_url, TrackerInfos(tracker_url)).num_peers); |
|
|
|
|
tracker_dict[KEY_TRACKER_MSG] = data.last_message.trimmed(); |
|
|
|
|
|
|
|
|
|
tracker_list.append(tracker_dict); |
|
|
|
|
} |
|
|
|
|
} catch(const std::exception& e) { |
|
|
|
|
qWarning() << Q_FUNC_INFO << "Invalid torrent: " << e.what(); |
|
|
|
|
return QString(); |
|
|
|
|
return QByteArray(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return tracker_list.toString(); |
|
|
|
|
return json::toJson(tracker_list); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -280,43 +279,42 @@ QString btjson::getTrackersForTorrent(const QString& hash)
@@ -280,43 +279,42 @@ QString btjson::getTrackersForTorrent(const QString& hash)
|
|
|
|
|
* - "nb_connections": Torrent connection count |
|
|
|
|
* - "share_ratio": Torrent share ratio |
|
|
|
|
*/ |
|
|
|
|
QString btjson::getPropertiesForTorrent(const QString& hash) |
|
|
|
|
QByteArray btjson::getPropertiesForTorrent(const QString& hash) |
|
|
|
|
{ |
|
|
|
|
CACHED_VARIABLE_FOR_HASH(JsonDict, data, CACHE_DURATION_MS, hash); |
|
|
|
|
CACHED_VARIABLE_FOR_HASH(QVariantMap, data, CACHE_DURATION_MS, hash); |
|
|
|
|
try { |
|
|
|
|
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
|
|
|
|
|
|
|
|
|
libtorrent::torrent_status status = h.status(torrent_handle::query_accurate_download_counters); |
|
|
|
|
|
|
|
|
|
if (!status.has_metadata) |
|
|
|
|
return QString(); |
|
|
|
|
return QByteArray(); |
|
|
|
|
|
|
|
|
|
// Save path
|
|
|
|
|
QString save_path = fsutils::toNativePath(TorrentPersistentData::getSavePath(hash)); |
|
|
|
|
if (save_path.isEmpty()) |
|
|
|
|
save_path = fsutils::toNativePath(h.save_path()); |
|
|
|
|
data.add(KEY_PROP_SAVE_PATH, save_path); |
|
|
|
|
data.add(KEY_PROP_CREATION_DATE, h.creation_date()); |
|
|
|
|
data.add(KEY_PROP_PIECE_SIZE, misc::friendlyUnit(h.piece_length())); |
|
|
|
|
data.add(KEY_PROP_COMMENT, h.comment()); |
|
|
|
|
data.add(KEY_PROP_WASTED, misc::friendlyUnit(status.total_failed_bytes + status.total_redundant_bytes)); |
|
|
|
|
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(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_DL_LIMIT, h.download_limit() <= 0 ? QString::fromUtf8("∞") : misc::friendlyUnit(h.download_limit(), true)); |
|
|
|
|
data[KEY_PROP_SAVE_PATH] = save_path; |
|
|
|
|
data[KEY_PROP_CREATION_DATE] = h.creation_date(); |
|
|
|
|
data[KEY_PROP_PIECE_SIZE] = misc::friendlyUnit(h.piece_length()); |
|
|
|
|
data[KEY_PROP_COMMENT] = h.comment(); |
|
|
|
|
data[KEY_PROP_WASTED] = misc::friendlyUnit(status.total_failed_bytes + status.total_redundant_bytes); |
|
|
|
|
data[KEY_PROP_UPLOADED] = QString(misc::friendlyUnit(status.all_time_upload) + " (" + misc::friendlyUnit(status.total_payload_upload) + " " + tr("this session") + ")"); |
|
|
|
|
data[KEY_PROP_DOWNLOADED] = QString(misc::friendlyUnit(status.all_time_download) + " (" + misc::friendlyUnit(status.total_payload_download) + " " + tr("this session") + ")"); |
|
|
|
|
data[KEY_PROP_UP_LIMIT] = h.upload_limit() <= 0 ? QString::fromUtf8("∞") : misc::friendlyUnit(h.upload_limit(), true); |
|
|
|
|
data[KEY_PROP_DL_LIMIT] = h.download_limit() <= 0 ? QString::fromUtf8("∞") : misc::friendlyUnit(h.download_limit(), true); |
|
|
|
|
QString elapsed_txt = misc::userFriendlyDuration(status.active_time); |
|
|
|
|
if (h.is_seed(status)) |
|
|
|
|
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_CONNECT_COUNT, QString(QString::number(status.num_connections) + " (" + tr("%1 max", "e.g. 10 max").arg(QString::number(status.connections_limit)) + ")")); |
|
|
|
|
data[KEY_PROP_TIME_ELAPSED] = elapsed_txt; |
|
|
|
|
data[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(status); |
|
|
|
|
data.add(KEY_PROP_RATIO, ratio > 100. ? QString::fromUtf8("∞") : misc::accurateDoubleToString(ratio, 1)); |
|
|
|
|
data[KEY_PROP_RATIO] = ratio > 100. ? QString::fromUtf8("∞") : misc::accurateDoubleToString(ratio, 1); |
|
|
|
|
} catch(const std::exception& e) { |
|
|
|
|
qWarning() << Q_FUNC_INFO << "Invalid torrent: " << e.what(); |
|
|
|
|
return QString(); |
|
|
|
|
return QByteArray(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return data.toString(); |
|
|
|
|
return json::toJson(data); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -330,38 +328,38 @@ QString btjson::getPropertiesForTorrent(const QString& hash)
@@ -330,38 +328,38 @@ QString btjson::getPropertiesForTorrent(const QString& hash)
|
|
|
|
|
* - "priority": File priority |
|
|
|
|
* - "is_seed": Flag indicating if torrent is seeding/complete |
|
|
|
|
*/ |
|
|
|
|
QString btjson::getFilesForTorrent(const QString& hash) |
|
|
|
|
QByteArray btjson::getFilesForTorrent(const QString& hash) |
|
|
|
|
{ |
|
|
|
|
CACHED_VARIABLE_FOR_HASH(JsonList, file_list, CACHE_DURATION_MS, hash); |
|
|
|
|
CACHED_VARIABLE_FOR_HASH(QVariantList, file_list, CACHE_DURATION_MS, hash); |
|
|
|
|
try { |
|
|
|
|
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
|
|
|
|
if (!h.has_metadata()) |
|
|
|
|
return QString(); |
|
|
|
|
return QByteArray(); |
|
|
|
|
|
|
|
|
|
const std::vector<int> priorities = h.file_priorities(); |
|
|
|
|
std::vector<size_type> fp; |
|
|
|
|
h.file_progress(fp); |
|
|
|
|
for (int i = 0; i < h.num_files(); ++i) { |
|
|
|
|
JsonDict file_dict; |
|
|
|
|
QVariantMap file_dict; |
|
|
|
|
QString fileName = h.filename_at(i); |
|
|
|
|
if (fileName.endsWith(".!qB", Qt::CaseInsensitive)) |
|
|
|
|
fileName.chop(4); |
|
|
|
|
file_dict.add(KEY_FILE_NAME, fsutils::toNativePath(fileName)); |
|
|
|
|
file_dict[KEY_FILE_NAME] = fsutils::toNativePath(fileName); |
|
|
|
|
const size_type size = h.filesize_at(i); |
|
|
|
|
file_dict.add(KEY_FILE_SIZE, misc::friendlyUnit(size)); |
|
|
|
|
file_dict.add(KEY_FILE_PROGRESS, (size > 0) ? (fp[i] / (double) size) : 1.); |
|
|
|
|
file_dict.add(KEY_FILE_PRIORITY, priorities[i]); |
|
|
|
|
file_dict[KEY_FILE_SIZE] = misc::friendlyUnit(size); |
|
|
|
|
file_dict[KEY_FILE_PROGRESS] = (size > 0) ? (fp[i] / (double) size) : 1.; |
|
|
|
|
file_dict[KEY_FILE_PRIORITY] = priorities[i]; |
|
|
|
|
if (i == 0) |
|
|
|
|
file_dict.add(KEY_FILE_IS_SEED, h.is_seed()); |
|
|
|
|
file_dict[KEY_FILE_IS_SEED] = h.is_seed(); |
|
|
|
|
|
|
|
|
|
file_list.append(file_dict); |
|
|
|
|
} |
|
|
|
|
} catch (const std::exception& e) { |
|
|
|
|
qWarning() << Q_FUNC_INFO << "Invalid torrent: " << e.what(); |
|
|
|
|
return QString(); |
|
|
|
|
return QByteArray(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return file_list.toString(); |
|
|
|
|
return json::toJson(file_list); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -372,11 +370,11 @@ QString btjson::getFilesForTorrent(const QString& hash)
@@ -372,11 +370,11 @@ QString btjson::getFilesForTorrent(const QString& hash)
|
|
|
|
|
* - "dl_info": Global download info |
|
|
|
|
* - "up_info": Global upload info |
|
|
|
|
*/ |
|
|
|
|
QString btjson::getTransferInfo() |
|
|
|
|
QByteArray btjson::getTransferInfo() |
|
|
|
|
{ |
|
|
|
|
CACHED_VARIABLE(JsonDict, info, CACHE_DURATION_MS); |
|
|
|
|
CACHED_VARIABLE(QVariantMap, info, CACHE_DURATION_MS); |
|
|
|
|
session_status sessionStatus = QBtSession::instance()->getSessionStatus(); |
|
|
|
|
info.add(KEY_TRANSFER_DLSPEED, tr("D: %1/s - T: %2", "Download speed: x KiB/s - Transferred: x MiB").arg(misc::friendlyUnit(sessionStatus.payload_download_rate)).arg(misc::friendlyUnit(sessionStatus.total_payload_download))); |
|
|
|
|
info.add(KEY_TRANSFER_UPSPEED, tr("U: %1/s - T: %2", "Upload speed: x KiB/s - Transferred: x MiB").arg(misc::friendlyUnit(sessionStatus.payload_upload_rate)).arg(misc::friendlyUnit(sessionStatus.total_payload_upload))); |
|
|
|
|
return info.toString(); |
|
|
|
|
info[KEY_TRANSFER_DLSPEED] = tr("D: %1/s - T: %2", "Download speed: x KiB/s - Transferred: x MiB").arg(misc::friendlyUnit(sessionStatus.payload_download_rate)).arg(misc::friendlyUnit(sessionStatus.total_payload_download)); |
|
|
|
|
info[KEY_TRANSFER_UPSPEED] = tr("U: %1/s - T: %2", "Upload speed: x KiB/s - Transferred: x MiB").arg(misc::friendlyUnit(sessionStatus.payload_upload_rate)).arg(misc::friendlyUnit(sessionStatus.total_payload_upload)); |
|
|
|
|
return json::toJson(info); |
|
|
|
|
} |
|
|
|
|