void TorrentPersistentData::saveSeedStatus(const QTorrentHandle &h) { QHash<QString, QVariant> data = all_data[h.hash()].toHash(); bool was_seed = data.value("seed", false).toBool(); if (was_seed != h.is_seed()) { data["seed"] = !was_seed; all_data[h.hash()] = data; markDirty(); } }
TorrentModelItem::TorrentModelItem(const QTorrentHandle &h) : m_torrent(h) , m_addedTime(TorrentPersistentData::getAddedDate(h.hash())) , m_seedTime(TorrentPersistentData::getSeedDate(h.hash())) , m_label(TorrentPersistentData::getLabel(h.hash())) , m_name(TorrentPersistentData::getName(h.hash())) , m_hash(h.hash()) { if (m_name.isEmpty()) m_name = h.name(); }
TorrentModelItem::TorrentModelItem(const QTorrentHandle &h) : m_torrent(h) , m_lastStatus(h.status(torrent_handle::query_accurate_download_counters)) , m_addedTime(TorrentPersistentData::getAddedDate(h.hash())) , m_label(TorrentPersistentData::getLabel(h.hash())) , m_name(TorrentPersistentData::getName(h.hash())) , m_hash(h.hash()) { if (m_name.isEmpty()) m_name = h.name(); }
TorrentModelItem::TorrentModelItem(const QTorrentHandle &h) : m_torrent(h) , m_lastStatus(h.status(torrent_handle::query_accurate_download_counters)) , m_addedTime(TorrentPersistentData::instance()->getAddedDate(h.hash())) , m_label(TorrentPersistentData::instance()->getLabel(h.hash())) , m_name(TorrentPersistentData::instance()->getName(h.hash())) , m_hash(h.hash()) { if (m_name.isEmpty()) m_name = h.name(); // If name is empty show the hash. This happens when magnet isn't retrieved. if (m_name.isEmpty()) m_name = h.hash(); }
void TorrentModel::handleTorrentUpdate(const QTorrentHandle &h) { const int row = torrentRow(h.hash()); if (row >= 0) { notifyTorrentChanged(row); } }
void TorrentModel::handleTorrentAboutToBeRemoved(const QTorrentHandle &h) { const int row = torrentRow(h.hash()); if (row >= 0) { emit torrentAboutToBeRemoved(m_torrents.at(row)); } }
bool QTorrentFilter::torrentHasLabel(const QTorrentHandle &h) const { if (label_.isNull()) return true; else return TorrentPersistentData::instance()->getLabel(h.hash()) == label_; }
void TorrentModel::populate() { // Load the torrents std::vector<torrent_handle> torrents = QBtSession::instance()->getSession()->get_torrents(); std::vector<torrent_handle>::const_iterator it = torrents.begin(); std::vector<torrent_handle>::const_iterator itend = torrents.end(); for ( ; it != itend; ++it) { const QTorrentHandle h(*it); if (HiddenData::hasData(h.hash())) continue; addTorrent(h); } // Refresh timer connect(&m_refreshTimer, SIGNAL(timeout()), SLOT(forceModelRefresh())); m_refreshTimer.start(m_refreshInterval); // Listen for torrent changes connect(QBtSession::instance(), SIGNAL(addedTorrent(QTorrentHandle)), SLOT(addTorrent(QTorrentHandle))); connect(QBtSession::instance(), SIGNAL(torrentAboutToBeRemoved(QTorrentHandle)), SLOT(handleTorrentAboutToBeRemoved(QTorrentHandle))); connect(QBtSession::instance(), SIGNAL(deletedTorrent(QString)), SLOT(removeTorrent(QString))); connect(QBtSession::instance(), SIGNAL(finishedTorrent(QTorrentHandle)), SLOT(handleFinishedTorrent(QTorrentHandle))); connect(QBtSession::instance(), SIGNAL(metadataReceived(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(torrentFinishedChecking(QTorrentHandle)), SLOT(handleTorrentUpdate(QTorrentHandle))); connect(QBtSession::instance(), SIGNAL(stateUpdate(std::vector<libtorrent::torrent_status>)), SLOT(stateUpdated(std::vector<libtorrent::torrent_status>))); }
/** * The function returns the changed data from the server to synchronize with the web client. * Return value is map in JSON format. * Map contain the key: * - "Rid": ID response * Map can contain the keys: * - "full_update": full data update flag * - "torrents": dictionary contains information about torrents. * - "torrents_removed": a list of hashes of removed torrents * - "labels": list of labels * - "labels_removed": list of removed labels * - "server_state": map contains information about the state of the server * The keys of the 'torrents' dictionary are hashes of torrents. * Each value of the 'torrents' dictionary contains map. The map can contain following keys: * - "name": Torrent name * - "size": Torrent size * - "progress: Torrent progress * - "dlspeed": Torrent download speed * - "upspeed": Torrent upload speed * - "priority": Torrent priority (-1 if queuing is disabled) * - "num_seeds": Torrent seeds connected to * - "num_complete": Torrent seeds in the swarm * - "num_leechs": Torrent leechers connected to * - "num_incomplete": Torrent leechers in the swarm * - "ratio": Torrent share ratio * - "eta": Torrent ETA * - "state": Torrent state * - "seq_dl": Torrent sequential download state * - "f_l_piece_prio": Torrent first last piece priority state * Server state map may contain the following keys: * - "connection_status": conection status * - "dht_nodes": DHT nodes count * - "dl_info_data": bytes downloaded * - "dl_info_speed": download speed * - "dl_rate_limit: downlaod rate limit * - "up_info_data: bytes uploaded * - "up_info_speed: upload speed * - "up_rate_limit: upload speed limit * - "queueing": priority system usage flag * - "refresh_interval": torrents table refresh interval */ QByteArray btjson::getSyncMainData(int acceptedResponseId, QVariantMap &lastData, QVariantMap &lastAcceptedData) { QVariantMap data; QVariantHash torrents; std::vector<torrent_handle> torrentsList = QBtSession::instance()->getTorrents(); std::vector<torrent_handle>::const_iterator it = torrentsList.begin(); std::vector<torrent_handle>::const_iterator end = torrentsList.end(); for (; it != end; ++it) { QTorrentHandle torrent = QTorrentHandle(*it); QVariantMap map = toMap(torrent); map.remove(KEY_TORRENT_HASH); torrents[torrent.hash()] = map; } data["torrents"] = torrents; QVariantList labels; foreach (QString s, Preferences::instance()->getTorrentLabels()) labels << s; data["labels"] = labels; QVariantMap serverState = getTranserInfoMap(); serverState[KEY_SYNC_MAINDATA_QUEUEING] = QBtSession::instance()->isQueueingEnabled(); serverState[KEY_SYNC_MAINDATA_USE_ALT_SPEED_LIMITS] = Preferences::instance()->isAltBandwidthEnabled(); serverState[KEY_SYNC_MAINDATA_REFRESH_INTERVAL] = Preferences::instance()->getRefreshInterval(); data["server_state"] = serverState; return json::toJson(generateSyncData(acceptedResponseId, data, lastAcceptedData, lastData)); }
void TorrentModel::handleTorrentUpdate(const QTorrentHandle &h) { const int row = torrentRow(h.hash()); if (row >= 0) { m_torrents[row]->refreshStatus(h.status(torrent_handle::query_accurate_download_counters)); notifyTorrentChanged(row); } }
void TorrentModel::handleFinishedTorrent(const QTorrentHandle& h) { const int row = torrentRow(h.hash()); if (row < 0) return; // Update completion date m_torrents[row]->refreshStatus(h.status(torrent_handle::query_accurate_download_counters)); notifyTorrentChanged(row); }
void TorrentModel::handleFinishedTorrent(const QTorrentHandle& h) { const int row = torrentRow(h.hash()); if (row < 0) return; // Update completion date m_torrents[row]->setData(TorrentModelItem::TR_SEED_DATE, QDateTime::currentDateTime(), Qt::DisplayRole); notifyTorrentChanged(row); }
void TorrentModel::handleFinishedTorrent(const QTorrentHandle& h) { const int row = torrentRow(h.hash()); if (row < 0) return; // Update completion date 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); }
void TorrentModel::addTorrent(const QTorrentHandle &h) { if (torrentRow(h.hash()) < 0) { beginInsertTorrent(m_torrents.size()); TorrentModelItem *item = new TorrentModelItem(h); connect(item, SIGNAL(labelChanged(QString,QString)), SLOT(handleTorrentLabelChange(QString,QString))); m_torrents << item; emit torrentAdded(item); endInsertTorrent(); } }
void TorrentPersistentData::saveTorrentPersistentData(const QTorrentHandle &h, const QString &save_path, const bool is_magnet) { Q_ASSERT(h.is_valid()); qDebug("Saving persistent data for %s", qPrintable(h.hash())); // Save persistent data QHash<QString, QVariant> data = all_data.value(h.hash()).toHash(); data["is_magnet"] = is_magnet; if (is_magnet) { data["magnet_uri"] = misc::toQString(make_magnet_uri(h)); } data["seed"] = h.is_seed(); data["priority"] = h.queue_position(); if (save_path.isEmpty()) { qDebug("TorrentPersistantData: save path is %s", qPrintable(h.save_path())); data["save_path"] = h.save_path(); } else { qDebug("TorrentPersistantData: overriding save path is %s", qPrintable(save_path)); data["save_path"] = save_path; // Override torrent save path (e.g. because it is a temp dir) } // Label data["label"] = TorrentTempData::getLabel(h.hash()); // Save data all_data[h.hash()] = data; markDirty(); qDebug("TorrentPersistentData: Saving save_path %s, hash: %s", qPrintable(h.save_path()), qPrintable(h.hash())); // Set Added date setAddedDate(h.hash(), QDateTime::currentDateTime()); // Finally, remove temp data TorrentTempData::deleteTempData(h.hash()); }
void TorrentModel::handleTorrentAboutToBeRemoved(const QTorrentHandle &h) { const int row = torrentRow(h.hash()); qDebug() << Q_FUNC_INFO << row; if (row >= 0) { emit torrentAboutToBeRemoved(m_torrents.at(row)); beginRemoveTorrent(row); delete m_torrents[row]; m_torrents.removeAt(row); endRemoveTorrent(); } }
void TorrentModel::handleTorrentUpdate(const QTorrentHandle &h) { const int row = torrentRow(h.hash()); if (row >= 0) { // This line changes the torrent name when magnet is retrieved. // When magnet link is added, "dn" parameter is used as name, but when metadata is retrieved // we change the name with the retrieved torrent name. m_torrents[row]->setData(TorrentModelItem::TR_NAME, h.name(), Qt::DisplayRole); m_torrents[row]->refreshStatus(h.status(torrent_handle::query_accurate_download_counters)); notifyTorrentChanged(row); } }
/** * Returns the properties for a torrent in JSON format. * * The return value is a JSON-formatted dictionary. * The dictionary keys are: * - "save_path": Torrent save path * - "creation_date": Torrent creation date * - "piece_size": Torrent piece size * - "comment": Torrent comment * - "total_wasted": Total data wasted for torrent * - "total_uploaded": Total data uploaded for torrent * - "total_downloaded": Total data uploaded for torrent * - "up_limit": Torrent upload limit * - "dl_limit": Torrent download limit * - "time_elapsed": Torrent elapsed time * - "nb_connections": Torrent connection count * - "share_ratio": Torrent share ratio */ QString btjson::getPropertiesForTorrent(const QString& hash) { CACHED_VARIABLE_FOR_HASH(JsonDict, data, CACHE_DURATION_MS, hash); try { QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); if (!h.has_metadata()) return QString(); // Save path QString save_path = TorrentPersistentData::getSavePath(hash); if (save_path.isEmpty()) save_path = 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(h.total_failed_bytes() + h.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_DOWNLOADED, QString(misc::friendlyUnit(h.all_time_download()) + " (" + misc::friendlyUnit(h.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)); QString elapsed_txt = misc::userFriendlyDuration(h.active_time()); if (h.is_seed()) elapsed_txt += " ("+tr("Seeded for %1", "e.g. Seeded for 3m10s").arg(misc::userFriendlyDuration(h.seeding_time()))+")"; 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())) + ")")); const qreal ratio = QBtSession::instance()->getRealRatio(h.hash()); /* HACK because QString rounds up. Eg QString::number(0.999*100.0, 'f' ,1) == 99.9 ** but QString::number(0.9999*100.0, 'f' ,1) == 100.0 */ data.add(KEY_PROP_RATIO, ratio > 100. ? QString::fromUtf8("∞") : QString::number((int)(ratio*10)/10.0, 'f', 1)); } catch(const std::exception& e) { qWarning() << Q_FUNC_INFO << "Invalid torrent: " << e.what(); return QString(); } return data.toString(); }
static JsonDict toJson(const QTorrentHandle& h) { JsonDict ret; ret.add(KEY_TORRENT_HASH, h.hash()); 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_PROGRESS, (double)h.progress()); ret.add(KEY_TORRENT_DLSPEED, misc::friendlyUnit(h.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 if (QBtSession::instance()->isQueueingEnabled() && h.queue_position() >= 0) ret.add(KEY_TORRENT_PRIORITY, QString::number(h.queue_position())); else ret.add(KEY_TORRENT_PRIORITY, "*"); QString seeds = QString::number(h.num_seeds()); if (h.num_complete() > 0) seeds += " ("+QString::number(h.num_complete())+")"; ret.add(KEY_TORRENT_SEEDS, seeds); QString leechs = QString::number(h.num_peers() - h.num_seeds()); if (h.num_incomplete() > 0) leechs += " ("+QString::number(h.num_incomplete())+")"; ret.add(KEY_TORRENT_LEECHS, leechs); const qreal ratio = QBtSession::instance()->getRealRatio(h.hash()); /* HACK because QString rounds up. Eg QString::number(0.999*100.0, 'f' ,1) == 99.9 ** but QString::number(0.9999*100.0, 'f' ,1) == 100.0 */ ret.add(KEY_TORRENT_RATIO, (ratio > 100.) ? QString::fromUtf8("∞") : QString::number((int)(ratio*10)/10.0, 'f', 1)); QString eta; QString state; if (h.is_paused()) { if (h.has_error()) state = "error"; else state = h.is_seed() ? "pausedUP" : "pausedDL"; } else { if (QBtSession::instance()->isQueueingEnabled() && h.is_queued()) state = h.is_seed() ? "queuedUP" : "queuedDL"; else { switch (h.state()) { case torrent_status::finished: case torrent_status::seeding: state = h.upload_payload_rate() > 0 ? "uploading" : "stalledUP"; break; case torrent_status::allocating: case torrent_status::checking_files: case torrent_status::queued_for_checking: case torrent_status::checking_resume_data: state = h.is_seed() ? "checkingUP" : "checkingDL"; break; case torrent_status::downloading: case torrent_status::downloading_metadata: state = h.download_payload_rate() > 0 ? "downloading" : "stalledDL"; eta = misc::userFriendlyDuration(QBtSession::instance()->getETA(h.hash())); break; default: qWarning("Unrecognized torrent status, should not happen!!! status was %d", h.state()); } } } ret.add(KEY_TORRENT_ETA, eta.isEmpty() ? QString::fromUtf8("∞") : eta); ret.add(KEY_TORRENT_STATE, state); return ret; }
void TorrentSpeedMonitor::removeSamples(const QTorrentHandle& h) { try { m_samples.remove(h.hash()); } catch(invalid_handle&) {} }
void TorrentPersistentData::savePriority(const QTorrentHandle &h) { QHash<QString, QVariant> data = all_data[h.hash()].toHash(); data["priority"] = h.queue_position(); all_data[h.hash()] = data; markDirty(); }
static QVariantMap toMap(const QTorrentHandle& h) { libtorrent::torrent_status status = h.status(torrent_handle::query_accurate_download_counters); QVariantMap ret; ret[KEY_TORRENT_HASH] = h.hash(); ret[KEY_TORRENT_NAME] = h.name(); ret[KEY_TORRENT_SIZE] = misc::friendlyUnit(status.total_wanted, false, true); // 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, true); // FIXME: Should be passed as a Number ret[KEY_TORRENT_UPSPEED] = misc::friendlyUnit(status.upload_payload_rate, true, true); // FIXME: Should be passed as a Number if (QBtSession::instance()->isQueueingEnabled() && h.queue_position(status) >= 0) ret[KEY_TORRENT_PRIORITY] = QString::number(h.queue_position(status)); else ret[KEY_TORRENT_PRIORITY] = "*"; QString seeds = QString::number(status.num_seeds); if (status.num_complete > 0) seeds += " ("+QString::number(status.num_complete)+")"; 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[KEY_TORRENT_LEECHS] = leechs; const qreal ratio = QBtSession::instance()->getRealRatio(status); ret[KEY_TORRENT_RATIO] = (ratio > 100.) ? QString::fromUtf8("∞") : misc::accurateDoubleToString(ratio, 1, false); QString eta; QString state; if (h.is_paused(status)) { if (h.has_error(status)) state = "error"; else state = h.is_seed(status) ? "pausedUP" : "pausedDL"; } else { if (QBtSession::instance()->isQueueingEnabled() && h.is_queued(status)) state = h.is_seed(status) ? "queuedUP" : "queuedDL"; else { switch (status.state) { case torrent_status::finished: case torrent_status::seeding: state = status.upload_payload_rate > 0 ? "uploading" : "stalledUP"; break; case torrent_status::allocating: case torrent_status::checking_files: case torrent_status::queued_for_checking: case torrent_status::checking_resume_data: state = h.is_seed(status) ? "checkingUP" : "checkingDL"; break; case torrent_status::downloading: case torrent_status::downloading_metadata: state = status.download_payload_rate > 0 ? "downloading" : "stalledDL"; eta = misc::userFriendlyDuration(QBtSession::instance()->getETA(h.hash(), status)); break; default: qWarning("Unrecognized torrent status, should not happen!!! status was %d", h.state()); } } } ret[KEY_TORRENT_ETA] = eta.isEmpty() ? QString::fromUtf8("∞") : eta; ret[KEY_TORRENT_STATE] = state; return ret; }