mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-08-20 21:33:27 -07:00
parent
15069b2643
commit
2785636d3f
3 changed files with 93 additions and 77 deletions
|
@ -290,6 +290,8 @@ BitTorrent::LoadResumeDataResult BitTorrent::BencodeResumeDataStorage::loadTorre
|
||||||
lt::add_torrent_params &p = torrentParams.ltAddTorrentParams;
|
lt::add_torrent_params &p = torrentParams.ltAddTorrentParams;
|
||||||
|
|
||||||
p = lt::read_resume_data(resumeDataRoot, ec);
|
p = lt::read_resume_data(resumeDataRoot, ec);
|
||||||
|
if (ec)
|
||||||
|
return nonstd::make_unexpected(tr("Cannot parse resume data: %1").arg(QString::fromStdString(ec.message())));
|
||||||
|
|
||||||
if (!metadata.isEmpty())
|
if (!metadata.isEmpty())
|
||||||
{
|
{
|
||||||
|
@ -320,6 +322,8 @@ BitTorrent::LoadResumeDataResult BitTorrent::BencodeResumeDataStorage::loadTorre
|
||||||
|
|
||||||
p.save_path = Profile::instance()->fromPortablePath(
|
p.save_path = Profile::instance()->fromPortablePath(
|
||||||
Path(fromLTString(p.save_path))).toString().toStdString();
|
Path(fromLTString(p.save_path))).toString().toStdString();
|
||||||
|
if (p.save_path.empty())
|
||||||
|
return nonstd::make_unexpected(tr("Corrupted resume data: %1").arg(tr("save_path is invalid")));
|
||||||
|
|
||||||
torrentParams.stopped = (p.flags & lt::torrent_flags::paused) && !(p.flags & lt::torrent_flags::auto_managed);
|
torrentParams.stopped = (p.flags & lt::torrent_flags::paused) && !(p.flags & lt::torrent_flags::auto_managed);
|
||||||
torrentParams.operatingMode = (p.flags & lt::torrent_flags::paused) || (p.flags & lt::torrent_flags::auto_managed)
|
torrentParams.operatingMode = (p.flags & lt::torrent_flags::paused) || (p.flags & lt::torrent_flags::auto_managed)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2021-2023 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2021-2025 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
|
||||||
|
@ -217,80 +217,6 @@ namespace
|
||||||
{
|
{
|
||||||
return u"%1 %2"_s.arg(quoted(column.name), definition);
|
return u"%1 %2"_s.arg(quoted(column.name), definition);
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadTorrentParams parseQueryResultRow(const QSqlQuery &query)
|
|
||||||
{
|
|
||||||
LoadTorrentParams resumeData;
|
|
||||||
resumeData.name = query.value(DB_COLUMN_NAME.name).toString();
|
|
||||||
resumeData.category = query.value(DB_COLUMN_CATEGORY.name).toString();
|
|
||||||
const QString tagsData = query.value(DB_COLUMN_TAGS.name).toString();
|
|
||||||
if (!tagsData.isEmpty())
|
|
||||||
{
|
|
||||||
const QStringList tagList = tagsData.split(u',');
|
|
||||||
resumeData.tags.insert(tagList.cbegin(), tagList.cend());
|
|
||||||
}
|
|
||||||
resumeData.hasFinishedStatus = query.value(DB_COLUMN_HAS_SEED_STATUS.name).toBool();
|
|
||||||
resumeData.firstLastPiecePriority = query.value(DB_COLUMN_HAS_OUTER_PIECES_PRIORITY.name).toBool();
|
|
||||||
resumeData.ratioLimit = query.value(DB_COLUMN_RATIO_LIMIT.name).toInt() / 1000.0;
|
|
||||||
resumeData.seedingTimeLimit = query.value(DB_COLUMN_SEEDING_TIME_LIMIT.name).toInt();
|
|
||||||
resumeData.inactiveSeedingTimeLimit = query.value(DB_COLUMN_INACTIVE_SEEDING_TIME_LIMIT.name).toInt();
|
|
||||||
resumeData.shareLimitAction = Utils::String::toEnum<ShareLimitAction>(
|
|
||||||
query.value(DB_COLUMN_SHARE_LIMIT_ACTION.name).toString(), ShareLimitAction::Default);
|
|
||||||
resumeData.contentLayout = Utils::String::toEnum<TorrentContentLayout>(
|
|
||||||
query.value(DB_COLUMN_CONTENT_LAYOUT.name).toString(), TorrentContentLayout::Original);
|
|
||||||
resumeData.operatingMode = Utils::String::toEnum<TorrentOperatingMode>(
|
|
||||||
query.value(DB_COLUMN_OPERATING_MODE.name).toString(), TorrentOperatingMode::AutoManaged);
|
|
||||||
resumeData.stopped = query.value(DB_COLUMN_STOPPED.name).toBool();
|
|
||||||
resumeData.stopCondition = Utils::String::toEnum(
|
|
||||||
query.value(DB_COLUMN_STOP_CONDITION.name).toString(), Torrent::StopCondition::None);
|
|
||||||
resumeData.sslParameters =
|
|
||||||
{
|
|
||||||
.certificate = QSslCertificate(query.value(DB_COLUMN_SSL_CERTIFICATE.name).toByteArray()),
|
|
||||||
.privateKey = Utils::SSLKey::load(query.value(DB_COLUMN_SSL_PRIVATE_KEY.name).toByteArray()),
|
|
||||||
.dhParams = query.value(DB_COLUMN_SSL_DH_PARAMS.name).toByteArray()
|
|
||||||
};
|
|
||||||
|
|
||||||
resumeData.savePath = Profile::instance()->fromPortablePath(
|
|
||||||
Path(query.value(DB_COLUMN_TARGET_SAVE_PATH.name).toString()));
|
|
||||||
resumeData.useAutoTMM = resumeData.savePath.isEmpty();
|
|
||||||
if (!resumeData.useAutoTMM)
|
|
||||||
{
|
|
||||||
resumeData.downloadPath = Profile::instance()->fromPortablePath(
|
|
||||||
Path(query.value(DB_COLUMN_DOWNLOAD_PATH.name).toString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
const QByteArray bencodedResumeData = query.value(DB_COLUMN_RESUMEDATA.name).toByteArray();
|
|
||||||
const auto *pref = Preferences::instance();
|
|
||||||
const int bdecodeDepthLimit = pref->getBdecodeDepthLimit();
|
|
||||||
const int bdecodeTokenLimit = pref->getBdecodeTokenLimit();
|
|
||||||
|
|
||||||
lt::error_code ec;
|
|
||||||
const lt::bdecode_node resumeDataRoot = lt::bdecode(bencodedResumeData, ec
|
|
||||||
, nullptr, bdecodeDepthLimit, bdecodeTokenLimit);
|
|
||||||
|
|
||||||
lt::add_torrent_params &p = resumeData.ltAddTorrentParams;
|
|
||||||
|
|
||||||
p = lt::read_resume_data(resumeDataRoot, ec);
|
|
||||||
|
|
||||||
if (const QByteArray bencodedMetadata = query.value(DB_COLUMN_METADATA.name).toByteArray()
|
|
||||||
; !bencodedMetadata.isEmpty())
|
|
||||||
{
|
|
||||||
const lt::bdecode_node torentInfoRoot = lt::bdecode(bencodedMetadata, ec
|
|
||||||
, nullptr, bdecodeDepthLimit, bdecodeTokenLimit);
|
|
||||||
p.ti = std::make_shared<lt::torrent_info>(torentInfoRoot, ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
p.save_path = Profile::instance()->fromPortablePath(Path(fromLTString(p.save_path)))
|
|
||||||
.toString().toStdString();
|
|
||||||
|
|
||||||
if (p.flags & lt::torrent_flags::stop_when_ready)
|
|
||||||
{
|
|
||||||
p.flags &= ~lt::torrent_flags::stop_when_ready;
|
|
||||||
resumeData.stopCondition = Torrent::StopCondition::FilesChecked;
|
|
||||||
}
|
|
||||||
|
|
||||||
return resumeData;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace BitTorrent
|
namespace BitTorrent
|
||||||
|
@ -688,6 +614,90 @@ void BitTorrent::DBResumeDataStorage::enableWALMode() const
|
||||||
throw RuntimeError(tr("WAL mode is probably unsupported due to filesystem limitations."));
|
throw RuntimeError(tr("WAL mode is probably unsupported due to filesystem limitations."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LoadResumeDataResult DBResumeDataStorage::parseQueryResultRow(const QSqlQuery &query) const
|
||||||
|
{
|
||||||
|
LoadTorrentParams resumeData;
|
||||||
|
resumeData.name = query.value(DB_COLUMN_NAME.name).toString();
|
||||||
|
resumeData.category = query.value(DB_COLUMN_CATEGORY.name).toString();
|
||||||
|
const QString tagsData = query.value(DB_COLUMN_TAGS.name).toString();
|
||||||
|
if (!tagsData.isEmpty())
|
||||||
|
{
|
||||||
|
const QStringList tagList = tagsData.split(u',');
|
||||||
|
resumeData.tags.insert(tagList.cbegin(), tagList.cend());
|
||||||
|
}
|
||||||
|
resumeData.hasFinishedStatus = query.value(DB_COLUMN_HAS_SEED_STATUS.name).toBool();
|
||||||
|
resumeData.firstLastPiecePriority = query.value(DB_COLUMN_HAS_OUTER_PIECES_PRIORITY.name).toBool();
|
||||||
|
resumeData.ratioLimit = query.value(DB_COLUMN_RATIO_LIMIT.name).toInt() / 1000.0;
|
||||||
|
resumeData.seedingTimeLimit = query.value(DB_COLUMN_SEEDING_TIME_LIMIT.name).toInt();
|
||||||
|
resumeData.inactiveSeedingTimeLimit = query.value(DB_COLUMN_INACTIVE_SEEDING_TIME_LIMIT.name).toInt();
|
||||||
|
resumeData.shareLimitAction = Utils::String::toEnum<ShareLimitAction>(
|
||||||
|
query.value(DB_COLUMN_SHARE_LIMIT_ACTION.name).toString(), ShareLimitAction::Default);
|
||||||
|
resumeData.contentLayout = Utils::String::toEnum<TorrentContentLayout>(
|
||||||
|
query.value(DB_COLUMN_CONTENT_LAYOUT.name).toString(), TorrentContentLayout::Original);
|
||||||
|
resumeData.operatingMode = Utils::String::toEnum<TorrentOperatingMode>(
|
||||||
|
query.value(DB_COLUMN_OPERATING_MODE.name).toString(), TorrentOperatingMode::AutoManaged);
|
||||||
|
resumeData.stopped = query.value(DB_COLUMN_STOPPED.name).toBool();
|
||||||
|
resumeData.stopCondition = Utils::String::toEnum(
|
||||||
|
query.value(DB_COLUMN_STOP_CONDITION.name).toString(), Torrent::StopCondition::None);
|
||||||
|
resumeData.sslParameters =
|
||||||
|
{
|
||||||
|
.certificate = QSslCertificate(query.value(DB_COLUMN_SSL_CERTIFICATE.name).toByteArray()),
|
||||||
|
.privateKey = Utils::SSLKey::load(query.value(DB_COLUMN_SSL_PRIVATE_KEY.name).toByteArray()),
|
||||||
|
.dhParams = query.value(DB_COLUMN_SSL_DH_PARAMS.name).toByteArray()
|
||||||
|
};
|
||||||
|
|
||||||
|
resumeData.savePath = Profile::instance()->fromPortablePath(
|
||||||
|
Path(query.value(DB_COLUMN_TARGET_SAVE_PATH.name).toString()));
|
||||||
|
resumeData.useAutoTMM = resumeData.savePath.isEmpty();
|
||||||
|
if (!resumeData.useAutoTMM)
|
||||||
|
{
|
||||||
|
resumeData.downloadPath = Profile::instance()->fromPortablePath(
|
||||||
|
Path(query.value(DB_COLUMN_DOWNLOAD_PATH.name).toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
const QByteArray bencodedResumeData = query.value(DB_COLUMN_RESUMEDATA.name).toByteArray();
|
||||||
|
const auto *pref = Preferences::instance();
|
||||||
|
const int bdecodeDepthLimit = pref->getBdecodeDepthLimit();
|
||||||
|
const int bdecodeTokenLimit = pref->getBdecodeTokenLimit();
|
||||||
|
|
||||||
|
lt::error_code ec;
|
||||||
|
const lt::bdecode_node resumeDataRoot = lt::bdecode(bencodedResumeData, ec, nullptr, bdecodeDepthLimit, bdecodeTokenLimit);
|
||||||
|
if (ec)
|
||||||
|
return nonstd::make_unexpected(tr("Cannot parse resume data: %1").arg(QString::fromStdString(ec.message())));
|
||||||
|
|
||||||
|
lt::add_torrent_params &p = resumeData.ltAddTorrentParams;
|
||||||
|
|
||||||
|
p = lt::read_resume_data(resumeDataRoot, ec);
|
||||||
|
if (ec)
|
||||||
|
return nonstd::make_unexpected(tr("Cannot parse resume data: %1").arg(QString::fromStdString(ec.message())));
|
||||||
|
|
||||||
|
if (const QByteArray bencodedMetadata = query.value(DB_COLUMN_METADATA.name).toByteArray()
|
||||||
|
; !bencodedMetadata.isEmpty())
|
||||||
|
{
|
||||||
|
const lt::bdecode_node torentInfoRoot = lt::bdecode(bencodedMetadata, ec
|
||||||
|
, nullptr, bdecodeDepthLimit, bdecodeTokenLimit);
|
||||||
|
if (ec)
|
||||||
|
return nonstd::make_unexpected(tr("Cannot parse torrent info: %1").arg(QString::fromStdString(ec.message())));
|
||||||
|
|
||||||
|
p.ti = std::make_shared<lt::torrent_info>(torentInfoRoot, ec);
|
||||||
|
if (ec)
|
||||||
|
return nonstd::make_unexpected(tr("Cannot parse torrent info: %1").arg(QString::fromStdString(ec.message())));
|
||||||
|
}
|
||||||
|
|
||||||
|
p.save_path = Profile::instance()->fromPortablePath(Path(fromLTString(p.save_path)))
|
||||||
|
.toString().toStdString();
|
||||||
|
if (p.save_path.empty())
|
||||||
|
return nonstd::make_unexpected(tr("Corrupted resume data: %1").arg(tr("save_path is invalid")));
|
||||||
|
|
||||||
|
if (p.flags & lt::torrent_flags::stop_when_ready)
|
||||||
|
{
|
||||||
|
p.flags &= ~lt::torrent_flags::stop_when_ready;
|
||||||
|
resumeData.stopCondition = Torrent::StopCondition::FilesChecked;
|
||||||
|
}
|
||||||
|
|
||||||
|
return resumeData;
|
||||||
|
}
|
||||||
|
|
||||||
BitTorrent::DBResumeDataStorage::Worker::Worker(const Path &dbPath, QReadWriteLock &dbLock, QObject *parent)
|
BitTorrent::DBResumeDataStorage::Worker::Worker(const Path &dbPath, QReadWriteLock &dbLock, QObject *parent)
|
||||||
: QThread(parent)
|
: QThread(parent)
|
||||||
, m_path {dbPath}
|
, m_path {dbPath}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2021-2022 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2021-2025 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
|
||||||
|
@ -31,9 +31,10 @@
|
||||||
#include <QReadWriteLock>
|
#include <QReadWriteLock>
|
||||||
|
|
||||||
#include "base/pathfwd.h"
|
#include "base/pathfwd.h"
|
||||||
#include "base/utils/thread.h"
|
|
||||||
#include "resumedatastorage.h"
|
#include "resumedatastorage.h"
|
||||||
|
|
||||||
|
class QSqlQuery;
|
||||||
|
|
||||||
namespace BitTorrent
|
namespace BitTorrent
|
||||||
{
|
{
|
||||||
class DBResumeDataStorage final : public ResumeDataStorage
|
class DBResumeDataStorage final : public ResumeDataStorage
|
||||||
|
@ -58,6 +59,7 @@ namespace BitTorrent
|
||||||
void createDB() const;
|
void createDB() const;
|
||||||
void updateDB(int fromVersion) const;
|
void updateDB(int fromVersion) const;
|
||||||
void enableWALMode() const;
|
void enableWALMode() const;
|
||||||
|
LoadResumeDataResult parseQueryResultRow(const QSqlQuery &query) const;
|
||||||
|
|
||||||
class Worker;
|
class Worker;
|
||||||
Worker *m_asyncWorker = nullptr;
|
Worker *m_asyncWorker = nullptr;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue