mirror of
https://github.com/d47081/qBittorrent.git
synced 2025-01-22 20:44:15 +00:00
parent
8df80b67f9
commit
2f9b313287
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2022 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2022-2023 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@ -46,7 +46,6 @@ namespace BitTorrent
|
|||||||
virtual Path actualFilePath(int fileIndex) const = 0;
|
virtual Path actualFilePath(int fileIndex) const = 0;
|
||||||
virtual QVector<DownloadPriority> filePriorities() const = 0;
|
virtual QVector<DownloadPriority> filePriorities() const = 0;
|
||||||
virtual QVector<qreal> filesProgress() const = 0;
|
virtual QVector<qreal> filesProgress() const = 0;
|
||||||
virtual void fetchFilesProgress(std::function<void (QVector<qreal>)> resultHandler) const = 0;
|
|
||||||
/**
|
/**
|
||||||
* @brief fraction of file pieces that are available at least from one peer
|
* @brief fraction of file pieces that are available at least from one peer
|
||||||
*
|
*
|
||||||
|
@ -279,6 +279,7 @@ TorrentImpl::TorrentImpl(SessionImpl *session, lt::session *nativeSession
|
|||||||
, LT::toNative(m_ltAddTorrentParams.file_priorities.empty() ? DownloadPriority::Normal : DownloadPriority::Ignored));
|
, LT::toNative(m_ltAddTorrentParams.file_priorities.empty() ? DownloadPriority::Normal : DownloadPriority::Ignored));
|
||||||
|
|
||||||
m_completedFiles.fill(static_cast<bool>(m_ltAddTorrentParams.flags & lt::torrent_flags::seed_mode), filesCount);
|
m_completedFiles.fill(static_cast<bool>(m_ltAddTorrentParams.flags & lt::torrent_flags::seed_mode), filesCount);
|
||||||
|
m_filesProgress.resize(filesCount);
|
||||||
|
|
||||||
for (int i = 0; i < filesCount; ++i)
|
for (int i = 0; i < filesCount; ++i)
|
||||||
{
|
{
|
||||||
@ -306,6 +307,9 @@ TorrentImpl::TorrentImpl(SessionImpl *session, lt::session *nativeSession
|
|||||||
m_urlSeeds.append(QString::fromStdString(urlSeed));
|
m_urlSeeds.append(QString::fromStdString(urlSeed));
|
||||||
m_nativeStatus = extensionData->status;
|
m_nativeStatus = extensionData->status;
|
||||||
|
|
||||||
|
if (hasMetadata())
|
||||||
|
updateProgress();
|
||||||
|
|
||||||
updateState();
|
updateState();
|
||||||
|
|
||||||
if (hasMetadata())
|
if (hasMetadata())
|
||||||
@ -1184,20 +1188,20 @@ QVector<qreal> TorrentImpl::filesProgress() const
|
|||||||
if (!hasMetadata())
|
if (!hasMetadata())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (m_completedFiles.count(true) == filesCount())
|
const int count = m_filesProgress.size();
|
||||||
return QVector<qreal>(filesCount(), 1);
|
Q_ASSERT(count == filesCount());
|
||||||
|
if (Q_UNLIKELY(count != filesCount()))
|
||||||
|
return {};
|
||||||
|
|
||||||
std::vector<int64_t> fp;
|
if (m_completedFiles.count(true) == count)
|
||||||
m_nativeHandle.file_progress(fp, lt::torrent_handle::piece_granularity);
|
return QVector<qreal>(count, 1);
|
||||||
|
|
||||||
const int count = filesCount();
|
|
||||||
const auto nativeIndexes = m_torrentInfo.nativeIndexes();
|
|
||||||
QVector<qreal> result;
|
QVector<qreal> result;
|
||||||
result.reserve(count);
|
result.reserve(count);
|
||||||
for (int i = 0; i < count; ++i)
|
for (int i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
const int64_t progress = fp[LT::toUnderlyingType(nativeIndexes[i])];
|
const int64_t progress = m_filesProgress.at(i);
|
||||||
const qlonglong size = fileSize(i);
|
const int64_t size = fileSize(i);
|
||||||
if ((size <= 0) || (progress == size))
|
if ((size <= 0) || (progress == size))
|
||||||
result << 1;
|
result << 1;
|
||||||
else
|
else
|
||||||
@ -1323,8 +1327,6 @@ QVector<PeerInfo> TorrentImpl::peers() const
|
|||||||
|
|
||||||
QBitArray TorrentImpl::pieces() const
|
QBitArray TorrentImpl::pieces() const
|
||||||
{
|
{
|
||||||
if (m_pieces.isEmpty())
|
|
||||||
m_pieces = LT::toQBitArray(m_nativeStatus.pieces);
|
|
||||||
return m_pieces;
|
return m_pieces;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1469,7 +1471,8 @@ void TorrentImpl::forceDHTAnnounce()
|
|||||||
|
|
||||||
void TorrentImpl::forceRecheck()
|
void TorrentImpl::forceRecheck()
|
||||||
{
|
{
|
||||||
if (!hasMetadata()) return;
|
if (!hasMetadata())
|
||||||
|
return;
|
||||||
|
|
||||||
m_nativeHandle.force_recheck();
|
m_nativeHandle.force_recheck();
|
||||||
// We have to force update the cached state, otherwise someone will be able to get
|
// We have to force update the cached state, otherwise someone will be able to get
|
||||||
@ -1478,7 +1481,12 @@ void TorrentImpl::forceRecheck()
|
|||||||
|
|
||||||
m_hasMissingFiles = false;
|
m_hasMissingFiles = false;
|
||||||
m_unchecked = false;
|
m_unchecked = false;
|
||||||
|
|
||||||
m_completedFiles.fill(false);
|
m_completedFiles.fill(false);
|
||||||
|
m_filesProgress.fill(0);
|
||||||
|
m_pieces.fill(false);
|
||||||
|
m_nativeStatus.pieces.clear_all();
|
||||||
|
m_nativeStatus.num_pieces = 0;
|
||||||
|
|
||||||
if (isPaused())
|
if (isPaused())
|
||||||
{
|
{
|
||||||
@ -1603,6 +1611,8 @@ void TorrentImpl::endReceivedMetadataHandling(const Path &savePath, const PathLi
|
|||||||
, LT::toNative(p.file_priorities.empty() ? DownloadPriority::Normal : DownloadPriority::Ignored));
|
, LT::toNative(p.file_priorities.empty() ? DownloadPriority::Normal : DownloadPriority::Ignored));
|
||||||
|
|
||||||
m_completedFiles.fill(static_cast<bool>(p.flags & lt::torrent_flags::seed_mode), filesCount());
|
m_completedFiles.fill(static_cast<bool>(p.flags & lt::torrent_flags::seed_mode), filesCount());
|
||||||
|
m_filesProgress.resize(filesCount());
|
||||||
|
updateProgress();
|
||||||
|
|
||||||
for (int i = 0; i < fileNames.size(); ++i)
|
for (int i = 0; i < fileNames.size(); ++i)
|
||||||
{
|
{
|
||||||
@ -1650,7 +1660,10 @@ void TorrentImpl::endReceivedMetadataHandling(const Path &savePath, const PathLi
|
|||||||
void TorrentImpl::reload()
|
void TorrentImpl::reload()
|
||||||
{
|
{
|
||||||
m_completedFiles.fill(false);
|
m_completedFiles.fill(false);
|
||||||
m_pieces.clear();
|
m_filesProgress.fill(0);
|
||||||
|
m_pieces.fill(false);
|
||||||
|
m_nativeStatus.pieces.clear_all();
|
||||||
|
m_nativeStatus.num_pieces = 0;
|
||||||
|
|
||||||
const auto queuePos = m_nativeHandle.queue_position();
|
const auto queuePos = m_nativeHandle.queue_position();
|
||||||
|
|
||||||
@ -2279,8 +2292,11 @@ bool TorrentImpl::isMoveInProgress() const
|
|||||||
|
|
||||||
void TorrentImpl::updateStatus(const lt::torrent_status &nativeStatus)
|
void TorrentImpl::updateStatus(const lt::torrent_status &nativeStatus)
|
||||||
{
|
{
|
||||||
m_pieces.clear();
|
const lt::torrent_status oldStatus = std::exchange(m_nativeStatus, nativeStatus);
|
||||||
m_nativeStatus = nativeStatus;
|
|
||||||
|
if (m_nativeStatus.num_pieces != oldStatus.num_pieces)
|
||||||
|
updateProgress();
|
||||||
|
|
||||||
updateState();
|
updateState();
|
||||||
|
|
||||||
m_payloadRateMonitor.addSample({nativeStatus.download_payload_rate
|
m_payloadRateMonitor.addSample({nativeStatus.download_payload_rate
|
||||||
@ -2300,6 +2316,44 @@ void TorrentImpl::updateStatus(const lt::torrent_status &nativeStatus)
|
|||||||
std::invoke(m_statusUpdatedTriggers.dequeue());
|
std::invoke(m_statusUpdatedTriggers.dequeue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TorrentImpl::updateProgress()
|
||||||
|
{
|
||||||
|
Q_ASSERT(hasMetadata());
|
||||||
|
if (Q_UNLIKELY(!hasMetadata()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Q_ASSERT(!m_filesProgress.isEmpty());
|
||||||
|
if (Q_UNLIKELY(m_filesProgress.isEmpty()))
|
||||||
|
m_filesProgress.resize(filesCount());
|
||||||
|
|
||||||
|
const QBitArray oldPieces = std::exchange(m_pieces, LT::toQBitArray(m_nativeStatus.pieces));
|
||||||
|
const QBitArray newPieces = m_pieces ^ oldPieces;
|
||||||
|
|
||||||
|
const int64_t pieceSize = m_torrentInfo.pieceLength();
|
||||||
|
for (qsizetype index = 0; index < newPieces.size(); ++index)
|
||||||
|
{
|
||||||
|
if (!newPieces.at(index))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int64_t size = m_torrentInfo.pieceLength(index);
|
||||||
|
int64_t pieceOffset = index * pieceSize;
|
||||||
|
|
||||||
|
for (const int fileIndex : asConst(m_torrentInfo.fileIndicesForPiece(index)))
|
||||||
|
{
|
||||||
|
const int64_t fileOffsetInPiece = pieceOffset - m_torrentInfo.fileOffset(fileIndex);
|
||||||
|
const int64_t add = std::min<int64_t>((m_torrentInfo.fileSize(fileIndex) - fileOffsetInPiece), size);
|
||||||
|
|
||||||
|
m_filesProgress[fileIndex] += add;
|
||||||
|
|
||||||
|
size -= add;
|
||||||
|
if (size <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
pieceOffset += add;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TorrentImpl::setRatioLimit(qreal limit)
|
void TorrentImpl::setRatioLimit(qreal limit)
|
||||||
{
|
{
|
||||||
if (limit < USE_GLOBAL_RATIO)
|
if (limit < USE_GLOBAL_RATIO)
|
||||||
@ -2540,48 +2594,6 @@ void TorrentImpl::fetchURLSeeds(std::function<void (QVector<QUrl>)> resultHandle
|
|||||||
, std::move(resultHandler));
|
, std::move(resultHandler));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentImpl::fetchFilesProgress(std::function<void (QVector<qreal>)> resultHandler) const
|
|
||||||
{
|
|
||||||
invokeAsync([nativeHandle = m_nativeHandle, torrentInfo = m_torrentInfo
|
|
||||||
, completedFiles = m_completedFiles]() -> QVector<qreal>
|
|
||||||
{
|
|
||||||
if (!torrentInfo.isValid())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
const int filesCount = torrentInfo.filesCount();
|
|
||||||
if (completedFiles.count(true) == filesCount)
|
|
||||||
return QVector<qreal>(filesCount, 1);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
#ifdef QBT_USES_LIBTORRENT2
|
|
||||||
const std::vector<int64_t> fp = nativeHandle.file_progress(lt::torrent_handle::piece_granularity);
|
|
||||||
#else
|
|
||||||
std::vector<int64_t> fp;
|
|
||||||
nativeHandle.file_progress(fp, lt::torrent_handle::piece_granularity);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const auto nativeIndexes = torrentInfo.nativeIndexes();
|
|
||||||
QVector<qreal> result;
|
|
||||||
result.reserve(filesCount);
|
|
||||||
for (int i = 0; i < filesCount; ++i)
|
|
||||||
{
|
|
||||||
const int64_t progress = fp[LT::toUnderlyingType(nativeIndexes[i])];
|
|
||||||
const qlonglong size = torrentInfo.fileSize(i);
|
|
||||||
if ((size <= 0) || (progress == size))
|
|
||||||
result.append(1);
|
|
||||||
else
|
|
||||||
result.append(progress / static_cast<qreal>(size));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
catch (const std::exception &) {}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
, std::move(resultHandler));
|
|
||||||
}
|
|
||||||
|
|
||||||
void TorrentImpl::fetchPieceAvailability(std::function<void (QVector<int>)> resultHandler) const
|
void TorrentImpl::fetchPieceAvailability(std::function<void (QVector<int>)> resultHandler) const
|
||||||
{
|
{
|
||||||
invokeAsync([nativeHandle = m_nativeHandle]() -> QVector<int>
|
invokeAsync([nativeHandle = m_nativeHandle]() -> QVector<int>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2015-2022 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2015-2023 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
@ -238,7 +238,6 @@ namespace BitTorrent
|
|||||||
|
|
||||||
void fetchPeerInfo(std::function<void (QVector<PeerInfo>)> resultHandler) const override;
|
void fetchPeerInfo(std::function<void (QVector<PeerInfo>)> resultHandler) const override;
|
||||||
void fetchURLSeeds(std::function<void (QVector<QUrl>)> resultHandler) const override;
|
void fetchURLSeeds(std::function<void (QVector<QUrl>)> resultHandler) const override;
|
||||||
void fetchFilesProgress(std::function<void (QVector<qreal>)> resultHandler) const override;
|
|
||||||
void fetchPieceAvailability(std::function<void (QVector<int>)> resultHandler) const override;
|
void fetchPieceAvailability(std::function<void (QVector<int>)> resultHandler) const override;
|
||||||
void fetchDownloadingPieces(std::function<void (QBitArray)> resultHandler) const override;
|
void fetchDownloadingPieces(std::function<void (QBitArray)> resultHandler) const override;
|
||||||
void fetchAvailableFileFractions(std::function<void (QVector<qreal>)> resultHandler) const override;
|
void fetchAvailableFileFractions(std::function<void (QVector<qreal>)> resultHandler) const override;
|
||||||
@ -263,6 +262,7 @@ namespace BitTorrent
|
|||||||
std::shared_ptr<const lt::torrent_info> nativeTorrentInfo() const;
|
std::shared_ptr<const lt::torrent_info> nativeTorrentInfo() const;
|
||||||
|
|
||||||
void updateStatus(const lt::torrent_status &nativeStatus);
|
void updateStatus(const lt::torrent_status &nativeStatus);
|
||||||
|
void updateProgress();
|
||||||
void updateState();
|
void updateState();
|
||||||
|
|
||||||
void handleFastResumeRejectedAlert(const lt::fastresume_rejected_alert *p);
|
void handleFastResumeRejectedAlert(const lt::fastresume_rejected_alert *p);
|
||||||
@ -354,6 +354,7 @@ namespace BitTorrent
|
|||||||
int m_downloadLimit = 0;
|
int m_downloadLimit = 0;
|
||||||
int m_uploadLimit = 0;
|
int m_uploadLimit = 0;
|
||||||
|
|
||||||
mutable QBitArray m_pieces;
|
QBitArray m_pieces;
|
||||||
|
QVector<std::int64_t> m_filesProgress;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2022 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2022-2023 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
* Copyright (C) 2012 Christophe Dumez <chris@qbittorrent.org>
|
* Copyright (C) 2012 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
@ -237,11 +237,6 @@ public:
|
|||||||
return QVector<qreal>(filesCount(), 0);
|
return QVector<qreal>(filesCount(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fetchFilesProgress(std::function<void (QVector<qreal>)> resultHandler) const override
|
|
||||||
{
|
|
||||||
resultHandler(filesProgress());
|
|
||||||
}
|
|
||||||
|
|
||||||
QVector<qreal> availableFileFractions() const override
|
QVector<qreal> availableFileFractions() const override
|
||||||
{
|
{
|
||||||
return QVector<qreal>(filesCount(), 0);
|
return QVector<qreal>(filesCount(), 0);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2022 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2022-2023 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
* Copyright (C) 2006-2012 Christophe Dumez <chris@qbittorrent.org>
|
* Copyright (C) 2006-2012 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
@ -216,23 +216,17 @@ void TorrentContentModel::updateFilesProgress()
|
|||||||
{
|
{
|
||||||
Q_ASSERT(m_contentHandler && m_contentHandler->hasMetadata());
|
Q_ASSERT(m_contentHandler && m_contentHandler->hasMetadata());
|
||||||
|
|
||||||
using HandlerPtr = QPointer<BitTorrent::TorrentContentHandler>;
|
const QVector<qreal> &filesProgress = m_contentHandler->filesProgress();
|
||||||
m_contentHandler->fetchFilesProgress([this, handler = HandlerPtr(m_contentHandler)](const QVector<qreal> &filesProgress)
|
Q_ASSERT(m_filesIndex.size() == filesProgress.size());
|
||||||
{
|
// XXX: Why is this necessary?
|
||||||
if (handler != m_contentHandler)
|
if (Q_UNLIKELY(m_filesIndex.size() != filesProgress.size()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Q_ASSERT(m_filesIndex.size() == filesProgress.size());
|
for (int i = 0; i < filesProgress.size(); ++i)
|
||||||
// XXX: Why is this necessary?
|
m_filesIndex[i]->setProgress(filesProgress[i]);
|
||||||
if (Q_UNLIKELY(m_filesIndex.size() != filesProgress.size()))
|
// Update folders progress in the tree
|
||||||
return;
|
m_rootItem->recalculateProgress();
|
||||||
|
m_rootItem->recalculateAvailability();
|
||||||
for (int i = 0; i < filesProgress.size(); ++i)
|
|
||||||
m_filesIndex[i]->setProgress(filesProgress[i]);
|
|
||||||
// Update folders progress in the tree
|
|
||||||
m_rootItem->recalculateProgress();
|
|
||||||
m_rootItem->recalculateAvailability();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentContentModel::updateFilesPriorities()
|
void TorrentContentModel::updateFilesPriorities()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user