mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-07-06 13:11:25 -07:00
parent
8b7fdf0f22
commit
3b38d0de7f
5 changed files with 23 additions and 164 deletions
|
@ -37,7 +37,6 @@
|
||||||
|
|
||||||
#include "base/3rdparty/expected.hpp"
|
#include "base/3rdparty/expected.hpp"
|
||||||
#include "base/path.h"
|
#include "base/path.h"
|
||||||
#include "torrentdescriptor.h"
|
|
||||||
#include "torrentinfo.h"
|
#include "torrentinfo.h"
|
||||||
|
|
||||||
class QByteArray;
|
class QByteArray;
|
||||||
|
|
|
@ -403,17 +403,27 @@ QString TorrentImpl::name() const
|
||||||
|
|
||||||
QDateTime TorrentImpl::creationDate() const
|
QDateTime TorrentImpl::creationDate() const
|
||||||
{
|
{
|
||||||
return m_torrentInfo.creationDate();
|
if (!hasMetadata())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const std::time_t date = nativeTorrentInfo()->creation_date();
|
||||||
|
return ((date != 0) ? QDateTime::fromSecsSinceEpoch(date) : QDateTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
QString TorrentImpl::creator() const
|
QString TorrentImpl::creator() const
|
||||||
{
|
{
|
||||||
return m_torrentInfo.creator();
|
if (!hasMetadata())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return QString::fromStdString(nativeTorrentInfo()->creator());
|
||||||
}
|
}
|
||||||
|
|
||||||
QString TorrentImpl::comment() const
|
QString TorrentImpl::comment() const
|
||||||
{
|
{
|
||||||
return m_torrentInfo.comment();
|
if (!hasMetadata())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return QString::fromStdString(nativeTorrentInfo()->comment());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TorrentImpl::isPrivate() const
|
bool TorrentImpl::isPrivate() const
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2015-2023 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2015-2024 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,24 +28,15 @@
|
||||||
|
|
||||||
#include "torrentinfo.h"
|
#include "torrentinfo.h"
|
||||||
|
|
||||||
#include <libtorrent/create_torrent.hpp>
|
|
||||||
#include <libtorrent/error_code.hpp>
|
|
||||||
#include <libtorrent/version.hpp>
|
#include <libtorrent/version.hpp>
|
||||||
|
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QDebug>
|
|
||||||
#include <QDir>
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
#include "base/global.h"
|
#include "base/global.h"
|
||||||
#include "base/path.h"
|
#include "base/path.h"
|
||||||
#include "base/preferences.h"
|
|
||||||
#include "base/utils/fs.h"
|
|
||||||
#include "base/utils/io.h"
|
|
||||||
#include "base/utils/misc.h"
|
|
||||||
#include "infohash.h"
|
#include "infohash.h"
|
||||||
#include "trackerentry.h"
|
#include "trackerentry.h"
|
||||||
|
|
||||||
|
@ -82,66 +73,6 @@ bool TorrentInfo::isValid() const
|
||||||
return (m_nativeInfo != nullptr);
|
return (m_nativeInfo != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
nonstd::expected<TorrentInfo, QString> TorrentInfo::load(const QByteArray &data) noexcept
|
|
||||||
{
|
|
||||||
// 2-step construction to overcome default limits of `depth_limit` & `token_limit` which are
|
|
||||||
// used in `torrent_info()` constructor
|
|
||||||
const auto *pref = Preferences::instance();
|
|
||||||
|
|
||||||
lt::error_code ec;
|
|
||||||
const lt::bdecode_node node = lt::bdecode(data, ec
|
|
||||||
, nullptr, pref->getBdecodeDepthLimit(), pref->getBdecodeTokenLimit());
|
|
||||||
if (ec)
|
|
||||||
return nonstd::make_unexpected(QString::fromStdString(ec.message()));
|
|
||||||
|
|
||||||
const lt::torrent_info nativeInfo {node, ec};
|
|
||||||
if (ec)
|
|
||||||
return nonstd::make_unexpected(QString::fromStdString(ec.message()));
|
|
||||||
|
|
||||||
return TorrentInfo(nativeInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
nonstd::expected<TorrentInfo, QString> TorrentInfo::loadFromFile(const Path &path) noexcept
|
|
||||||
{
|
|
||||||
QByteArray data;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
const qint64 torrentSizeLimit = Preferences::instance()->getTorrentFileSizeLimit();
|
|
||||||
const auto readResult = Utils::IO::readFile(path, torrentSizeLimit);
|
|
||||||
if (!readResult)
|
|
||||||
return nonstd::make_unexpected(readResult.error().message);
|
|
||||||
data = readResult.value();
|
|
||||||
}
|
|
||||||
catch (const std::bad_alloc &e)
|
|
||||||
{
|
|
||||||
return nonstd::make_unexpected(tr("Failed to allocate memory when reading file. File: \"%1\". Error: \"%2\"")
|
|
||||||
.arg(path.toString(), QString::fromLocal8Bit(e.what())));
|
|
||||||
}
|
|
||||||
|
|
||||||
return load(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
nonstd::expected<void, QString> TorrentInfo::saveToFile(const Path &path) const
|
|
||||||
{
|
|
||||||
if (!isValid())
|
|
||||||
return nonstd::make_unexpected(tr("Invalid metadata"));
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
const auto torrentCreator = lt::create_torrent(*m_nativeInfo);
|
|
||||||
const lt::entry torrentEntry = torrentCreator.generate();
|
|
||||||
const nonstd::expected<void, QString> result = Utils::IO::saveToFile(path, torrentEntry);
|
|
||||||
if (!result)
|
|
||||||
return result.get_unexpected();
|
|
||||||
}
|
|
||||||
catch (const lt::system_error &err)
|
|
||||||
{
|
|
||||||
return nonstd::make_unexpected(QString::fromLocal8Bit(err.what()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
InfoHash TorrentInfo::infoHash() const
|
InfoHash TorrentInfo::infoHash() const
|
||||||
{
|
{
|
||||||
if (!isValid()) return {};
|
if (!isValid()) return {};
|
||||||
|
@ -160,28 +91,6 @@ QString TorrentInfo::name() const
|
||||||
return QString::fromStdString(m_nativeInfo->orig_files().name());
|
return QString::fromStdString(m_nativeInfo->orig_files().name());
|
||||||
}
|
}
|
||||||
|
|
||||||
QDateTime TorrentInfo::creationDate() const
|
|
||||||
{
|
|
||||||
if (!isValid()) return {};
|
|
||||||
|
|
||||||
const std::time_t date = m_nativeInfo->creation_date();
|
|
||||||
return ((date != 0) ? QDateTime::fromSecsSinceEpoch(date) : QDateTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
QString TorrentInfo::creator() const
|
|
||||||
{
|
|
||||||
if (!isValid()) return {};
|
|
||||||
|
|
||||||
return QString::fromStdString(m_nativeInfo->creator());
|
|
||||||
}
|
|
||||||
|
|
||||||
QString TorrentInfo::comment() const
|
|
||||||
{
|
|
||||||
if (!isValid()) return {};
|
|
||||||
|
|
||||||
return QString::fromStdString(m_nativeInfo->comment());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TorrentInfo::isPrivate() const
|
bool TorrentInfo::isPrivate() const
|
||||||
{
|
{
|
||||||
if (!isValid()) return false;
|
if (!isValid()) return false;
|
||||||
|
@ -270,43 +179,7 @@ qlonglong TorrentInfo::fileOffset(const int index) const
|
||||||
return m_nativeInfo->orig_files().file_offset(m_nativeIndexes[index]);
|
return m_nativeInfo->orig_files().file_offset(m_nativeIndexes[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<TrackerEntry> TorrentInfo::trackers() const
|
QByteArray TorrentInfo::rawData() const
|
||||||
{
|
|
||||||
if (!isValid()) return {};
|
|
||||||
|
|
||||||
const std::vector<lt::announce_entry> trackers = m_nativeInfo->trackers();
|
|
||||||
|
|
||||||
QList<TrackerEntry> ret;
|
|
||||||
ret.reserve(static_cast<decltype(ret)::size_type>(trackers.size()));
|
|
||||||
for (const lt::announce_entry &tracker : trackers)
|
|
||||||
ret.append({.url = QString::fromStdString(tracker.url), .tier = tracker.tier});
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QUrl> TorrentInfo::urlSeeds() const
|
|
||||||
{
|
|
||||||
if (!isValid()) return {};
|
|
||||||
|
|
||||||
const std::vector<lt::web_seed_entry> &nativeWebSeeds = m_nativeInfo->web_seeds();
|
|
||||||
|
|
||||||
QList<QUrl> urlSeeds;
|
|
||||||
urlSeeds.reserve(static_cast<decltype(urlSeeds)::size_type>(nativeWebSeeds.size()));
|
|
||||||
|
|
||||||
for (const lt::web_seed_entry &webSeed : nativeWebSeeds)
|
|
||||||
{
|
|
||||||
#if LIBTORRENT_VERSION_NUM < 20100
|
|
||||||
if (webSeed.type == lt::web_seed_entry::url_seed)
|
|
||||||
urlSeeds.append(QUrl(QString::fromStdString(webSeed.url)));
|
|
||||||
#else
|
|
||||||
urlSeeds.append(QUrl(QString::fromStdString(webSeed.url)));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
return urlSeeds;
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray TorrentInfo::metadata() const
|
|
||||||
{
|
{
|
||||||
if (!isValid()) return {};
|
if (!isValid()) return {};
|
||||||
#ifdef QBT_USES_LIBTORRENT2
|
#ifdef QBT_USES_LIBTORRENT2
|
||||||
|
@ -366,16 +239,7 @@ QList<QByteArray> TorrentInfo::pieceHashes() const
|
||||||
|
|
||||||
TorrentInfo::PieceRange TorrentInfo::filePieces(const Path &filePath) const
|
TorrentInfo::PieceRange TorrentInfo::filePieces(const Path &filePath) const
|
||||||
{
|
{
|
||||||
if (!isValid()) // if we do not check here the debug message will be printed, which would be not correct
|
return filePieces(fileIndex(filePath));
|
||||||
return {};
|
|
||||||
|
|
||||||
const int index = fileIndex(filePath);
|
|
||||||
if (index == -1)
|
|
||||||
{
|
|
||||||
qDebug() << "Filename" << filePath.toString() << "was not found in torrent" << name();
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return filePieces(index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TorrentInfo::PieceRange TorrentInfo::filePieces(const int fileIndex) const
|
TorrentInfo::PieceRange TorrentInfo::filePieces(const int fileIndex) const
|
||||||
|
@ -384,10 +248,7 @@ TorrentInfo::PieceRange TorrentInfo::filePieces(const int fileIndex) const
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if ((fileIndex < 0) || (fileIndex >= filesCount()))
|
if ((fileIndex < 0) || (fileIndex >= filesCount()))
|
||||||
{
|
|
||||||
qDebug() << "File index (" << fileIndex << ") is out of range for torrent" << name();
|
|
||||||
return {};
|
return {};
|
||||||
}
|
|
||||||
|
|
||||||
const lt::file_storage &files = m_nativeInfo->orig_files();
|
const lt::file_storage &files = m_nativeInfo->orig_files();
|
||||||
const auto fileSize = files.file_size(m_nativeIndexes[fileIndex]);
|
const auto fileSize = files.file_size(m_nativeIndexes[fileIndex]);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2015-2024 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
|
||||||
|
@ -34,7 +34,6 @@
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
|
||||||
#include "base/3rdparty/expected.hpp"
|
|
||||||
#include "base/indexrange.h"
|
#include "base/indexrange.h"
|
||||||
#include "base/pathfwd.h"
|
#include "base/pathfwd.h"
|
||||||
|
|
||||||
|
@ -50,26 +49,17 @@ namespace BitTorrent
|
||||||
|
|
||||||
class TorrentInfo
|
class TorrentInfo
|
||||||
{
|
{
|
||||||
Q_DECLARE_TR_FUNCTIONS(TorrentInfo)
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TorrentInfo() = default;
|
TorrentInfo() = default;
|
||||||
TorrentInfo(const TorrentInfo &other) = default;
|
TorrentInfo(const TorrentInfo &other) = default;
|
||||||
|
|
||||||
explicit TorrentInfo(const lt::torrent_info &nativeInfo);
|
explicit TorrentInfo(const lt::torrent_info &nativeInfo);
|
||||||
|
|
||||||
static nonstd::expected<TorrentInfo, QString> load(const QByteArray &data) noexcept;
|
|
||||||
static nonstd::expected<TorrentInfo, QString> loadFromFile(const Path &path) noexcept;
|
|
||||||
nonstd::expected<void, QString> saveToFile(const Path &path) const;
|
|
||||||
|
|
||||||
TorrentInfo &operator=(const TorrentInfo &other);
|
TorrentInfo &operator=(const TorrentInfo &other);
|
||||||
|
|
||||||
bool isValid() const;
|
bool isValid() const;
|
||||||
InfoHash infoHash() const;
|
InfoHash infoHash() const;
|
||||||
QString name() const;
|
QString name() const;
|
||||||
QDateTime creationDate() const;
|
|
||||||
QString creator() const;
|
|
||||||
QString comment() const;
|
|
||||||
bool isPrivate() const;
|
bool isPrivate() const;
|
||||||
qlonglong totalSize() const;
|
qlonglong totalSize() const;
|
||||||
int filesCount() const;
|
int filesCount() const;
|
||||||
|
@ -80,9 +70,6 @@ namespace BitTorrent
|
||||||
PathList filePaths() const;
|
PathList filePaths() const;
|
||||||
qlonglong fileSize(int index) const;
|
qlonglong fileSize(int index) const;
|
||||||
qlonglong fileOffset(int index) const;
|
qlonglong fileOffset(int index) const;
|
||||||
QList<TrackerEntry> trackers() const;
|
|
||||||
QList<QUrl> urlSeeds() const;
|
|
||||||
QByteArray metadata() const;
|
|
||||||
PathList filesForPiece(int pieceIndex) const;
|
PathList filesForPiece(int pieceIndex) const;
|
||||||
QList<int> fileIndicesForPiece(int pieceIndex) const;
|
QList<int> fileIndicesForPiece(int pieceIndex) const;
|
||||||
QList<QByteArray> pieceHashes() const;
|
QList<QByteArray> pieceHashes() const;
|
||||||
|
@ -93,6 +80,8 @@ namespace BitTorrent
|
||||||
PieceRange filePieces(const Path &filePath) const;
|
PieceRange filePieces(const Path &filePath) const;
|
||||||
PieceRange filePieces(int fileIndex) const;
|
PieceRange filePieces(int fileIndex) const;
|
||||||
|
|
||||||
|
QByteArray rawData() const;
|
||||||
|
|
||||||
bool matchesInfoHash(const InfoHash &otherInfoHash) const;
|
bool matchesInfoHash(const InfoHash &otherInfoHash) const;
|
||||||
|
|
||||||
std::shared_ptr<lt::torrent_info> nativeInfo() const;
|
std::shared_ptr<lt::torrent_info> nativeInfo() const;
|
||||||
|
|
|
@ -897,11 +897,11 @@ void AddNewTorrentDialog::setupTreeview()
|
||||||
// Set dialog title
|
// Set dialog title
|
||||||
setWindowTitle(torrentDescr.name());
|
setWindowTitle(torrentDescr.name());
|
||||||
|
|
||||||
const auto &torrentInfo = *torrentDescr.info();
|
|
||||||
|
|
||||||
// Set torrent information
|
// Set torrent information
|
||||||
m_ui->labelCommentData->setText(Utils::Misc::parseHtmlLinks(torrentInfo.comment().toHtmlEscaped()));
|
m_ui->labelCommentData->setText(Utils::Misc::parseHtmlLinks(torrentDescr.comment().toHtmlEscaped()));
|
||||||
m_ui->labelDateData->setText(!torrentInfo.creationDate().isNull() ? QLocale().toString(torrentInfo.creationDate(), QLocale::ShortFormat) : tr("Not available"));
|
m_ui->labelDateData->setText(!torrentDescr.creationDate().isNull() ? QLocale().toString(torrentDescr.creationDate(), QLocale::ShortFormat) : tr("Not available"));
|
||||||
|
|
||||||
|
const auto &torrentInfo = *torrentDescr.info();
|
||||||
|
|
||||||
BitTorrent::AddTorrentParams &addTorrentParams = m_currentContext->torrentParams;
|
BitTorrent::AddTorrentParams &addTorrentParams = m_currentContext->torrentParams;
|
||||||
if (addTorrentParams.filePaths.isEmpty())
|
if (addTorrentParams.filePaths.isEmpty())
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue