kget: implement partial torrent download via priority

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2021-08-12 16:55:15 +03:00
parent d8086e9fbc
commit 2eb48c6fb4
2 changed files with 102 additions and 10 deletions

View file

@ -18,6 +18,7 @@
#include "transferTorrent.h"
#include <QTimer>
#include <klocale.h>
#include <kdebug.h>
@ -34,6 +35,13 @@
static const int LTPollInterval = 1000;
enum LTPriorities {
Disabled = 0,
LowPriority = 1,
NormalPriority = 4,
HighPriority = 7,
};
static QString translatelterror(lt::error_code lterror)
{
if (lterror == lt::errors::no_error) {
@ -338,7 +346,7 @@ TransferTorrent::TransferTorrent(TransferGroup* parent, TransferFactory* factory
Scheduler* scheduler, const KUrl &source, const KUrl &dest,
const QDomElement* e)
: Transfer(parent, factory, scheduler, source, dest, e),
m_timerid(0), m_ltsession(nullptr), m_filemodel(nullptr)
m_timerid(0), m_ltsession(nullptr), m_filemodel(nullptr), m_recreatefilemodel(false)
{
setCapabilities(Transfer::Cap_SpeedLimit | Transfer::Cap_Resuming);
@ -434,6 +442,9 @@ void TransferTorrent::start()
m_lthandle = m_ltsession->add_torrent(ltparams);
m_lthandle.set_upload_limit(m_uploadLimit * 1024);
m_lthandle.set_download_limit(m_downloadLimit * 1024);
if (m_priorities.size() > 0) {
m_lthandle.prioritize_files(m_priorities);
}
setStatus(Job::Running);
setTransferChange(Transfer::Tc_Status, true);
@ -500,27 +511,40 @@ QList<KUrl> TransferTorrent::files() const
FileModel* TransferTorrent::fileModel()
{
if (m_recreatefilemodel && m_filemodel) {
delete m_filemodel;
m_filemodel = nullptr;
}
if (!m_filemodel) {
m_filemodel = new FileModel(files(), directory(), this);
connect(m_filemodel, SIGNAL(checkStateChanged()), this, SLOT(slotCheckStateChanged()));
// TODO: disable downloading based on check state
// TODO: file status should not be based on global transfer status
if (m_lthandle.torrent_file()) {
const lt::file_storage ltstorage = m_lthandle.torrent_file()->files();
if (ltstorage.is_valid()) {
for (int i = 0; i < ltstorage.num_files(); i++) {
const KUrl filepath = KUrl(ltstorage.file_path(i).c_str());
const KUrl fileurl = KUrl(ltstorage.file_path(i).c_str());
const Qt::CheckState filestate = Qt::Checked;
QModelIndex fileindex = m_filemodel->index(filepath, FileItem::File);
Job::Status filestatus = status();
const int ltpriority = m_lthandle.file_priority(i);
// priority has no effect on finished/seeded torrents
const lt::torrent_status ltstatus = m_lthandle.status();
if (ltstatus.state == lt::torrent_status::seeding || ltstatus.state == lt::torrent_status::finished) {
filestatus = Job::Finished;
// TODO: disable checkbox via custom file model class
} else if (ltpriority == LTPriorities::Disabled) {
filestatus = Job::Stopped;
}
const Qt::CheckState filestate = (ltpriority == LTPriorities::Disabled ? Qt::Unchecked : Qt::Checked);
QModelIndex fileindex = m_filemodel->index(fileurl, FileItem::File);
m_filemodel->setData(fileindex, filestate, Qt::CheckStateRole);
const Job::Status filestatus = status();
QModelIndex statusindex = m_filemodel->index(filepath, FileItem::Status);
QModelIndex statusindex = m_filemodel->index(fileurl, FileItem::Status);
m_filemodel->setData(statusindex, filestatus);
const qlonglong filesize = ltstorage.file_size(i);
QModelIndex sizeindex = m_filemodel->index(filepath, FileItem::Size);
QModelIndex sizeindex = m_filemodel->index(fileurl, FileItem::Size);
m_filemodel->setData(sizeindex, filesize);
}
}
@ -530,15 +554,71 @@ FileModel* TransferTorrent::fileModel()
return m_filemodel;
}
void TransferTorrent::slotCheckStateChanged()
{
Q_ASSERT(m_filemodel);
int counter = 0;
foreach (const KUrl &url, files()) {
const QModelIndex fileindex = m_filemodel->index(url, FileItem::File);
const int checkstate = m_filemodel->data(fileindex, Qt::CheckStateRole).toInt();
if (checkstate != int(Qt::Unchecked)) {
m_lthandle.file_priority(counter, LTPriorities::NormalPriority);
kDebug(5001) << "will downloand" << url;
} else {
m_lthandle.file_priority(counter, LTPriorities::Disabled);
kDebug(5001) << "will not downloand" << url;
}
counter++;
}
}
void TransferTorrent::save(const QDomElement &element)
{
QDomElement elementcopy = element;
QString prioritiesstring;
const std::vector<int> priorities = m_lthandle.file_priorities();
for (int i = 0; i < priorities.size(); i++) {
const int priority = priorities.at(i);
if (i == 0) {
prioritiesstring.append(QString::number(priority));
} else {
prioritiesstring.append(QString::fromLatin1(",") + QString::number(priority));
}
}
elementcopy.setAttribute("FilePriorities", prioritiesstring);
Transfer::save(elementcopy);
}
void TransferTorrent::load(const QDomElement *element)
{
Transfer::load(element);
m_priorities.clear();
if (element) {
const QStringList priorities = element->attribute("FilePriorities").split(",");
foreach (const QString priority, priorities) {
m_priorities.push_back(priority.toInt());
}
}
}
void TransferTorrent::init()
{
// start even if transfer is finished so that torrent is seeded
const bool shouldstart = (policy() != Job::Stop);
if (shouldstart) {
start();
// do it after load(), this is racy
QTimer::singleShot(2000, this, SLOT(slotDelayedStart()));
}
}
void TransferTorrent::slotDelayedStart()
{
start();
}
void TransferTorrent::timerEvent(QTimerEvent *event)
{
if (event->timerId() != m_timerid) {
@ -594,6 +674,9 @@ void TransferTorrent::timerEvent(QTimerEvent *event)
, true
);
} else if (lt::alert_cast<lt::torrent_finished_alert>(ltalert)) {
// see note in TransferTorrent::fileModel()
m_recreatefilemodel = true;
m_lthandle.save_resume_data();
setStatus(Job::FinishedKeepAlive);

View file

@ -24,6 +24,7 @@
#include <QTimerEvent>
#include <vector>
#include <libtorrent/session.hpp>
#include <libtorrent/torrent_handle.hpp>
@ -42,6 +43,8 @@ public:
void deinit(Transfer::DeleteOptions options) final;
QList<KUrl> files() const final;
FileModel* fileModel() final;
void save(const QDomElement &element) final;
void load(const QDomElement *element) final;
// Job reimplementations
void start() final;
@ -55,11 +58,17 @@ protected:
// Transfer reimplementation
void setSpeedLimits(int uploadLimit, int downloadLimit) final;
private Q_SLOTS:
void slotDelayedStart();
void slotCheckStateChanged();
private:
int m_timerid;
lt::session* m_ltsession;
lt::torrent_handle m_lthandle;
FileModel* m_filemodel;
std::vector<int> m_priorities;
bool m_recreatefilemodel;
};
#endif // TRANSFER_TORRENT_H