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);
  }
}
Exemple #6
0
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>)));
}
Exemple #9
0
/**
 * 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));
}
Exemple #10
0
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);
  }
}
Exemple #11
0
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);
}
Exemple #13
0
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);
}
Exemple #14
0
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());
}
Exemple #16
0
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();
    }
}
Exemple #17
0
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);
    }
}
Exemple #18
0
/**
 * 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();
}
Exemple #19
0
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();
}
Exemple #22
0
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;
}