mirror of
https://github.com/d47081/qBittorrent.git
synced 2025-01-11 07:18:08 +00:00
parent
a8ade3a04b
commit
bc71827c01
@ -17,7 +17,7 @@ add_library(qbt_base STATIC
|
|||||||
bittorrent/infohash.h
|
bittorrent/infohash.h
|
||||||
bittorrent/loadtorrentparams.h
|
bittorrent/loadtorrentparams.h
|
||||||
bittorrent/ltqhash.h
|
bittorrent/ltqhash.h
|
||||||
bittorrent/ltunderlyingtype.h
|
bittorrent/lttypecast.h
|
||||||
bittorrent/magneturi.h
|
bittorrent/magneturi.h
|
||||||
bittorrent/nativesessionextension.h
|
bittorrent/nativesessionextension.h
|
||||||
bittorrent/nativetorrentextension.h
|
bittorrent/nativetorrentextension.h
|
||||||
|
@ -16,7 +16,7 @@ HEADERS += \
|
|||||||
$$PWD/bittorrent/infohash.h \
|
$$PWD/bittorrent/infohash.h \
|
||||||
$$PWD/bittorrent/loadtorrentparams.h \
|
$$PWD/bittorrent/loadtorrentparams.h \
|
||||||
$$PWD/bittorrent/ltqhash.h \
|
$$PWD/bittorrent/ltqhash.h \
|
||||||
$$PWD/bittorrent/ltunderlyingtype.h \
|
$$PWD/bittorrent/lttypecast.h \
|
||||||
$$PWD/bittorrent/magneturi.h \
|
$$PWD/bittorrent/magneturi.h \
|
||||||
$$PWD/bittorrent/nativesessionextension.h \
|
$$PWD/bittorrent/nativesessionextension.h \
|
||||||
$$PWD/bittorrent/nativetorrentextension.h \
|
$$PWD/bittorrent/nativetorrentextension.h \
|
||||||
|
@ -44,7 +44,6 @@ namespace BitTorrent
|
|||||||
|
|
||||||
virtual int filesCount() const = 0;
|
virtual int filesCount() const = 0;
|
||||||
virtual QString filePath(int index) const = 0;
|
virtual QString filePath(int index) const = 0;
|
||||||
virtual QString fileName(int index) const = 0;
|
|
||||||
virtual qlonglong fileSize(int index) const = 0;
|
virtual qlonglong fileSize(int index) const = 0;
|
||||||
|
|
||||||
virtual void renameFile(int index, const QString &name) = 0;
|
virtual void renameFile(int index, const QString &name) = 0;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* 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
|
* 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
|
||||||
@ -28,8 +28,25 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
template <typename T>
|
#include <libtorrent/download_priority.hpp>
|
||||||
typename T::underlying_type toLTUnderlyingType(const T &t)
|
|
||||||
|
#include "downloadpriority.h"
|
||||||
|
|
||||||
|
namespace BitTorrent::LT
|
||||||
{
|
{
|
||||||
return static_cast<typename T::underlying_type>(t);
|
template <typename 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));
|
||||||
|
}
|
||||||
}
|
}
|
@ -93,7 +93,7 @@
|
|||||||
#include "filesearcher.h"
|
#include "filesearcher.h"
|
||||||
#include "filterparserthread.h"
|
#include "filterparserthread.h"
|
||||||
#include "loadtorrentparams.h"
|
#include "loadtorrentparams.h"
|
||||||
#include "ltunderlyingtype.h"
|
#include "lttypecast.h"
|
||||||
#include "magneturi.h"
|
#include "magneturi.h"
|
||||||
#include "nativesessionextension.h"
|
#include "nativesessionextension.h"
|
||||||
#include "portforwarderimpl.h"
|
#include "portforwarderimpl.h"
|
||||||
@ -1491,7 +1491,7 @@ void Session::configurePeerClasses()
|
|||||||
// Proactively do the same for 0.0.0.0 and address_v4::any()
|
// Proactively do the same for 0.0.0.0 and address_v4::any()
|
||||||
f.add_rule(lt::address_v4::any()
|
f.add_rule(lt::address_v4::any()
|
||||||
, lt::address_v4::broadcast()
|
, 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
|
// IPv6 may not be available on OS and the parsing
|
||||||
// would result in an exception -> abnormal program termination
|
// would result in an exception -> abnormal program termination
|
||||||
@ -1500,7 +1500,7 @@ void Session::configurePeerClasses()
|
|||||||
{
|
{
|
||||||
f.add_rule(lt::address_v6::any()
|
f.add_rule(lt::address_v6::any()
|
||||||
, lt::make_address("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
|
, 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 &) {}
|
catch (const std::exception &) {}
|
||||||
|
|
||||||
@ -1509,21 +1509,21 @@ void Session::configurePeerClasses()
|
|||||||
// local networks
|
// local networks
|
||||||
f.add_rule(lt::make_address("10.0.0.0")
|
f.add_rule(lt::make_address("10.0.0.0")
|
||||||
, lt::make_address("10.255.255.255")
|
, 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")
|
f.add_rule(lt::make_address("172.16.0.0")
|
||||||
, lt::make_address("172.31.255.255")
|
, 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")
|
f.add_rule(lt::make_address("192.168.0.0")
|
||||||
, lt::make_address("192.168.255.255")
|
, 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
|
// link local
|
||||||
f.add_rule(lt::make_address("169.254.0.0")
|
f.add_rule(lt::make_address("169.254.0.0")
|
||||||
, lt::make_address("169.254.255.255")
|
, 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
|
// loopback
|
||||||
f.add_rule(lt::make_address("127.0.0.0")
|
f.add_rule(lt::make_address("127.0.0.0")
|
||||||
, lt::make_address("127.255.255.255")
|
, 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
|
// IPv6 may not be available on OS and the parsing
|
||||||
// would result in an exception -> abnormal program termination
|
// would result in an exception -> abnormal program termination
|
||||||
@ -1533,15 +1533,15 @@ void Session::configurePeerClasses()
|
|||||||
// link local
|
// link local
|
||||||
f.add_rule(lt::make_address("fe80::")
|
f.add_rule(lt::make_address("fe80::")
|
||||||
, lt::make_address("febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
|
, 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
|
// unique local addresses
|
||||||
f.add_rule(lt::make_address("fc00::")
|
f.add_rule(lt::make_address("fc00::")
|
||||||
, lt::make_address("fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
|
, 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
|
// loopback
|
||||||
f.add_rule(lt::address_v6::loopback()
|
f.add_rule(lt::address_v6::loopback()
|
||||||
, 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 &) {}
|
catch (const std::exception &) {}
|
||||||
}
|
}
|
||||||
@ -1727,8 +1727,10 @@ void Session::fileSearchFinished(const TorrentID &id, const QString &savePath, c
|
|||||||
lt::add_torrent_params &p = params.ltAddTorrentParams;
|
lt::add_torrent_params &p = params.ltAddTorrentParams;
|
||||||
|
|
||||||
p.save_path = Utils::Fs::toNativePath(savePath).toStdString();
|
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)
|
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);
|
loadTorrent(params);
|
||||||
}
|
}
|
||||||
@ -2141,28 +2143,20 @@ bool Session::addTorrent_impl(const std::variant<MagnetUri, TorrentInfo> &source
|
|||||||
{
|
{
|
||||||
QString contentName = metadata.rootFolder();
|
QString contentName = metadata.rootFolder();
|
||||||
if (contentName.isEmpty() && (metadata.filesCount() == 1))
|
if (contentName.isEmpty() && (metadata.filesCount() == 1))
|
||||||
contentName = metadata.fileName(0);
|
contentName = Utils::Fs::fileName(metadata.filePath(0));
|
||||||
|
|
||||||
if (!contentName.isEmpty() && (contentName != metadata.name()))
|
if (!contentName.isEmpty() && (contentName != metadata.name()))
|
||||||
loadTorrentParams.name = contentName;
|
loadTorrentParams.name = contentName;
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_ASSERT(p.file_priorities.empty());
|
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)
|
||||||
// Use qBittorrent default priority rather than libtorrent's (4)
|
p.file_priorities = std::vector(internalFilesCount, LT::toNative(DownloadPriority::Normal));
|
||||||
p.file_priorities = std::vector(metadata.filesCount(), static_cast<lt::download_priority_t>(
|
const auto nativeIndexes = metadata.nativeIndexes();
|
||||||
static_cast<lt::download_priority_t::underlying_type>(DownloadPriority::Normal)));
|
Q_ASSERT(addTorrentParams.filePriorities.isEmpty() || (addTorrentParams.filePriorities.size() == nativeIndexes.size()));
|
||||||
}
|
for (int i = 0; i < addTorrentParams.filePriorities.size(); ++i)
|
||||||
else
|
p.file_priorities[LT::toUnderlyingType(nativeIndexes[i])] = LT::toNative(addTorrentParams.filePriorities[i]);
|
||||||
{
|
|
||||||
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.ti = metadata.nativeInfo();
|
p.ti = metadata.nativeInfo();
|
||||||
}
|
}
|
||||||
@ -2388,7 +2382,7 @@ void Session::saveTorrentsQueue() const
|
|||||||
for (const TorrentImpl *torrent : asConst(m_torrents))
|
for (const TorrentImpl *torrent : asConst(m_torrents))
|
||||||
{
|
{
|
||||||
// We require actual (non-cached) queue position here!
|
// 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 >= 0)
|
||||||
{
|
{
|
||||||
if (queuePos >= queue.size())
|
if (queuePos >= queue.size())
|
||||||
@ -3937,9 +3931,8 @@ void Session::handleTorrentFinished(TorrentImpl *const torrent)
|
|||||||
|
|
||||||
qDebug("Checking if the torrent contains torrent files to download");
|
qDebug("Checking if the torrent contains torrent files to download");
|
||||||
// Check if there are torrent files inside
|
// 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))
|
if (torrentRelpath.endsWith(".torrent", Qt::CaseInsensitive))
|
||||||
{
|
{
|
||||||
qDebug("Found possible recursive torrent download.");
|
qDebug("Found possible recursive torrent download.");
|
||||||
@ -4162,9 +4155,8 @@ void Session::recursiveTorrentDownload(const TorrentID &id)
|
|||||||
TorrentImpl *const torrent = m_torrents.value(id);
|
TorrentImpl *const torrent = m_torrents.value(id);
|
||||||
if (!torrent) return;
|
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"))
|
if (torrentRelpath.endsWith(".torrent"))
|
||||||
{
|
{
|
||||||
LogMsg(tr("Recursive download of file '%1' embedded in torrent '%2'"
|
LogMsg(tr("Recursive download of file '%1' embedded in torrent '%2'"
|
||||||
|
@ -193,6 +193,7 @@ namespace BitTorrent
|
|||||||
virtual qreal ratioLimit() const = 0;
|
virtual qreal ratioLimit() const = 0;
|
||||||
virtual int seedingTimeLimit() const = 0;
|
virtual int seedingTimeLimit() const = 0;
|
||||||
|
|
||||||
|
virtual QStringList filePaths() const = 0;
|
||||||
virtual QStringList absoluteFilePaths() const = 0;
|
virtual QStringList absoluteFilePaths() const = 0;
|
||||||
virtual QVector<DownloadPriority> filePriorities() const = 0;
|
virtual QVector<DownloadPriority> filePriorities() const = 0;
|
||||||
|
|
||||||
@ -214,7 +215,6 @@ namespace BitTorrent
|
|||||||
virtual bool hasMetadata() const = 0;
|
virtual bool hasMetadata() const = 0;
|
||||||
virtual bool hasMissingFiles() const = 0;
|
virtual bool hasMissingFiles() const = 0;
|
||||||
virtual bool hasError() const = 0;
|
virtual bool hasError() const = 0;
|
||||||
virtual bool hasFilteredPieces() const = 0;
|
|
||||||
virtual int queuePosition() const = 0;
|
virtual int queuePosition() const = 0;
|
||||||
virtual QVector<TrackerEntry> trackers() const = 0;
|
virtual QVector<TrackerEntry> trackers() const = 0;
|
||||||
virtual QVector<QUrl> urlSeeds() const = 0;
|
virtual QVector<QUrl> urlSeeds() const = 0;
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
#include "base/utils/fs.h"
|
#include "base/utils/fs.h"
|
||||||
#include "base/utils/io.h"
|
#include "base/utils/io.h"
|
||||||
#include "base/version.h"
|
#include "base/version.h"
|
||||||
#include "ltunderlyingtype.h"
|
#include "lttypecast.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@ -186,7 +186,7 @@ void TorrentCreatorThread::run()
|
|||||||
, [this, &newTorrent](const lt::piece_index_t n)
|
, [this, &newTorrent](const lt::piece_index_t n)
|
||||||
{
|
{
|
||||||
checkInterruptionRequested();
|
checkInterruptionRequested();
|
||||||
sendProgressSignal(toLTUnderlyingType(n), newTorrent.num_pieces());
|
sendProgressSignal(LT::toUnderlyingType(n), newTorrent.num_pieces());
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set qBittorrent as creator and add user comment to
|
// Set qBittorrent as creator and add user comment to
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
#include "downloadpriority.h"
|
#include "downloadpriority.h"
|
||||||
#include "loadtorrentparams.h"
|
#include "loadtorrentparams.h"
|
||||||
#include "ltqhash.h"
|
#include "ltqhash.h"
|
||||||
#include "ltunderlyingtype.h"
|
#include "lttypecast.h"
|
||||||
#include "peeraddress.h"
|
#include "peeraddress.h"
|
||||||
#include "peerinfo.h"
|
#include "peerinfo.h"
|
||||||
#include "session.h"
|
#include "session.h"
|
||||||
@ -74,20 +74,6 @@ using namespace BitTorrent;
|
|||||||
|
|
||||||
namespace
|
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 makeNativeAnnouncerEntry(const QString &url, const int tier)
|
||||||
{
|
{
|
||||||
lt::announce_entry entry {url.toStdString()};
|
lt::announce_entry entry {url.toStdString()};
|
||||||
@ -762,30 +748,30 @@ int TorrentImpl::seedingTimeLimit() const
|
|||||||
return m_seedingTimeLimit;
|
return m_seedingTimeLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString TorrentImpl::filePath(int index) const
|
QString TorrentImpl::filePath(const int index) const
|
||||||
{
|
{
|
||||||
return m_torrentInfo.filePath(index);
|
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
qlonglong TorrentImpl::fileSize(int index) const
|
|
||||||
{
|
{
|
||||||
return m_torrentInfo.fileSize(index);
|
return m_torrentInfo.fileSize(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList TorrentImpl::filePaths() const
|
||||||
|
{
|
||||||
|
return m_torrentInfo.filePaths();
|
||||||
|
}
|
||||||
|
|
||||||
// Return a list of absolute paths corresponding
|
// Return a list of absolute paths corresponding
|
||||||
// to all files in a torrent
|
// to all files in a torrent
|
||||||
QStringList TorrentImpl::absoluteFilePaths() const
|
QStringList TorrentImpl::absoluteFilePaths() const
|
||||||
{
|
{
|
||||||
if (!hasMetadata()) return {};
|
if (!hasMetadata()) return {};
|
||||||
|
|
||||||
const QDir saveDir(savePath(true));
|
const QDir saveDir {savePath(true)};
|
||||||
QStringList res;
|
QStringList res;
|
||||||
|
res.reserve(filesCount());
|
||||||
for (int i = 0; i < filesCount(); ++i)
|
for (int i = 0; i < filesCount(); ++i)
|
||||||
res << Utils::Fs::expandPathAbs(saveDir.absoluteFilePath(filePath(i)));
|
res << Utils::Fs::expandPathAbs(saveDir.absoluteFilePath(filePath(i)));
|
||||||
return res;
|
return res;
|
||||||
@ -793,14 +779,19 @@ QStringList TorrentImpl::absoluteFilePaths() const
|
|||||||
|
|
||||||
QVector<DownloadPriority> TorrentImpl::filePriorities() const
|
QVector<DownloadPriority> TorrentImpl::filePriorities() const
|
||||||
{
|
{
|
||||||
|
if (!hasMetadata())
|
||||||
|
return {};
|
||||||
|
|
||||||
const std::vector<lt::download_priority_t> fp = m_nativeHandle.get_file_priorities();
|
const std::vector<lt::download_priority_t> fp = m_nativeHandle.get_file_priorities();
|
||||||
|
|
||||||
QVector<DownloadPriority> ret;
|
QVector<DownloadPriority> ret;
|
||||||
ret.reserve(static_cast<decltype(ret)::size_type>(fp.size()));
|
ret.reserve(filesCount());
|
||||||
std::transform(fp.cbegin(), fp.cend(), std::back_inserter(ret), [](const lt::download_priority_t priority)
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -987,15 +978,6 @@ bool TorrentImpl::hasError() const
|
|||||||
return (m_nativeStatus.errc || (m_nativeStatus.flags & lt::torrent_flags::upload_mode));
|
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
|
int TorrentImpl::queuePosition() const
|
||||||
{
|
{
|
||||||
return static_cast<int>(m_nativeStatus.queue_position);
|
return static_cast<int>(m_nativeStatus.queue_position);
|
||||||
@ -1092,16 +1074,18 @@ QVector<qreal> TorrentImpl::filesProgress() const
|
|||||||
std::vector<int64_t> fp;
|
std::vector<int64_t> fp;
|
||||||
m_nativeHandle.file_progress(fp, lt::torrent_handle::piece_granularity);
|
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;
|
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 qlonglong size = fileSize(i);
|
const qlonglong size = fileSize(i);
|
||||||
if ((size <= 0) || (fp[i] == size))
|
if ((size <= 0) || (progress == size))
|
||||||
result << 1;
|
result << 1;
|
||||||
else
|
else
|
||||||
result << (fp[i] / static_cast<qreal>(size));
|
result << (progress / static_cast<qreal>(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -1252,7 +1236,7 @@ QBitArray TorrentImpl::downloadingPieces() const
|
|||||||
m_nativeHandle.get_download_queue(queue);
|
m_nativeHandle.get_download_queue(queue);
|
||||||
|
|
||||||
for (const lt::partial_piece_info &info : queue)
|
for (const lt::partial_piece_info &info : queue)
|
||||||
result.setBit(toLTUnderlyingType(info.piece_index));
|
result.setBit(LT::toUnderlyingType(info.piece_index));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -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);
|
m_nativeHandle.force_reannounce(0, index);
|
||||||
}
|
}
|
||||||
@ -1469,28 +1453,29 @@ void TorrentImpl::applyFirstLastPiecePriority(const bool enabled, const QVector<
|
|||||||
|
|
||||||
// Download first and last pieces first for every file in the torrent
|
// Download first and last pieces first for every file in the torrent
|
||||||
|
|
||||||
const std::vector<lt::download_priority_t> filePriorities = !updatedFilePrio.isEmpty() ? toLTDownloadPriorities(updatedFilePrio)
|
const QVector<DownloadPriority> filePriorities =
|
||||||
: nativeHandle().get_file_priorities();
|
!updatedFilePrio.isEmpty() ? updatedFilePrio : this->filePriorities();
|
||||||
std::vector<lt::download_priority_t> piecePriorities = nativeHandle().get_piece_priorities();
|
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
|
// 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.
|
// 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];
|
const DownloadPriority filePrio = filePriorities[index];
|
||||||
if (filePrio <= lt::download_priority_t {0})
|
if (filePrio <= DownloadPriority::Ignored)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Determine the priority to set
|
// 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);
|
const TorrentInfo::PieceRange extremities = info().filePieces(index);
|
||||||
|
|
||||||
// worst case: AVI index = 1% of total file size (at the end of the file)
|
// 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());
|
const int nNumPieces = std::ceil(fileSize(index) * 0.01 / pieceLength());
|
||||||
for (int i = 0; i < nNumPieces; ++i)
|
for (int i = 0; i < nNumPieces; ++i)
|
||||||
{
|
{
|
||||||
piecePriorities[extremities.first() + i] = newPrio;
|
piecePriorities[extremities.first() + i] = piecePrio;
|
||||||
piecePriorities[extremities.last() - i] = newPrio;
|
piecePriorities[extremities.last() - i] = piecePrio;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1506,14 +1491,16 @@ void TorrentImpl::endReceivedMetadataHandling(const QString &savePath, const QSt
|
|||||||
{
|
{
|
||||||
lt::add_torrent_params &p = m_ltAddTorrentParams;
|
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)
|
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.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)
|
// Use qBittorrent default priority rather than libtorrent's (4)
|
||||||
p.file_priorities = std::vector(fileNames.size(), static_cast<lt::download_priority_t>(
|
p.file_priorities = std::vector(internalFilesCount, LT::toNative(DownloadPriority::Normal));
|
||||||
static_cast<lt::download_priority_t::underlying_type>(DownloadPriority::Normal)));
|
|
||||||
|
|
||||||
reload();
|
reload();
|
||||||
|
|
||||||
@ -1630,10 +1617,10 @@ void TorrentImpl::renameFile(const int index, const QString &path)
|
|||||||
{
|
{
|
||||||
#ifndef QBT_USES_LIBTORRENT2
|
#ifndef QBT_USES_LIBTORRENT2
|
||||||
const QString oldPath = filePath(index);
|
const QString oldPath = filePath(index);
|
||||||
m_oldPath[lt::file_index_t {index}].push_back(oldPath);
|
m_oldPath[index].push_back(oldPath);
|
||||||
#endif
|
#endif
|
||||||
++m_renameCount;
|
++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)
|
void TorrentImpl::handleStateUpdate(const lt::torrent_status &nativeStatus)
|
||||||
@ -1864,13 +1851,16 @@ void TorrentImpl::handleFastResumeRejectedAlert(const lt::fastresume_rejected_al
|
|||||||
|
|
||||||
void TorrentImpl::handleFileRenamedAlert(const lt::file_renamed_alert *p)
|
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
|
// Remove empty leftover folders
|
||||||
// For example renaming "a/b/c" to "d/b/c", then folders "a/b" and "a" will
|
// For example renaming "a/b/c" to "d/b/c", then folders "a/b" and "a" will
|
||||||
// be removed if they are empty
|
// be removed if they are empty
|
||||||
#ifndef QBT_USES_LIBTORRENT2
|
#ifndef QBT_USES_LIBTORRENT2
|
||||||
const QString oldFilePath = m_oldPath[p->index].takeFirst();
|
const QString oldFilePath = m_oldPath[fileIndex].takeFirst();
|
||||||
if (m_oldPath[p->index].isEmpty())
|
if (m_oldPath[fileIndex].isEmpty())
|
||||||
m_oldPath.remove(p->index);
|
m_oldPath.remove(fileIndex);
|
||||||
#else
|
#else
|
||||||
const QString oldFilePath = Utils::Fs::toUniformPath(p->old_name());
|
const QString oldFilePath = Utils::Fs::toUniformPath(p->old_name());
|
||||||
#endif
|
#endif
|
||||||
@ -1910,14 +1900,16 @@ void TorrentImpl::handleFileRenamedAlert(const lt::file_renamed_alert *p)
|
|||||||
|
|
||||||
void TorrentImpl::handleFileRenameFailedAlert(const lt::file_rename_failed_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\"")
|
LogMsg(tr("File rename failed. Torrent: \"%1\", file: \"%2\", reason: \"%3\"")
|
||||||
.arg(name(), filePath(toLTUnderlyingType(p->index))
|
.arg(name(), filePath(fileIndex), QString::fromLocal8Bit(p->error.message().c_str())), Log::WARNING);
|
||||||
, QString::fromLocal8Bit(p->error.message().c_str())), Log::WARNING);
|
|
||||||
|
|
||||||
#ifndef QBT_USES_LIBTORRENT2
|
#ifndef QBT_USES_LIBTORRENT2
|
||||||
m_oldPath[p->index].removeFirst();
|
m_oldPath[fileIndex].removeFirst();
|
||||||
if (m_oldPath[p->index].isEmpty())
|
if (m_oldPath[fileIndex].isEmpty())
|
||||||
m_oldPath.remove(p->index);
|
m_oldPath.remove(fileIndex);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
--m_renameCount;
|
--m_renameCount;
|
||||||
@ -1929,16 +1921,19 @@ void TorrentImpl::handleFileRenameFailedAlert(const lt::file_rename_failed_alert
|
|||||||
|
|
||||||
void TorrentImpl::handleFileCompletedAlert(const lt::file_completed_alert *p)
|
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()));
|
qDebug("A file completed download in torrent \"%s\"", qUtf8Printable(name()));
|
||||||
if (m_session->isAppendExtensionEnabled())
|
if (m_session->isAppendExtensionEnabled())
|
||||||
{
|
{
|
||||||
QString name = filePath(toLTUnderlyingType(p->index));
|
QString name = filePath(fileIndex);
|
||||||
if (name.endsWith(QB_EXT))
|
if (name.endsWith(QB_EXT))
|
||||||
{
|
{
|
||||||
const QString oldName = name;
|
const QString oldName = name;
|
||||||
name.chop(QB_EXT.size());
|
name.chop(QB_EXT.size());
|
||||||
qDebug("Renaming %s to %s", qUtf8Printable(oldName), qUtf8Printable(name));
|
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
|
|||||||
void TorrentImpl::prioritizeFiles(const QVector<DownloadPriority> &priorities)
|
void TorrentImpl::prioritizeFiles(const QVector<DownloadPriority> &priorities)
|
||||||
{
|
{
|
||||||
if (!hasMetadata()) return;
|
if (!hasMetadata()) return;
|
||||||
if (priorities.size() != filesCount()) return;
|
|
||||||
|
Q_ASSERT(priorities.size() == filesCount());
|
||||||
|
|
||||||
// Reset 'm_hasSeedStatus' if needed in order to react again to
|
// Reset 'm_hasSeedStatus' if needed in order to react again to
|
||||||
// 'torrent_finished_alert' and eg show tray notifications
|
// 'torrent_finished_alert' and eg show tray notifications
|
||||||
@ -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...";
|
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
|
// Restore first/last piece first option if necessary
|
||||||
if (m_hasFirstLastPiecePriority)
|
if (m_hasFirstLastPiecePriority)
|
||||||
|
@ -126,8 +126,8 @@ namespace BitTorrent
|
|||||||
int seedingTimeLimit() const override;
|
int seedingTimeLimit() const override;
|
||||||
|
|
||||||
QString filePath(int index) const override;
|
QString filePath(int index) const override;
|
||||||
QString fileName(int index) const override;
|
|
||||||
qlonglong fileSize(int index) const override;
|
qlonglong fileSize(int index) const override;
|
||||||
|
QStringList filePaths() const override;
|
||||||
QStringList absoluteFilePaths() const override;
|
QStringList absoluteFilePaths() const override;
|
||||||
QVector<DownloadPriority> filePriorities() const override;
|
QVector<DownloadPriority> filePriorities() const override;
|
||||||
|
|
||||||
@ -149,7 +149,6 @@ namespace BitTorrent
|
|||||||
bool hasMetadata() const override;
|
bool hasMetadata() const override;
|
||||||
bool hasMissingFiles() const override;
|
bool hasMissingFiles() const override;
|
||||||
bool hasError() const override;
|
bool hasError() const override;
|
||||||
bool hasFilteredPieces() const override;
|
|
||||||
int queuePosition() const override;
|
int queuePosition() const override;
|
||||||
QVector<TrackerEntry> trackers() const override;
|
QVector<TrackerEntry> trackers() const override;
|
||||||
QVector<QUrl> urlSeeds() const override;
|
QVector<QUrl> urlSeeds() const override;
|
||||||
@ -305,7 +304,7 @@ namespace BitTorrent
|
|||||||
#ifndef QBT_USES_LIBTORRENT2
|
#ifndef QBT_USES_LIBTORRENT2
|
||||||
// Until libtorrent provided an "old_name" field in `file_renamed_alert`
|
// Until libtorrent provided an "old_name" field in `file_renamed_alert`
|
||||||
// we relied on this workaround to remove empty leftover folders
|
// 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
|
#endif
|
||||||
|
|
||||||
QHash<QString, QMap<lt::tcp::endpoint, int>> m_trackerPeerCounts;
|
QHash<QString, QMap<lt::tcp::endpoint, int>> m_trackerPeerCounts;
|
||||||
|
@ -76,12 +76,23 @@ namespace
|
|||||||
const int torrentInfoId = qRegisterMetaType<TorrentInfo>();
|
const int torrentInfoId = qRegisterMetaType<TorrentInfo>();
|
||||||
|
|
||||||
TorrentInfo::TorrentInfo(std::shared_ptr<const lt::torrent_info> nativeInfo)
|
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)
|
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)
|
|||||||
if (this != &other)
|
if (this != &other)
|
||||||
{
|
{
|
||||||
m_nativeInfo = other.m_nativeInfo;
|
m_nativeInfo = other.m_nativeInfo;
|
||||||
|
m_nativeIndexes = other.m_nativeIndexes;
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -241,7 +253,7 @@ qlonglong TorrentInfo::totalSize() const
|
|||||||
int TorrentInfo::filesCount() const
|
int TorrentInfo::filesCount() const
|
||||||
{
|
{
|
||||||
if (!isValid()) return -1;
|
if (!isValid()) return -1;
|
||||||
return m_nativeInfo->num_files();
|
return m_nativeIndexes.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
int TorrentInfo::pieceLength() const
|
int TorrentInfo::pieceLength() const
|
||||||
@ -266,40 +278,36 @@ QString TorrentInfo::filePath(const int index) const
|
|||||||
{
|
{
|
||||||
if (!isValid()) return {};
|
if (!isValid()) return {};
|
||||||
return Utils::Fs::toUniformPath(
|
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 TorrentInfo::filePaths() const
|
||||||
{
|
{
|
||||||
QStringList list;
|
QStringList list;
|
||||||
|
list.reserve(filesCount());
|
||||||
for (int i = 0; i < filesCount(); ++i)
|
for (int i = 0; i < filesCount(); ++i)
|
||||||
list << filePath(i);
|
list << filePath(i);
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString TorrentInfo::fileName(const int index) const
|
|
||||||
{
|
|
||||||
return Utils::Fs::fileName(filePath(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
QString TorrentInfo::origFilePath(const int index) const
|
QString TorrentInfo::origFilePath(const int index) const
|
||||||
{
|
{
|
||||||
if (!isValid()) return {};
|
if (!isValid()) return {};
|
||||||
return Utils::Fs::toUniformPath(
|
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
|
qlonglong TorrentInfo::fileSize(const int index) const
|
||||||
{
|
{
|
||||||
if (!isValid()) return -1;
|
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
|
qlonglong TorrentInfo::fileOffset(const int index) const
|
||||||
{
|
{
|
||||||
if (!isValid()) return -1;
|
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
|
QVector<TrackerEntry> TorrentInfo::trackers() 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}));
|
lt::piece_index_t {pieceIndex}, 0, nativeInfo()->piece_size(lt::piece_index_t {pieceIndex}));
|
||||||
QVector<int> res;
|
QVector<int> res;
|
||||||
res.reserve(static_cast<decltype(res)::size_type>(files.size()));
|
res.reserve(static_cast<decltype(res)::size_type>(files.size()));
|
||||||
std::transform(files.begin(), files.end(), std::back_inserter(res),
|
for (const lt::file_slice &fileSlice : files)
|
||||||
[](const lt::file_slice &s) { return static_cast<int>(s.file_index); });
|
{
|
||||||
|
const int index = m_nativeIndexes.indexOf(fileSlice.file_index);
|
||||||
|
if (index >= 0)
|
||||||
|
res.append(index);
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -415,8 +427,8 @@ TorrentInfo::PieceRange TorrentInfo::filePieces(const int fileIndex) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
const lt::file_storage &files = nativeInfo()->files();
|
const lt::file_storage &files = nativeInfo()->files();
|
||||||
const auto fileSize = files.file_size(lt::file_index_t {fileIndex});
|
const auto fileSize = files.file_size(m_nativeIndexes[fileIndex]);
|
||||||
const auto fileOffset = files.file_offset(lt::file_index_t {fileIndex});
|
const auto fileOffset = files.file_offset(m_nativeIndexes[fileIndex]);
|
||||||
|
|
||||||
const int beginIdx = (fileOffset / pieceLength());
|
const int beginIdx = (fileOffset / pieceLength());
|
||||||
const int endIdx = ((fileOffset + fileSize - 1) / pieceLength());
|
const int endIdx = ((fileOffset + fileSize - 1) / pieceLength());
|
||||||
@ -429,7 +441,7 @@ TorrentInfo::PieceRange TorrentInfo::filePieces(const int fileIndex) const
|
|||||||
void TorrentInfo::renameFile(const int index, const QString &newPath)
|
void TorrentInfo::renameFile(const int index, const QString &newPath)
|
||||||
{
|
{
|
||||||
if (!isValid()) return;
|
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
|
int TorrentInfo::fileIndex(const QString &fileName) const
|
||||||
@ -481,8 +493,8 @@ void TorrentInfo::stripRootFolder()
|
|||||||
if (files.name() != newName)
|
if (files.name() != newName)
|
||||||
{
|
{
|
||||||
files.set_name(newName);
|
files.set_name(newName);
|
||||||
for (int i = 0; i < files.num_files(); ++i)
|
for (const lt::file_index_t nativeIndex : files.file_range())
|
||||||
files.rename_file(lt::file_index_t {i}, files.file_path(lt::file_index_t {i}));
|
files.rename_file(nativeIndex, files.file_path(nativeIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
files.set_name("");
|
files.set_name("");
|
||||||
@ -501,8 +513,8 @@ void TorrentInfo::addRootFolder()
|
|||||||
const std::string rootPrefix = Utils::Fs::toNativePath(rootFolder + QLatin1Char {'/'}).toStdString();
|
const std::string rootPrefix = Utils::Fs::toNativePath(rootFolder + QLatin1Char {'/'}).toStdString();
|
||||||
lt::file_storage files = m_nativeInfo->files();
|
lt::file_storage files = m_nativeInfo->files();
|
||||||
files.set_name(rootFolder.toStdString());
|
files.set_name(rootFolder.toStdString());
|
||||||
for (int i = 0; i < files.num_files(); ++i)
|
for (const lt::file_index_t nativeIndex : files.file_range())
|
||||||
files.rename_file(lt::file_index_t {i}, rootPrefix + files.file_path(lt::file_index_t {i}));
|
files.rename_file(nativeIndex, rootPrefix + files.file_path(nativeIndex));
|
||||||
m_nativeInfo->remap_files(files);
|
m_nativeInfo->remap_files(files);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,3 +535,8 @@ std::shared_ptr<lt::torrent_info> TorrentInfo::nativeInfo() const
|
|||||||
{
|
{
|
||||||
return m_nativeInfo;
|
return m_nativeInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVector<lt::file_index_t> TorrentInfo::nativeIndexes() const
|
||||||
|
{
|
||||||
|
return m_nativeIndexes;
|
||||||
|
}
|
||||||
|
@ -75,7 +75,6 @@ namespace BitTorrent
|
|||||||
int piecesCount() const;
|
int piecesCount() const;
|
||||||
QString filePath(int index) const override;
|
QString filePath(int index) const override;
|
||||||
QStringList filePaths() const;
|
QStringList filePaths() const;
|
||||||
QString fileName(int index) const override;
|
|
||||||
QString origFilePath(int index) const;
|
QString origFilePath(int index) const;
|
||||||
qlonglong fileSize(int index) const override;
|
qlonglong fileSize(int index) const override;
|
||||||
qlonglong fileOffset(int index) const;
|
qlonglong fileOffset(int index) const;
|
||||||
@ -99,6 +98,7 @@ namespace BitTorrent
|
|||||||
void setContentLayout(TorrentContentLayout layout);
|
void setContentLayout(TorrentContentLayout layout);
|
||||||
|
|
||||||
std::shared_ptr<lt::torrent_info> nativeInfo() const;
|
std::shared_ptr<lt::torrent_info> nativeInfo() const;
|
||||||
|
QVector<lt::file_index_t> nativeIndexes() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// returns file index or -1 if fileName is not found
|
// returns file index or -1 if fileName is not found
|
||||||
@ -108,6 +108,10 @@ namespace BitTorrent
|
|||||||
TorrentContentLayout defaultContentLayout() const;
|
TorrentContentLayout defaultContentLayout() const;
|
||||||
|
|
||||||
std::shared_ptr<lt::torrent_info> m_nativeInfo;
|
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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,8 +407,10 @@ void AddNewTorrentDialog::updateDiskSpaceLabel()
|
|||||||
const QVector<BitTorrent::DownloadPriority> priorities = m_contentModel->model()->getFilePriorities();
|
const QVector<BitTorrent::DownloadPriority> priorities = m_contentModel->model()->getFilePriorities();
|
||||||
Q_ASSERT(priorities.size() == m_torrentInfo.filesCount());
|
Q_ASSERT(priorities.size() == m_torrentInfo.filesCount());
|
||||||
for (int i = 0; i < priorities.size(); ++i)
|
for (int i = 0; i < priorities.size(); ++i)
|
||||||
|
{
|
||||||
if (priorities[i] > BitTorrent::DownloadPriority::Ignored)
|
if (priorities[i] > BitTorrent::DownloadPriority::Ignored)
|
||||||
torrentSize += m_torrentInfo.fileSize(i);
|
torrentSize += m_torrentInfo.fileSize(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -85,10 +85,9 @@ PreviewSelectDialog::PreviewSelectDialog(QWidget *parent, const BitTorrent::Torr
|
|||||||
m_ui->previewList->setAlternatingRowColors(pref->useAlternatingRowColors());
|
m_ui->previewList->setAlternatingRowColors(pref->useAlternatingRowColors());
|
||||||
// Fill list in
|
// Fill list in
|
||||||
const QVector<qreal> fp = torrent->filesProgress();
|
const QVector<qreal> fp = torrent->filesProgress();
|
||||||
int nbFiles = torrent->filesCount();
|
for (int i = 0; i <= torrent->filesCount(); ++i)
|
||||||
for (int i = 0; i < nbFiles; ++i)
|
|
||||||
{
|
{
|
||||||
QString fileName = torrent->fileName(i);
|
QString fileName = Utils::Fs::fileName(torrent->filePath(i));
|
||||||
if (fileName.endsWith(QB_EXT))
|
if (fileName.endsWith(QB_EXT))
|
||||||
fileName.chop(QB_EXT.length());
|
fileName.chop(QB_EXT.length());
|
||||||
if (Utils::Misc::isPreviewable(fileName))
|
if (Utils::Misc::isPreviewable(fileName))
|
||||||
|
@ -283,7 +283,7 @@ bool TorrentContentModel::setData(const QModelIndex &index, const QVariant &valu
|
|||||||
if ((index.column() == TorrentContentModelItem::COL_NAME) && (role == Qt::CheckStateRole))
|
if ((index.column() == TorrentContentModelItem::COL_NAME) && (role == Qt::CheckStateRole))
|
||||||
{
|
{
|
||||||
auto *item = static_cast<TorrentContentModelItem*>(index.internalPointer());
|
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())
|
if (static_cast<int>(item->priority()) != value.toInt())
|
||||||
{
|
{
|
||||||
BitTorrent::DownloadPriority prio = BitTorrent::DownloadPriority::Normal;
|
BitTorrent::DownloadPriority prio = BitTorrent::DownloadPriority::Normal;
|
||||||
@ -349,7 +349,7 @@ QVariant TorrentContentModel::data(const QModelIndex &index, const int role) con
|
|||||||
switch (role)
|
switch (role)
|
||||||
{
|
{
|
||||||
case Qt::DecorationRole:
|
case Qt::DecorationRole:
|
||||||
{
|
{
|
||||||
if (index.column() != TorrentContentModelItem::COL_NAME)
|
if (index.column() != TorrentContentModelItem::COL_NAME)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
@ -358,7 +358,7 @@ QVariant TorrentContentModel::data(const QModelIndex &index, const int role) con
|
|||||||
return m_fileIconProvider->icon(QFileInfo(item->name()));
|
return m_fileIconProvider->icon(QFileInfo(item->name()));
|
||||||
}
|
}
|
||||||
case Qt::CheckStateRole:
|
case Qt::CheckStateRole:
|
||||||
{
|
{
|
||||||
if (index.column() != TorrentContentModelItem::COL_NAME)
|
if (index.column() != TorrentContentModelItem::COL_NAME)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
@ -519,7 +519,8 @@ void TorrentContentModel::setupModelData(const BitTorrent::TorrentInfo &info)
|
|||||||
currentParent = newParent;
|
currentParent = newParent;
|
||||||
}
|
}
|
||||||
// Actually create the file
|
// 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);
|
currentParent->appendChild(fileItem);
|
||||||
m_filesIndex.push_back(fileItem);
|
m_filesIndex.push_back(fileItem);
|
||||||
}
|
}
|
||||||
|
@ -139,8 +139,10 @@ void TorrentContentModelFolder::setPriority(BitTorrent::DownloadPriority newPrio
|
|||||||
|
|
||||||
// Update children
|
// Update children
|
||||||
if (m_priority != BitTorrent::DownloadPriority::Mixed)
|
if (m_priority != BitTorrent::DownloadPriority::Mixed)
|
||||||
|
{
|
||||||
for (TorrentContentModelItem *child : asConst(m_childItems))
|
for (TorrentContentModelItem *child : asConst(m_childItems))
|
||||||
child->setPriority(m_priority, false);
|
child->setPriority(m_priority, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TorrentContentModelFolder::recalculateProgress()
|
void TorrentContentModelFolder::recalculateProgress()
|
||||||
|
@ -91,9 +91,9 @@ namespace
|
|||||||
if (!torrent->hasMetadata())
|
if (!torrent->hasMetadata())
|
||||||
return false;
|
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))
|
if (fileName.endsWith(QB_EXT))
|
||||||
fileName.chop(QB_EXT.length());
|
fileName.chop(QB_EXT.length());
|
||||||
if (Utils::Misc::isPreviewable(fileName))
|
if (Utils::Misc::isPreviewable(fileName))
|
||||||
|
Loading…
Reference in New Issue
Block a user