Browse Source

Improve torrent content handling

Hide .pad files.

PR #15468.
adaptive-webui-19844
Vladimir Golovnev 3 years ago committed by GitHub
parent
commit
bc71827c01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      src/base/CMakeLists.txt
  2. 2
      src/base/base.pri
  3. 1
      src/base/bittorrent/abstractfilestorage.h
  4. 21
      src/base/bittorrent/lttypecast.h
  5. 56
      src/base/bittorrent/session.cpp
  6. 2
      src/base/bittorrent/torrent.h
  7. 4
      src/base/bittorrent/torrentcreatorthread.cpp
  8. 134
      src/base/bittorrent/torrentimpl.cpp
  9. 5
      src/base/bittorrent/torrentimpl.h
  10. 59
      src/base/bittorrent/torrentinfo.cpp
  11. 6
      src/base/bittorrent/torrentinfo.h
  12. 2
      src/gui/addnewtorrentdialog.cpp
  13. 5
      src/gui/previewselectdialog.cpp
  14. 5
      src/gui/torrentcontentmodel.cpp
  15. 2
      src/gui/torrentcontentmodelfolder.cpp
  16. 4
      src/gui/transferlistwidget.cpp

2
src/base/CMakeLists.txt

@ -17,7 +17,7 @@ add_library(qbt_base STATIC @@ -17,7 +17,7 @@ add_library(qbt_base STATIC
bittorrent/infohash.h
bittorrent/loadtorrentparams.h
bittorrent/ltqhash.h
bittorrent/ltunderlyingtype.h
bittorrent/lttypecast.h
bittorrent/magneturi.h
bittorrent/nativesessionextension.h
bittorrent/nativetorrentextension.h

2
src/base/base.pri

@ -16,7 +16,7 @@ HEADERS += \ @@ -16,7 +16,7 @@ HEADERS += \
$$PWD/bittorrent/infohash.h \
$$PWD/bittorrent/loadtorrentparams.h \
$$PWD/bittorrent/ltqhash.h \
$$PWD/bittorrent/ltunderlyingtype.h \
$$PWD/bittorrent/lttypecast.h \
$$PWD/bittorrent/magneturi.h \
$$PWD/bittorrent/nativesessionextension.h \
$$PWD/bittorrent/nativetorrentextension.h \

1
src/base/bittorrent/abstractfilestorage.h

@ -44,7 +44,6 @@ namespace BitTorrent @@ -44,7 +44,6 @@ namespace BitTorrent
virtual int filesCount() const = 0;
virtual QString filePath(int index) const = 0;
virtual QString fileName(int index) const = 0;
virtual qlonglong fileSize(int index) const = 0;
virtual void renameFile(int index, const QString &name) = 0;

21
src/base/bittorrent/ltunderlyingtype.h → src/base/bittorrent/lttypecast.h

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2019 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2019, 2021 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -28,8 +28,25 @@ @@ -28,8 +28,25 @@
#pragma once
#include <libtorrent/download_priority.hpp>
#include "downloadpriority.h"
namespace BitTorrent::LT
{
template <typename T>
typename T::underlying_type toLTUnderlyingType(const T &t)
constexpr typename T::underlying_type toUnderlyingType(const T &t) noexcept
{
return static_cast<typename T::underlying_type>(t);
}
constexpr lt::download_priority_t toNative(const DownloadPriority priority) noexcept
{
return static_cast<lt::download_priority_t>(static_cast<lt::download_priority_t::underlying_type>(priority));
}
constexpr DownloadPriority fromNative(const lt::download_priority_t priority) noexcept
{
return static_cast<DownloadPriority>(toUnderlyingType(priority));
}
}

56
src/base/bittorrent/session.cpp

@ -93,7 +93,7 @@ @@ -93,7 +93,7 @@
#include "filesearcher.h"
#include "filterparserthread.h"
#include "loadtorrentparams.h"
#include "ltunderlyingtype.h"
#include "lttypecast.h"
#include "magneturi.h"
#include "nativesessionextension.h"
#include "portforwarderimpl.h"
@ -1491,7 +1491,7 @@ void Session::configurePeerClasses() @@ -1491,7 +1491,7 @@ void Session::configurePeerClasses()
// Proactively do the same for 0.0.0.0 and address_v4::any()
f.add_rule(lt::address_v4::any()
, lt::address_v4::broadcast()
, 1 << toLTUnderlyingType(lt::session::global_peer_class_id));
, 1 << LT::toUnderlyingType(lt::session::global_peer_class_id));
// IPv6 may not be available on OS and the parsing
// would result in an exception -> abnormal program termination
@ -1500,7 +1500,7 @@ void Session::configurePeerClasses() @@ -1500,7 +1500,7 @@ void Session::configurePeerClasses()
{
f.add_rule(lt::address_v6::any()
, lt::make_address("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
, 1 << toLTUnderlyingType(lt::session::global_peer_class_id));
, 1 << LT::toUnderlyingType(lt::session::global_peer_class_id));
}
catch (const std::exception &) {}
@ -1509,21 +1509,21 @@ void Session::configurePeerClasses() @@ -1509,21 +1509,21 @@ void Session::configurePeerClasses()
// local networks
f.add_rule(lt::make_address("10.0.0.0")
, lt::make_address("10.255.255.255")
, 1 << toLTUnderlyingType(lt::session::local_peer_class_id));
, 1 << LT::toUnderlyingType(lt::session::local_peer_class_id));
f.add_rule(lt::make_address("172.16.0.0")
, lt::make_address("172.31.255.255")
, 1 << toLTUnderlyingType(lt::session::local_peer_class_id));
, 1 << LT::toUnderlyingType(lt::session::local_peer_class_id));
f.add_rule(lt::make_address("192.168.0.0")
, lt::make_address("192.168.255.255")
, 1 << toLTUnderlyingType(lt::session::local_peer_class_id));
, 1 << LT::toUnderlyingType(lt::session::local_peer_class_id));
// link local
f.add_rule(lt::make_address("169.254.0.0")
, lt::make_address("169.254.255.255")
, 1 << toLTUnderlyingType(lt::session::local_peer_class_id));
, 1 << LT::toUnderlyingType(lt::session::local_peer_class_id));
// loopback
f.add_rule(lt::make_address("127.0.0.0")
, lt::make_address("127.255.255.255")
, 1 << toLTUnderlyingType(lt::session::local_peer_class_id));
, 1 << LT::toUnderlyingType(lt::session::local_peer_class_id));
// IPv6 may not be available on OS and the parsing
// would result in an exception -> abnormal program termination
@ -1533,15 +1533,15 @@ void Session::configurePeerClasses() @@ -1533,15 +1533,15 @@ void Session::configurePeerClasses()
// link local
f.add_rule(lt::make_address("fe80::")
, lt::make_address("febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
, 1 << toLTUnderlyingType(lt::session::local_peer_class_id));
, 1 << LT::toUnderlyingType(lt::session::local_peer_class_id));
// unique local addresses
f.add_rule(lt::make_address("fc00::")
, lt::make_address("fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
, 1 << toLTUnderlyingType(lt::session::local_peer_class_id));
, 1 << LT::toUnderlyingType(lt::session::local_peer_class_id));
// loopback
f.add_rule(lt::address_v6::loopback()
, lt::address_v6::loopback()
, 1 << toLTUnderlyingType(lt::session::local_peer_class_id));
, 1 << LT::toUnderlyingType(lt::session::local_peer_class_id));
}
catch (const std::exception &) {}
}
@ -1727,8 +1727,10 @@ void Session::fileSearchFinished(const TorrentID &id, const QString &savePath, c @@ -1727,8 +1727,10 @@ void Session::fileSearchFinished(const TorrentID &id, const QString &savePath, c
lt::add_torrent_params &p = params.ltAddTorrentParams;
p.save_path = Utils::Fs::toNativePath(savePath).toStdString();
const TorrentInfo torrentInfo {p.ti};
const auto nativeIndexes = torrentInfo.nativeIndexes();
for (int i = 0; i < fileNames.size(); ++i)
p.renamed_files[lt::file_index_t {i}] = fileNames[i].toStdString();
p.renamed_files[nativeIndexes[i]] = fileNames[i].toStdString();
loadTorrent(params);
}
@ -2141,28 +2143,20 @@ bool Session::addTorrent_impl(const std::variant<MagnetUri, TorrentInfo> &source @@ -2141,28 +2143,20 @@ bool Session::addTorrent_impl(const std::variant<MagnetUri, TorrentInfo> &source
{
QString contentName = metadata.rootFolder();
if (contentName.isEmpty() && (metadata.filesCount() == 1))
contentName = metadata.fileName(0);
contentName = Utils::Fs::fileName(metadata.filePath(0));
if (!contentName.isEmpty() && (contentName != metadata.name()))
loadTorrentParams.name = contentName;
}
Q_ASSERT(p.file_priorities.empty());
if (addTorrentParams.filePriorities.empty())
{
const int internalFilesCount = metadata.nativeInfo()->files().num_files(); // including .pad files
// Use qBittorrent default priority rather than libtorrent's (4)
p.file_priorities = std::vector(metadata.filesCount(), static_cast<lt::download_priority_t>(
static_cast<lt::download_priority_t::underlying_type>(DownloadPriority::Normal)));
}
else
{
std::transform(addTorrentParams.filePriorities.cbegin(), addTorrentParams.filePriorities.cend()
, std::back_inserter(p.file_priorities), [](const DownloadPriority priority)
{
return static_cast<lt::download_priority_t>(
static_cast<lt::download_priority_t::underlying_type>(priority));
});
}
p.file_priorities = std::vector(internalFilesCount, LT::toNative(DownloadPriority::Normal));
const auto nativeIndexes = metadata.nativeIndexes();
Q_ASSERT(addTorrentParams.filePriorities.isEmpty() || (addTorrentParams.filePriorities.size() == nativeIndexes.size()));
for (int i = 0; i < addTorrentParams.filePriorities.size(); ++i)
p.file_priorities[LT::toUnderlyingType(nativeIndexes[i])] = LT::toNative(addTorrentParams.filePriorities[i]);
p.ti = metadata.nativeInfo();
}
@ -2388,7 +2382,7 @@ void Session::saveTorrentsQueue() const @@ -2388,7 +2382,7 @@ void Session::saveTorrentsQueue() const
for (const TorrentImpl *torrent : asConst(m_torrents))
{
// We require actual (non-cached) queue position here!
const int queuePos = toLTUnderlyingType(torrent->nativeHandle().queue_position());
const int queuePos = LT::toUnderlyingType(torrent->nativeHandle().queue_position());
if (queuePos >= 0)
{
if (queuePos >= queue.size())
@ -3937,9 +3931,8 @@ void Session::handleTorrentFinished(TorrentImpl *const torrent) @@ -3937,9 +3931,8 @@ void Session::handleTorrentFinished(TorrentImpl *const torrent)
qDebug("Checking if the torrent contains torrent files to download");
// Check if there are torrent files inside
for (int i = 0; i < torrent->filesCount(); ++i)
for (const QString &torrentRelpath : asConst(torrent->filePaths()))
{
const QString torrentRelpath = torrent->filePath(i);
if (torrentRelpath.endsWith(".torrent", Qt::CaseInsensitive))
{
qDebug("Found possible recursive torrent download.");
@ -4162,9 +4155,8 @@ void Session::recursiveTorrentDownload(const TorrentID &id) @@ -4162,9 +4155,8 @@ void Session::recursiveTorrentDownload(const TorrentID &id)
TorrentImpl *const torrent = m_torrents.value(id);
if (!torrent) return;
for (int i = 0; i < torrent->filesCount(); ++i)
for (const QString &torrentRelpath : asConst(torrent->filePaths()))
{
const QString torrentRelpath = torrent->filePath(i);
if (torrentRelpath.endsWith(".torrent"))
{
LogMsg(tr("Recursive download of file '%1' embedded in torrent '%2'"

2
src/base/bittorrent/torrent.h

@ -193,6 +193,7 @@ namespace BitTorrent @@ -193,6 +193,7 @@ namespace BitTorrent
virtual qreal ratioLimit() const = 0;
virtual int seedingTimeLimit() const = 0;
virtual QStringList filePaths() const = 0;
virtual QStringList absoluteFilePaths() const = 0;
virtual QVector<DownloadPriority> filePriorities() const = 0;
@ -214,7 +215,6 @@ namespace BitTorrent @@ -214,7 +215,6 @@ namespace BitTorrent
virtual bool hasMetadata() const = 0;
virtual bool hasMissingFiles() const = 0;
virtual bool hasError() const = 0;
virtual bool hasFilteredPieces() const = 0;
virtual int queuePosition() const = 0;
virtual QVector<TrackerEntry> trackers() const = 0;
virtual QVector<QUrl> urlSeeds() const = 0;

4
src/base/bittorrent/torrentcreatorthread.cpp

@ -44,7 +44,7 @@ @@ -44,7 +44,7 @@
#include "base/utils/fs.h"
#include "base/utils/io.h"
#include "base/version.h"
#include "ltunderlyingtype.h"
#include "lttypecast.h"
namespace
{
@ -186,7 +186,7 @@ void TorrentCreatorThread::run() @@ -186,7 +186,7 @@ void TorrentCreatorThread::run()
, [this, &newTorrent](const lt::piece_index_t n)
{
checkInterruptionRequested();
sendProgressSignal(toLTUnderlyingType(n), newTorrent.num_pieces());
sendProgressSignal(LT::toUnderlyingType(n), newTorrent.num_pieces());
});
// Set qBittorrent as creator and add user comment to

134
src/base/bittorrent/torrentimpl.cpp

@ -64,7 +64,7 @@ @@ -64,7 +64,7 @@
#include "downloadpriority.h"
#include "loadtorrentparams.h"
#include "ltqhash.h"
#include "ltunderlyingtype.h"
#include "lttypecast.h"
#include "peeraddress.h"
#include "peerinfo.h"
#include "session.h"
@ -74,20 +74,6 @@ using namespace BitTorrent; @@ -74,20 +74,6 @@ using namespace BitTorrent;
namespace
{
std::vector<lt::download_priority_t> toLTDownloadPriorities(const QVector<DownloadPriority> &priorities)
{
std::vector<lt::download_priority_t> out;
out.reserve(priorities.size());
std::transform(priorities.cbegin(), priorities.cend()
, std::back_inserter(out), [](const DownloadPriority priority)
{
return static_cast<lt::download_priority_t>(
static_cast<lt::download_priority_t::underlying_type>(priority));
});
return out;
}
lt::announce_entry makeNativeAnnouncerEntry(const QString &url, const int tier)
{
lt::announce_entry entry {url.toStdString()};
@ -762,20 +748,19 @@ int TorrentImpl::seedingTimeLimit() const @@ -762,20 +748,19 @@ int TorrentImpl::seedingTimeLimit() const
return m_seedingTimeLimit;
}
QString TorrentImpl::filePath(int index) const
QString TorrentImpl::filePath(const int index) const
{
return m_torrentInfo.filePath(index);
}
QString TorrentImpl::fileName(int index) const
qlonglong TorrentImpl::fileSize(const int index) const
{
if (!hasMetadata()) return {};
return Utils::Fs::fileName(filePath(index));
return m_torrentInfo.fileSize(index);
}
qlonglong TorrentImpl::fileSize(int index) const
QStringList TorrentImpl::filePaths() const
{
return m_torrentInfo.fileSize(index);
return m_torrentInfo.filePaths();
}
// Return a list of absolute paths corresponding
@ -784,8 +769,9 @@ QStringList TorrentImpl::absoluteFilePaths() const @@ -784,8 +769,9 @@ QStringList TorrentImpl::absoluteFilePaths() const
{
if (!hasMetadata()) return {};
const QDir saveDir(savePath(true));
const QDir saveDir {savePath(true)};
QStringList res;
res.reserve(filesCount());
for (int i = 0; i < filesCount(); ++i)
res << Utils::Fs::expandPathAbs(saveDir.absoluteFilePath(filePath(i)));
return res;
@ -793,14 +779,19 @@ QStringList TorrentImpl::absoluteFilePaths() const @@ -793,14 +779,19 @@ QStringList TorrentImpl::absoluteFilePaths() const
QVector<DownloadPriority> TorrentImpl::filePriorities() const
{
if (!hasMetadata())
return {};
const std::vector<lt::download_priority_t> fp = m_nativeHandle.get_file_priorities();
QVector<DownloadPriority> ret;
ret.reserve(static_cast<decltype(ret)::size_type>(fp.size()));
std::transform(fp.cbegin(), fp.cend(), std::back_inserter(ret), [](const lt::download_priority_t priority)
ret.reserve(filesCount());
for (const lt::file_index_t nativeIndex : asConst(m_torrentInfo.nativeIndexes()))
{
return static_cast<DownloadPriority>(toLTUnderlyingType(priority));
});
const auto priority = LT::fromNative(fp[LT::toUnderlyingType(nativeIndex)]);
ret.append(priority);
}
return ret;
}
@ -987,15 +978,6 @@ bool TorrentImpl::hasError() const @@ -987,15 +978,6 @@ bool TorrentImpl::hasError() const
return (m_nativeStatus.errc || (m_nativeStatus.flags & lt::torrent_flags::upload_mode));
}
bool TorrentImpl::hasFilteredPieces() const
{
const std::vector<lt::download_priority_t> pp = m_nativeHandle.get_piece_priorities();
return std::any_of(pp.cbegin(), pp.cend(), [](const lt::download_priority_t priority)
{
return (priority == lt::download_priority_t {0});
});
}
int TorrentImpl::queuePosition() const
{
return static_cast<int>(m_nativeStatus.queue_position);
@ -1092,16 +1074,18 @@ QVector<qreal> TorrentImpl::filesProgress() const @@ -1092,16 +1074,18 @@ QVector<qreal> TorrentImpl::filesProgress() const
std::vector<int64_t> fp;
m_nativeHandle.file_progress(fp, lt::torrent_handle::piece_granularity);
const int count = static_cast<int>(fp.size());
const int count = filesCount();
const auto nativeIndexes = m_torrentInfo.nativeIndexes();
QVector<qreal> result;
result.reserve(count);
for (int i = 0; i < count; ++i)
{
const int64_t progress = fp[LT::toUnderlyingType(nativeIndexes[i])];
const qlonglong size = fileSize(i);
if ((size <= 0) || (fp[i] == size))
if ((size <= 0) || (progress == size))
result << 1;
else
result << (fp[i] / static_cast<qreal>(size));
result << (progress / static_cast<qreal>(size));
}
return result;
@ -1252,7 +1236,7 @@ QBitArray TorrentImpl::downloadingPieces() const @@ -1252,7 +1236,7 @@ QBitArray TorrentImpl::downloadingPieces() const
m_nativeHandle.get_download_queue(queue);
for (const lt::partial_piece_info &info : queue)
result.setBit(toLTUnderlyingType(info.piece_index));
result.setBit(LT::toUnderlyingType(info.piece_index));
return result;
}
@ -1406,7 +1390,7 @@ void TorrentImpl::move_impl(QString path, const MoveStorageMode mode) @@ -1406,7 +1390,7 @@ void TorrentImpl::move_impl(QString path, const MoveStorageMode mode)
}
}
void TorrentImpl::forceReannounce(int index)
void TorrentImpl::forceReannounce(const int index)
{
m_nativeHandle.force_reannounce(0, index);
}
@ -1469,28 +1453,29 @@ void TorrentImpl::applyFirstLastPiecePriority(const bool enabled, const QVector< @@ -1469,28 +1453,29 @@ void TorrentImpl::applyFirstLastPiecePriority(const bool enabled, const QVector<
// Download first and last pieces first for every file in the torrent
const std::vector<lt::download_priority_t> filePriorities = !updatedFilePrio.isEmpty() ? toLTDownloadPriorities(updatedFilePrio)
: nativeHandle().get_file_priorities();
const QVector<DownloadPriority> filePriorities =
!updatedFilePrio.isEmpty() ? updatedFilePrio : this->filePriorities();
std::vector<lt::download_priority_t> piecePriorities = nativeHandle().get_piece_priorities();
// Updating file priorities is an async operation in libtorrent, when we just updated it and immediately query it
// we might get the old/wrong values, so we rely on `updatedFilePrio` in this case.
for (int index = 0; index < static_cast<int>(filePriorities.size()); ++index)
for (int index = 0; index < filePriorities.size(); ++index)
{
const lt::download_priority_t filePrio = filePriorities[index];
if (filePrio <= lt::download_priority_t {0})
const DownloadPriority filePrio = filePriorities[index];
if (filePrio <= DownloadPriority::Ignored)
continue;
// Determine the priority to set
const lt::download_priority_t newPrio = enabled ? lt::download_priority_t {7} : filePrio;
const DownloadPriority newPrio = enabled ? DownloadPriority::Maximum : filePrio;
const auto piecePrio = static_cast<lt::download_priority_t>(static_cast<int>(newPrio));
const TorrentInfo::PieceRange extremities = info().filePieces(index);
// worst case: AVI index = 1% of total file size (at the end of the file)
const int nNumPieces = std::ceil(fileSize(index) * 0.01 / pieceLength());
for (int i = 0; i < nNumPieces; ++i)
{
piecePriorities[extremities.first() + i] = newPrio;
piecePriorities[extremities.last() - i] = newPrio;
piecePriorities[extremities.first() + i] = piecePrio;
piecePriorities[extremities.last() - i] = piecePrio;
}
}
@ -1506,14 +1491,16 @@ void TorrentImpl::endReceivedMetadataHandling(const QString &savePath, const QSt @@ -1506,14 +1491,16 @@ void TorrentImpl::endReceivedMetadataHandling(const QString &savePath, const QSt
{
lt::add_torrent_params &p = m_ltAddTorrentParams;
p.ti = std::const_pointer_cast<lt::torrent_info>(m_nativeHandle.torrent_file());
const TorrentInfo torrentInfo {m_nativeHandle.torrent_file()};
const auto nativeIndexes = torrentInfo.nativeIndexes();
for (int i = 0; i < fileNames.size(); ++i)
p.renamed_files[lt::file_index_t {i}] = fileNames[i].toStdString();
p.renamed_files[nativeIndexes[i]] = fileNames[i].toStdString();
p.save_path = Utils::Fs::toNativePath(savePath).toStdString();
p.ti = torrentInfo.nativeInfo();
const int internalFilesCount = p.ti->files().num_files(); // including .pad files
// Use qBittorrent default priority rather than libtorrent's (4)
p.file_priorities = std::vector(fileNames.size(), static_cast<lt::download_priority_t>(
static_cast<lt::download_priority_t::underlying_type>(DownloadPriority::Normal)));
p.file_priorities = std::vector(internalFilesCount, LT::toNative(DownloadPriority::Normal));
reload();
@ -1630,10 +1617,10 @@ void TorrentImpl::renameFile(const int index, const QString &path) @@ -1630,10 +1617,10 @@ void TorrentImpl::renameFile(const int index, const QString &path)
{
#ifndef QBT_USES_LIBTORRENT2
const QString oldPath = filePath(index);
m_oldPath[lt::file_index_t {index}].push_back(oldPath);
m_oldPath[index].push_back(oldPath);
#endif
++m_renameCount;
m_nativeHandle.rename_file(lt::file_index_t {index}, Utils::Fs::toNativePath(path).toStdString());
m_nativeHandle.rename_file(m_torrentInfo.nativeIndexes()[index], Utils::Fs::toNativePath(path).toStdString());
}
void TorrentImpl::handleStateUpdate(const lt::torrent_status &nativeStatus)
@ -1864,13 +1851,16 @@ void TorrentImpl::handleFastResumeRejectedAlert(const lt::fastresume_rejected_al @@ -1864,13 +1851,16 @@ void TorrentImpl::handleFastResumeRejectedAlert(const lt::fastresume_rejected_al
void TorrentImpl::handleFileRenamedAlert(const lt::file_renamed_alert *p)
{
const int fileIndex = m_torrentInfo.nativeIndexes().indexOf(p->index);
Q_ASSERT(fileIndex >= 0);
// Remove empty leftover folders
// For example renaming "a/b/c" to "d/b/c", then folders "a/b" and "a" will
// be removed if they are empty
#ifndef QBT_USES_LIBTORRENT2
const QString oldFilePath = m_oldPath[p->index].takeFirst();
if (m_oldPath[p->index].isEmpty())
m_oldPath.remove(p->index);
const QString oldFilePath = m_oldPath[fileIndex].takeFirst();
if (m_oldPath[fileIndex].isEmpty())
m_oldPath.remove(fileIndex);
#else
const QString oldFilePath = Utils::Fs::toUniformPath(p->old_name());
#endif
@ -1910,14 +1900,16 @@ void TorrentImpl::handleFileRenamedAlert(const lt::file_renamed_alert *p) @@ -1910,14 +1900,16 @@ void TorrentImpl::handleFileRenamedAlert(const lt::file_renamed_alert *p)
void TorrentImpl::handleFileRenameFailedAlert(const lt::file_rename_failed_alert *p)
{
const int fileIndex = m_torrentInfo.nativeIndexes().indexOf(p->index);
Q_ASSERT(fileIndex >= 0);
LogMsg(tr("File rename failed. Torrent: \"%1\", file: \"%2\", reason: \"%3\"")
.arg(name(), filePath(toLTUnderlyingType(p->index))
, QString::fromLocal8Bit(p->error.message().c_str())), Log::WARNING);
.arg(name(), filePath(fileIndex), QString::fromLocal8Bit(p->error.message().c_str())), Log::WARNING);
#ifndef QBT_USES_LIBTORRENT2
m_oldPath[p->index].removeFirst();
if (m_oldPath[p->index].isEmpty())
m_oldPath.remove(p->index);
m_oldPath[fileIndex].removeFirst();
if (m_oldPath[fileIndex].isEmpty())
m_oldPath.remove(fileIndex);
#endif
--m_renameCount;
@ -1929,16 +1921,19 @@ void TorrentImpl::handleFileRenameFailedAlert(const lt::file_rename_failed_alert @@ -1929,16 +1921,19 @@ void TorrentImpl::handleFileRenameFailedAlert(const lt::file_rename_failed_alert
void TorrentImpl::handleFileCompletedAlert(const lt::file_completed_alert *p)
{
const int fileIndex = m_torrentInfo.nativeIndexes().indexOf(p->index);
Q_ASSERT(fileIndex >= 0);
qDebug("A file completed download in torrent \"%s\"", qUtf8Printable(name()));
if (m_session->isAppendExtensionEnabled())
{
QString name = filePath(toLTUnderlyingType(p->index));
QString name = filePath(fileIndex);
if (name.endsWith(QB_EXT))
{
const QString oldName = name;
name.chop(QB_EXT.size());
qDebug("Renaming %s to %s", qUtf8Printable(oldName), qUtf8Printable(name));
renameFile(toLTUnderlyingType(p->index), name);
renameFile(fileIndex, name);
}
}
}
@ -2271,7 +2266,8 @@ QString TorrentImpl::createMagnetURI() const @@ -2271,7 +2266,8 @@ QString TorrentImpl::createMagnetURI() const
void TorrentImpl::prioritizeFiles(const QVector<DownloadPriority> &priorities)
{
if (!hasMetadata()) return;
if (priorities.size() != filesCount()) return;
Q_ASSERT(priorities.size() == filesCount());
// Reset 'm_hasSeedStatus' if needed in order to react again to
// 'torrent_finished_alert' and eg show tray notifications
@ -2288,8 +2284,14 @@ void TorrentImpl::prioritizeFiles(const QVector<DownloadPriority> &priorities) @@ -2288,8 +2284,14 @@ void TorrentImpl::prioritizeFiles(const QVector<DownloadPriority> &priorities)
}
}
const int internalFilesCount = m_torrentInfo.nativeInfo()->files().num_files(); // including .pad files
auto nativePriorities = std::vector<lt::download_priority_t>(internalFilesCount, LT::toNative(DownloadPriority::Normal));
const auto nativeIndexes = m_torrentInfo.nativeIndexes();
for (int i = 0; i < priorities.size(); ++i)
nativePriorities[LT::toUnderlyingType(nativeIndexes[i])] = LT::toNative(priorities[i]);
qDebug() << Q_FUNC_INFO << "Changing files priorities...";
m_nativeHandle.prioritize_files(toLTDownloadPriorities(priorities));
m_nativeHandle.prioritize_files(nativePriorities);
// Restore first/last piece first option if necessary
if (m_hasFirstLastPiecePriority)

5
src/base/bittorrent/torrentimpl.h

@ -126,8 +126,8 @@ namespace BitTorrent @@ -126,8 +126,8 @@ namespace BitTorrent
int seedingTimeLimit() const override;
QString filePath(int index) const override;
QString fileName(int index) const override;
qlonglong fileSize(int index) const override;
QStringList filePaths() const override;
QStringList absoluteFilePaths() const override;
QVector<DownloadPriority> filePriorities() const override;
@ -149,7 +149,6 @@ namespace BitTorrent @@ -149,7 +149,6 @@ namespace BitTorrent
bool hasMetadata() const override;
bool hasMissingFiles() const override;
bool hasError() const override;
bool hasFilteredPieces() const override;
int queuePosition() const override;
QVector<TrackerEntry> trackers() const override;
QVector<QUrl> urlSeeds() const override;
@ -305,7 +304,7 @@ namespace BitTorrent @@ -305,7 +304,7 @@ namespace BitTorrent
#ifndef QBT_USES_LIBTORRENT2
// Until libtorrent provided an "old_name" field in `file_renamed_alert`
// we relied on this workaround to remove empty leftover folders
QHash<lt::file_index_t, QVector<QString>> m_oldPath;
QHash<int, QVector<QString>> m_oldPath;
#endif
QHash<QString, QMap<lt::tcp::endpoint, int>> m_trackerPeerCounts;

59
src/base/bittorrent/torrentinfo.cpp

@ -76,12 +76,23 @@ namespace @@ -76,12 +76,23 @@ namespace
const int torrentInfoId = qRegisterMetaType<TorrentInfo>();
TorrentInfo::TorrentInfo(std::shared_ptr<const lt::torrent_info> nativeInfo)
: m_nativeInfo {std::const_pointer_cast<lt::torrent_info>(nativeInfo)}
{
m_nativeInfo = std::const_pointer_cast<lt::torrent_info>(nativeInfo);
if (!m_nativeInfo)
return;
const lt::file_storage &fileStorage = m_nativeInfo->files();
m_nativeIndexes.reserve(fileStorage.num_files());
for (const lt::file_index_t nativeIndex : fileStorage.file_range())
{
if (!fileStorage.pad_file_at(nativeIndex))
m_nativeIndexes.append(nativeIndex);
}
}
TorrentInfo::TorrentInfo(const TorrentInfo &other)
: m_nativeInfo(other.m_nativeInfo)
: m_nativeInfo {other.m_nativeInfo}
, m_nativeIndexes {other.m_nativeIndexes}
{
}
@ -90,6 +101,7 @@ TorrentInfo &TorrentInfo::operator=(const TorrentInfo &other) @@ -90,6 +101,7 @@ TorrentInfo &TorrentInfo::operator=(const TorrentInfo &other)
if (this != &other)
{
m_nativeInfo = other.m_nativeInfo;
m_nativeIndexes = other.m_nativeIndexes;
}
return *this;
}
@ -241,7 +253,7 @@ qlonglong TorrentInfo::totalSize() const @@ -241,7 +253,7 @@ qlonglong TorrentInfo::totalSize() const
int TorrentInfo::filesCount() const
{
if (!isValid()) return -1;
return m_nativeInfo->num_files();
return m_nativeIndexes.size();
}
int TorrentInfo::pieceLength() const
@ -266,40 +278,36 @@ QString TorrentInfo::filePath(const int index) const @@ -266,40 +278,36 @@ QString TorrentInfo::filePath(const int index) const
{
if (!isValid()) return {};
return Utils::Fs::toUniformPath(
QString::fromStdString(m_nativeInfo->files().file_path(lt::file_index_t {index})));
QString::fromStdString(m_nativeInfo->files().file_path(m_nativeIndexes[index])));
}
QStringList TorrentInfo::filePaths() const
{
QStringList list;
list.reserve(filesCount());
for (int i = 0; i < filesCount(); ++i)
list << filePath(i);
return list;
}
QString TorrentInfo::fileName(const int index) const
{
return Utils::Fs::fileName(filePath(index));
}
QString TorrentInfo::origFilePath(const int index) const
{
if (!isValid()) return {};
return Utils::Fs::toUniformPath(
QString::fromStdString(m_nativeInfo->orig_files().file_path(lt::file_index_t {index})));
QString::fromStdString(m_nativeInfo->orig_files().file_path(m_nativeIndexes[index])));
}
qlonglong TorrentInfo::fileSize(const int index) const
{
if (!isValid()) return -1;
return m_nativeInfo->files().file_size(lt::file_index_t {index});
return m_nativeInfo->files().file_size(m_nativeIndexes[index]);
}
qlonglong TorrentInfo::fileOffset(const int index) const
{
if (!isValid()) return -1;
return m_nativeInfo->files().file_offset(lt::file_index_t {index});
return m_nativeInfo->files().file_offset(m_nativeIndexes[index]);
}
QVector<TrackerEntry> TorrentInfo::trackers() const
@ -368,8 +376,12 @@ QVector<int> TorrentInfo::fileIndicesForPiece(const int pieceIndex) const @@ -368,8 +376,12 @@ QVector<int> TorrentInfo::fileIndicesForPiece(const int pieceIndex) const
lt::piece_index_t {pieceIndex}, 0, nativeInfo()->piece_size(lt::piece_index_t {pieceIndex}));
QVector<int> res;
res.reserve(static_cast<decltype(res)::size_type>(files.size()));
std::transform(files.begin(), files.end(), std::back_inserter(res),
[](const lt::file_slice &s) { return static_cast<int>(s.file_index); });
for (const lt::file_slice &fileSlice : files)
{
const int index = m_nativeIndexes.indexOf(fileSlice.file_index);
if (index >= 0)
res.append(index);
}
return res;
}
@ -415,8 +427,8 @@ TorrentInfo::PieceRange TorrentInfo::filePieces(const int fileIndex) const @@ -415,8 +427,8 @@ TorrentInfo::PieceRange TorrentInfo::filePieces(const int fileIndex) const
}
const lt::file_storage &files = nativeInfo()->files();
const auto fileSize = files.file_size(lt::file_index_t {fileIndex});
const auto fileOffset = files.file_offset(lt::file_index_t {fileIndex});
const auto fileSize = files.file_size(m_nativeIndexes[fileIndex]);
const auto fileOffset = files.file_offset(m_nativeIndexes[fileIndex]);
const int beginIdx = (fileOffset / pieceLength());
const int endIdx = ((fileOffset + fileSize - 1) / pieceLength());
@ -429,7 +441,7 @@ TorrentInfo::PieceRange TorrentInfo::filePieces(const int fileIndex) const @@ -429,7 +441,7 @@ TorrentInfo::PieceRange TorrentInfo::filePieces(const int fileIndex) const
void TorrentInfo::renameFile(const int index, const QString &newPath)
{
if (!isValid()) return;
nativeInfo()->rename_file(lt::file_index_t {index}, Utils::Fs::toNativePath(newPath).toStdString());
nativeInfo()->rename_file(m_nativeIndexes[index], Utils::Fs::toNativePath(newPath).toStdString());
}
int TorrentInfo::fileIndex(const QString &fileName) const
@ -481,8 +493,8 @@ void TorrentInfo::stripRootFolder() @@ -481,8 +493,8 @@ void TorrentInfo::stripRootFolder()
if (files.name() != newName)
{
files.set_name(newName);
for (int i = 0; i < files.num_files(); ++i)
files.rename_file(lt::file_index_t {i}, files.file_path(lt::file_index_t {i}));
for (const lt::file_index_t nativeIndex : files.file_range())
files.rename_file(nativeIndex, files.file_path(nativeIndex));
}
files.set_name("");
@ -501,8 +513,8 @@ void TorrentInfo::addRootFolder() @@ -501,8 +513,8 @@ void TorrentInfo::addRootFolder()
const std::string rootPrefix = Utils::Fs::toNativePath(rootFolder + QLatin1Char {'/'}).toStdString();
lt::file_storage files = m_nativeInfo->files();
files.set_name(rootFolder.toStdString());
for (int i = 0; i < files.num_files(); ++i)
files.rename_file(lt::file_index_t {i}, rootPrefix + files.file_path(lt::file_index_t {i}));
for (const lt::file_index_t nativeIndex : files.file_range())
files.rename_file(nativeIndex, rootPrefix + files.file_path(nativeIndex));
m_nativeInfo->remap_files(files);
}
@ -523,3 +535,8 @@ std::shared_ptr<lt::torrent_info> TorrentInfo::nativeInfo() const @@ -523,3 +535,8 @@ std::shared_ptr<lt::torrent_info> TorrentInfo::nativeInfo() const
{
return m_nativeInfo;
}
QVector<lt::file_index_t> TorrentInfo::nativeIndexes() const
{
return m_nativeIndexes;
}

6
src/base/bittorrent/torrentinfo.h

@ -75,7 +75,6 @@ namespace BitTorrent @@ -75,7 +75,6 @@ namespace BitTorrent
int piecesCount() const;
QString filePath(int index) const override;
QStringList filePaths() const;
QString fileName(int index) const override;
QString origFilePath(int index) const;
qlonglong fileSize(int index) const override;
qlonglong fileOffset(int index) const;
@ -99,6 +98,7 @@ namespace BitTorrent @@ -99,6 +98,7 @@ namespace BitTorrent
void setContentLayout(TorrentContentLayout layout);
std::shared_ptr<lt::torrent_info> nativeInfo() const;
QVector<lt::file_index_t> nativeIndexes() const;
private:
// returns file index or -1 if fileName is not found
@ -108,6 +108,10 @@ namespace BitTorrent @@ -108,6 +108,10 @@ namespace BitTorrent
TorrentContentLayout defaultContentLayout() const;
std::shared_ptr<lt::torrent_info> m_nativeInfo;
// internal indexes of files (payload only, excluding any .pad files)
// by which they are addressed in libtorrent
QVector<lt::file_index_t> m_nativeIndexes;
};
}

2
src/gui/addnewtorrentdialog.cpp

@ -407,9 +407,11 @@ void AddNewTorrentDialog::updateDiskSpaceLabel() @@ -407,9 +407,11 @@ void AddNewTorrentDialog::updateDiskSpaceLabel()
const QVector<BitTorrent::DownloadPriority> priorities = m_contentModel->model()->getFilePriorities();
Q_ASSERT(priorities.size() == m_torrentInfo.filesCount());
for (int i = 0; i < priorities.size(); ++i)
{
if (priorities[i] > BitTorrent::DownloadPriority::Ignored)
torrentSize += m_torrentInfo.fileSize(i);
}
}
else
{
torrentSize = m_torrentInfo.totalSize();

5
src/gui/previewselectdialog.cpp

@ -85,10 +85,9 @@ PreviewSelectDialog::PreviewSelectDialog(QWidget *parent, const BitTorrent::Torr @@ -85,10 +85,9 @@ PreviewSelectDialog::PreviewSelectDialog(QWidget *parent, const BitTorrent::Torr
m_ui->previewList->setAlternatingRowColors(pref->useAlternatingRowColors());
// Fill list in
const QVector<qreal> fp = torrent->filesProgress();
int nbFiles = torrent->filesCount();
for (int i = 0; i < nbFiles; ++i)
for (int i = 0; i <= torrent->filesCount(); ++i)
{
QString fileName = torrent->fileName(i);
QString fileName = Utils::Fs::fileName(torrent->filePath(i));
if (fileName.endsWith(QB_EXT))
fileName.chop(QB_EXT.length());
if (Utils::Misc::isPreviewable(fileName))

5
src/gui/torrentcontentmodel.cpp

@ -283,7 +283,7 @@ bool TorrentContentModel::setData(const QModelIndex &index, const QVariant &valu @@ -283,7 +283,7 @@ bool TorrentContentModel::setData(const QModelIndex &index, const QVariant &valu
if ((index.column() == TorrentContentModelItem::COL_NAME) && (role == Qt::CheckStateRole))
{
auto *item = static_cast<TorrentContentModelItem*>(index.internalPointer());
qDebug("setData(%s, %d", qUtf8Printable(item->name()), value.toInt());
qDebug("setData(%s, %d)", qUtf8Printable(item->name()), value.toInt());
if (static_cast<int>(item->priority()) != value.toInt())
{
BitTorrent::DownloadPriority prio = BitTorrent::DownloadPriority::Normal;
@ -519,7 +519,8 @@ void TorrentContentModel::setupModelData(const BitTorrent::TorrentInfo &info) @@ -519,7 +519,8 @@ void TorrentContentModel::setupModelData(const BitTorrent::TorrentInfo &info)
currentParent = newParent;
}
// Actually create the file
TorrentContentModelFile *fileItem = new TorrentContentModelFile(info.fileName(i), info.fileSize(i), currentParent, i);
TorrentContentModelFile *fileItem = new TorrentContentModelFile(
Utils::Fs::fileName(info.filePath(i)), info.fileSize(i), currentParent, i);
currentParent->appendChild(fileItem);
m_filesIndex.push_back(fileItem);
}

2
src/gui/torrentcontentmodelfolder.cpp

@ -139,9 +139,11 @@ void TorrentContentModelFolder::setPriority(BitTorrent::DownloadPriority newPrio @@ -139,9 +139,11 @@ void TorrentContentModelFolder::setPriority(BitTorrent::DownloadPriority newPrio
// Update children
if (m_priority != BitTorrent::DownloadPriority::Mixed)
{
for (TorrentContentModelItem *child : asConst(m_childItems))
child->setPriority(m_priority, false);
}
}
void TorrentContentModelFolder::recalculateProgress()
{

4
src/gui/transferlistwidget.cpp

@ -91,9 +91,9 @@ namespace @@ -91,9 +91,9 @@ namespace
if (!torrent->hasMetadata())
return false;
for (int i = 0; i < torrent->filesCount(); ++i)
for (const QString &filePath : asConst(torrent->filePaths()))
{
QString fileName = torrent->fileName(i);
QString fileName = Utils::Fs::fileName(filePath);
if (fileName.endsWith(QB_EXT))
fileName.chop(QB_EXT.length());
if (Utils::Misc::isPreviewable(fileName))

Loading…
Cancel
Save