You've already forked qBittorrent
mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-10-19 05:12:18 +02:00
Compare commits
16 Commits
release-5.
...
release-5.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0188e11dd7 | ||
![]() |
1dc348539b | ||
![]() |
241a0e91bf | ||
![]() |
68f7295500 | ||
![]() |
53adb7bfa8 | ||
![]() |
6128f6eecc | ||
![]() |
d156a44f8d | ||
![]() |
c3c7f28bad | ||
![]() |
9ac14cdf9f | ||
![]() |
b899ea8c40 | ||
![]() |
0d7c367332 | ||
![]() |
22826499d5 | ||
![]() |
dbfd830b56 | ||
![]() |
ad3348b95f | ||
![]() |
44b08fcb74 | ||
![]() |
71b752baf3 |
12
Changelog
12
Changelog
@@ -1,3 +1,15 @@
|
||||
Mon Dec 16th 2024 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v5.0.3
|
||||
- BUGFIX: Discard obsolete "state update" events after torrent is reloaded (glassez)
|
||||
- BUGFIX: Fix incorrect SQL column definition (glassez)
|
||||
- BUGFIX: Avoid redundant requests of announce entries from libtorrent (glassez)
|
||||
- WEBUI: Fix removing tracker URL with '|' character (Thomas Piccirello)
|
||||
- WEBUI: Fix reloading page after login (Evgenii Ryshkov)
|
||||
- WEBAPI: Fix incorrect key in torrent creator (Bartu Özen)
|
||||
- RSS: Don't add duplicate episodes to previously matched (wavygecko)
|
||||
- RSS: Use cached current time when parsing RSS feed (glassez)
|
||||
- WINDOWS: Don't follow symlink when creating torrents on Windows (Chocobo1)
|
||||
- WINDOWS: NSIS: Update Italian translation (Giacomo411)
|
||||
|
||||
Sun Nov 17th 2024 - sledgehammer999 <sledgehammer999@qbittorrent.org> - v5.0.2
|
||||
- BUGFIX: Remove trackers from previous category when moved to new one (glassez)
|
||||
- BUGFIX: Fix `.torrent` file could not be deleted when torrent is canceled (glassez)
|
||||
|
2
dist/mac/Info.plist
vendored
2
dist/mac/Info.plist
vendored
@@ -55,7 +55,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.0.2</string>
|
||||
<string>5.0.3</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
|
@@ -161,7 +161,7 @@ Name[ta]=qBittorrent
|
||||
GenericName[te]=క్యు బిట్ టొరెంట్ క్లయింట్
|
||||
Comment[te]=క్యు బిట్ టొరెంట్ తో ఫైల్స్ దిగుమతి చేసుకోండి , పంచుకోండి
|
||||
Name[te]=qBittorrent
|
||||
GenericName[th]=โปรแกรมบิตทอร์เรนต์
|
||||
GenericName[th]=ไคลเอนต์บิททอร์เรนต์
|
||||
Comment[th]=ดาวน์โหลดและแชร์ไฟล์ผ่านบิตทอร์เรนต์
|
||||
Name[th]=qBittorrent
|
||||
GenericName[tr]=BitTorrent istemcisi
|
||||
|
@@ -62,6 +62,6 @@
|
||||
<url type="contribute">https://github.com/qbittorrent/qBittorrent/blob/master/CONTRIBUTING.md</url>
|
||||
<content_rating type="oars-1.1"/>
|
||||
<releases>
|
||||
<release version="5.0.2" date="2024-11-17"/>
|
||||
<release version="5.0.3" date="2024-12-16"/>
|
||||
</releases>
|
||||
</component>
|
||||
|
2
dist/windows/config.nsh
vendored
2
dist/windows/config.nsh
vendored
@@ -14,7 +14,7 @@
|
||||
; 4.5.1.3 -> good
|
||||
; 4.5.1.3.2 -> bad
|
||||
; 4.5.0beta -> bad
|
||||
!define /ifndef QBT_VERSION "5.0.2"
|
||||
!define /ifndef QBT_VERSION "5.0.3"
|
||||
|
||||
; Option that controls the installer's window name
|
||||
; If set, its value will be used like this:
|
||||
|
@@ -29,7 +29,7 @@ LangString launch_qbt ${LANG_ITALIAN} "Esegui qBittorrent."
|
||||
;LangString inst_requires_64bit ${LANG_ENGLISH} "This installer works only in 64-bit Windows versions."
|
||||
LangString inst_requires_64bit ${LANG_ITALIAN} "Questo installer funziona solo con versioni di Windows a 64bit."
|
||||
;LangString inst_requires_win10 ${LANG_ENGLISH} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
|
||||
LangString inst_requires_win10 ${LANG_ITALIAN} "This installer requires at least Windows 10 (1809) / Windows Server 2019."
|
||||
LangString inst_requires_win10 ${LANG_ITALIAN} "Questo installer richiede almeno Windows 10 (1809) / Windows Server 2019."
|
||||
;LangString inst_uninstall_link_description ${LANG_ENGLISH} "Uninstall qBittorrent"
|
||||
LangString inst_uninstall_link_description ${LANG_ITALIAN} "Disinstalla qBittorrent"
|
||||
|
||||
|
@@ -67,7 +67,7 @@ namespace
|
||||
{
|
||||
const QString DB_CONNECTION_NAME = u"ResumeDataStorage"_s;
|
||||
|
||||
const int DB_VERSION = 7;
|
||||
const int DB_VERSION = 8;
|
||||
|
||||
const QString DB_TABLE_META = u"meta"_s;
|
||||
const QString DB_TABLE_TORRENTS = u"torrents"_s;
|
||||
@@ -628,7 +628,31 @@ void BitTorrent::DBResumeDataStorage::updateDB(const int fromVersion) const
|
||||
}
|
||||
|
||||
if (fromVersion <= 6)
|
||||
addColumn(DB_TABLE_TORRENTS, DB_COLUMN_SHARE_LIMIT_ACTION, "TEXTNOT NULL DEFAULT `Default`");
|
||||
addColumn(DB_TABLE_TORRENTS, DB_COLUMN_SHARE_LIMIT_ACTION, "TEXT NOT NULL DEFAULT `Default`");
|
||||
|
||||
if (fromVersion == 7)
|
||||
{
|
||||
const QString TEMP_COLUMN_NAME = DB_COLUMN_SHARE_LIMIT_ACTION.name + u"_temp";
|
||||
|
||||
auto queryStr = u"ALTER TABLE %1 ADD %2 %3"_s
|
||||
.arg(quoted(DB_TABLE_TORRENTS), TEMP_COLUMN_NAME, u"TEXT NOT NULL DEFAULT `Default`");
|
||||
if (!query.exec(queryStr))
|
||||
throw RuntimeError(query.lastError().text());
|
||||
|
||||
queryStr = u"UPDATE %1 SET %2 = %3"_s
|
||||
.arg(quoted(DB_TABLE_TORRENTS), quoted(TEMP_COLUMN_NAME), quoted(DB_COLUMN_SHARE_LIMIT_ACTION.name));
|
||||
if (!query.exec(queryStr))
|
||||
throw RuntimeError(query.lastError().text());
|
||||
|
||||
queryStr = u"ALTER TABLE %1 DROP %2"_s.arg(quoted(DB_TABLE_TORRENTS), quoted(DB_COLUMN_SHARE_LIMIT_ACTION.name));
|
||||
if (!query.exec(queryStr))
|
||||
throw RuntimeError(query.lastError().text());
|
||||
|
||||
queryStr = u"ALTER TABLE %1 RENAME %2 TO %3"_s
|
||||
.arg(quoted(DB_TABLE_TORRENTS), quoted(TEMP_COLUMN_NAME), quoted(DB_COLUMN_SHARE_LIMIT_ACTION.name));
|
||||
if (!query.exec(queryStr))
|
||||
throw RuntimeError(query.lastError().text());
|
||||
}
|
||||
|
||||
const QString updateMetaVersionQuery = makeUpdateStatement(DB_TABLE_META, {DB_COLUMN_NAME, DB_COLUMN_VALUE});
|
||||
if (!query.prepare(updateMetaVersionQuery))
|
||||
|
@@ -66,6 +66,7 @@
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QMutexLocker>
|
||||
#include <QNetworkAddressEntry>
|
||||
#include <QNetworkInterface>
|
||||
#include <QRegularExpression>
|
||||
@@ -1606,7 +1607,7 @@ void SessionImpl::endStartup(ResumeSessionContext *context)
|
||||
reannounceToAllTrackers();
|
||||
}
|
||||
|
||||
m_wakeupCheckTimestamp = QDateTime::currentDateTime();
|
||||
m_wakeupCheckTimestamp = now;
|
||||
});
|
||||
m_wakeupCheckTimestamp = QDateTime::currentDateTime();
|
||||
m_wakeupCheckTimer->start(30s);
|
||||
@@ -5526,8 +5527,6 @@ void SessionImpl::readAlerts()
|
||||
|
||||
// Some torrents may become "finished" after different alerts handling.
|
||||
processPendingFinishedTorrents();
|
||||
|
||||
processTrackerStatuses();
|
||||
}
|
||||
|
||||
void SessionImpl::handleAddTorrentAlert(const lt::add_torrent_alert *alert)
|
||||
@@ -6203,7 +6202,12 @@ void SessionImpl::handleTrackerAlert(const lt::tracker_alert *alert)
|
||||
if (!torrent)
|
||||
return;
|
||||
|
||||
[[maybe_unused]] const QMutexLocker updatedTrackerStatusesLocker {&m_updatedTrackerStatusesMutex};
|
||||
|
||||
const auto prevSize = m_updatedTrackerStatuses.size();
|
||||
QMap<int, int> &updateInfo = m_updatedTrackerStatuses[torrent->nativeHandle()][std::string(alert->tracker_url())][alert->local_endpoint];
|
||||
if (prevSize < m_updatedTrackerStatuses.size())
|
||||
updateTrackerEntryStatuses(torrent->nativeHandle());
|
||||
|
||||
if (alert->type() == lt::tracker_reply_alert::alert_type)
|
||||
{
|
||||
@@ -6265,17 +6269,6 @@ void SessionImpl::handleTorrentConflictAlert(const lt::torrent_conflict_alert *a
|
||||
}
|
||||
#endif
|
||||
|
||||
void SessionImpl::processTrackerStatuses()
|
||||
{
|
||||
if (m_updatedTrackerStatuses.isEmpty())
|
||||
return;
|
||||
|
||||
for (auto it = m_updatedTrackerStatuses.cbegin(); it != m_updatedTrackerStatuses.cend(); ++it)
|
||||
updateTrackerEntryStatuses(it.key(), it.value());
|
||||
|
||||
m_updatedTrackerStatuses.clear();
|
||||
}
|
||||
|
||||
void SessionImpl::saveStatistics() const
|
||||
{
|
||||
if (!m_isStatisticsDirty)
|
||||
@@ -6300,15 +6293,19 @@ void SessionImpl::loadStatistics()
|
||||
m_previouslyUploaded = value[u"AlltimeUL"_s].toLongLong();
|
||||
}
|
||||
|
||||
void SessionImpl::updateTrackerEntryStatuses(lt::torrent_handle torrentHandle, QHash<std::string, QHash<lt::tcp::endpoint, QMap<int, int>>> updatedTrackers)
|
||||
void SessionImpl::updateTrackerEntryStatuses(lt::torrent_handle torrentHandle)
|
||||
{
|
||||
invokeAsync([this, torrentHandle = std::move(torrentHandle), updatedTrackers = std::move(updatedTrackers)]() mutable
|
||||
invokeAsync([this, torrentHandle = std::move(torrentHandle)]() mutable
|
||||
{
|
||||
try
|
||||
{
|
||||
std::vector<lt::announce_entry> nativeTrackers = torrentHandle.trackers();
|
||||
invoke([this, torrentHandle, nativeTrackers = std::move(nativeTrackers)
|
||||
, updatedTrackers = std::move(updatedTrackers)]
|
||||
|
||||
QMutexLocker updatedTrackerStatusesLocker {&m_updatedTrackerStatusesMutex};
|
||||
QHash<std::string, QHash<lt::tcp::endpoint, QMap<int, int>>> updatedTrackers = m_updatedTrackerStatuses.take(torrentHandle);
|
||||
updatedTrackerStatusesLocker.unlock();
|
||||
|
||||
invoke([this, torrentHandle, nativeTrackers = std::move(nativeTrackers), updatedTrackers = std::move(updatedTrackers)]
|
||||
{
|
||||
TorrentImpl *torrent = m_torrents.value(torrentHandle.info_hash());
|
||||
if (!torrent || torrent->isStopped())
|
||||
@@ -6363,7 +6360,7 @@ void SessionImpl::handleRemovedTorrent(const TorrentID &torrentID, const QString
|
||||
m_removingTorrents.erase(removingTorrentDataIter);
|
||||
}
|
||||
|
||||
QDateTime SessionImpl::fromLTTimePoint32(const libtorrent::time_point32 &timePoint) const
|
||||
QDateTime SessionImpl::fromLTTimePoint32(const lt::time_point32 &timePoint) const
|
||||
{
|
||||
const auto secsSinceNow = lt::duration_cast<lt::seconds>(timePoint - m_ltNow + lt::milliseconds(500)).count();
|
||||
return m_qNow.addSecs(secsSinceNow);
|
||||
|
@@ -41,6 +41,7 @@
|
||||
#include <QElapsedTimer>
|
||||
#include <QHash>
|
||||
#include <QMap>
|
||||
#include <QMutex>
|
||||
#include <QPointer>
|
||||
#include <QSet>
|
||||
#include <QVector>
|
||||
@@ -541,7 +542,6 @@ namespace BitTorrent
|
||||
void populateAdditionalTrackers();
|
||||
void enableIPFilter();
|
||||
void disableIPFilter();
|
||||
void processTrackerStatuses();
|
||||
void processTorrentShareLimits(TorrentImpl *torrent);
|
||||
void populateExcludedFileNamesRegExpList();
|
||||
void prepareStartup();
|
||||
@@ -605,7 +605,7 @@ namespace BitTorrent
|
||||
void saveStatistics() const;
|
||||
void loadStatistics();
|
||||
|
||||
void updateTrackerEntryStatuses(lt::torrent_handle torrentHandle, QHash<std::string, QHash<lt::tcp::endpoint, QMap<int, int>>> updatedTrackers);
|
||||
void updateTrackerEntryStatuses(lt::torrent_handle torrentHandle);
|
||||
|
||||
void handleRemovedTorrent(const TorrentID &torrentID, const QString &partfileRemoveError = {});
|
||||
|
||||
@@ -794,6 +794,7 @@ namespace BitTorrent
|
||||
// This field holds amounts of peers reported by trackers in their responses to announces
|
||||
// (torrent.tracker_name.tracker_local_endpoint.protocol_version.num_peers)
|
||||
QHash<lt::torrent_handle, QHash<std::string, QHash<lt::tcp::endpoint, QMap<int, int>>>> m_updatedTrackerStatuses;
|
||||
QMutex m_updatedTrackerStatusesMutex;
|
||||
|
||||
// I/O errored torrents
|
||||
QSet<TorrentID> m_recentErroredTorrents;
|
||||
|
@@ -215,7 +215,15 @@ namespace BitTorrent
|
||||
virtual int piecesCount() const = 0;
|
||||
virtual int piecesHave() const = 0;
|
||||
virtual qreal progress() const = 0;
|
||||
|
||||
virtual QDateTime addedTime() const = 0;
|
||||
virtual QDateTime completedTime() const = 0;
|
||||
virtual QDateTime lastSeenComplete() const = 0;
|
||||
virtual qlonglong activeTime() const = 0;
|
||||
virtual qlonglong finishedTime() const = 0;
|
||||
virtual qlonglong timeSinceUpload() const = 0;
|
||||
virtual qlonglong timeSinceDownload() const = 0;
|
||||
virtual qlonglong timeSinceActivity() const = 0;
|
||||
|
||||
// Share limits
|
||||
virtual qreal ratioLimit() const = 0;
|
||||
@@ -254,8 +262,6 @@ namespace BitTorrent
|
||||
virtual QString error() const = 0;
|
||||
virtual qlonglong totalDownload() const = 0;
|
||||
virtual qlonglong totalUpload() const = 0;
|
||||
virtual qlonglong activeTime() const = 0;
|
||||
virtual qlonglong finishedTime() const = 0;
|
||||
virtual qlonglong eta() const = 0;
|
||||
virtual int seedsCount() const = 0;
|
||||
virtual int peersCount() const = 0;
|
||||
@@ -263,11 +269,6 @@ namespace BitTorrent
|
||||
virtual int totalSeedsCount() const = 0;
|
||||
virtual int totalPeersCount() const = 0;
|
||||
virtual int totalLeechersCount() const = 0;
|
||||
virtual QDateTime lastSeenComplete() const = 0;
|
||||
virtual QDateTime completedTime() const = 0;
|
||||
virtual qlonglong timeSinceUpload() const = 0;
|
||||
virtual qlonglong timeSinceDownload() const = 0;
|
||||
virtual qlonglong timeSinceActivity() const = 0;
|
||||
virtual int downloadLimit() const = 0;
|
||||
virtual int uploadLimit() const = 0;
|
||||
virtual bool superSeeding() const = 0;
|
||||
|
@@ -36,6 +36,7 @@
|
||||
#include <libtorrent/file_storage.hpp>
|
||||
#include <libtorrent/torrent_info.hpp>
|
||||
|
||||
#include <QtSystemDetection>
|
||||
#include <QDirIterator>
|
||||
#include <QFileInfo>
|
||||
#include <QHash>
|
||||
@@ -123,7 +124,14 @@ void TorrentCreator::run()
|
||||
// need to sort the file names by natural sort order
|
||||
QStringList dirs = {m_params.sourcePath.data()};
|
||||
|
||||
QDirIterator dirIter {m_params.sourcePath.data(), (QDir::AllDirs | QDir::NoDotAndDotDot), QDirIterator::Subdirectories};
|
||||
#ifdef Q_OS_WIN
|
||||
// libtorrent couldn't handle .lnk files on Windows
|
||||
// Also, Windows users do not expect torrent creator to traverse into .lnk files so skip over them
|
||||
const QDir::Filters dirFilters {QDir::AllDirs | QDir::NoDotAndDotDot | QDir::NoSymLinks};
|
||||
#else
|
||||
const QDir::Filters dirFilters {QDir::AllDirs | QDir::NoDotAndDotDot};
|
||||
#endif
|
||||
QDirIterator dirIter {m_params.sourcePath.data(), dirFilters, QDirIterator::Subdirectories};
|
||||
while (dirIter.hasNext())
|
||||
{
|
||||
const QString filePath = dirIter.next();
|
||||
@@ -138,7 +146,12 @@ void TorrentCreator::run()
|
||||
{
|
||||
QStringList tmpNames; // natural sort files within each dir
|
||||
|
||||
QDirIterator fileIter {dir, QDir::Files};
|
||||
#ifdef Q_OS_WIN
|
||||
const QDir::Filters fileFilters {QDir::Files | QDir::NoSymLinks};
|
||||
#else
|
||||
const QDir::Filters fileFilters {QDir::Files};
|
||||
#endif
|
||||
QDirIterator fileIter {dir, fileFilters};
|
||||
while (fileIter.hasNext())
|
||||
{
|
||||
const QFileInfo fileInfo = fileIter.nextFileInfo();
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -35,9 +35,7 @@
|
||||
#include <libtorrent/write_resume_data.hpp>
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QDateTime>
|
||||
#include <QRegularExpression>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
#include "base/global.h"
|
||||
@@ -147,7 +145,13 @@ BitTorrent::TorrentDescriptor::TorrentDescriptor(lt::add_torrent_params ltAddTor
|
||||
: m_ltAddTorrentParams {std::move(ltAddTorrentParams)}
|
||||
{
|
||||
if (m_ltAddTorrentParams.ti && m_ltAddTorrentParams.ti->is_valid())
|
||||
{
|
||||
m_info.emplace(*m_ltAddTorrentParams.ti);
|
||||
if (m_ltAddTorrentParams.ti->creation_date() > 0)
|
||||
m_creationDate = QDateTime::fromSecsSinceEpoch(m_ltAddTorrentParams.ti->creation_date());
|
||||
m_creator = QString::fromStdString(m_ltAddTorrentParams.ti->creator());
|
||||
m_comment = QString::fromStdString(m_ltAddTorrentParams.ti->comment());
|
||||
}
|
||||
}
|
||||
|
||||
BitTorrent::InfoHash BitTorrent::TorrentDescriptor::infoHash() const
|
||||
@@ -166,18 +170,17 @@ QString BitTorrent::TorrentDescriptor::name() const
|
||||
|
||||
QDateTime BitTorrent::TorrentDescriptor::creationDate() const
|
||||
{
|
||||
return ((m_ltAddTorrentParams.ti->creation_date() != 0)
|
||||
? QDateTime::fromSecsSinceEpoch(m_ltAddTorrentParams.ti->creation_date()) : QDateTime());
|
||||
return m_creationDate;
|
||||
}
|
||||
|
||||
QString BitTorrent::TorrentDescriptor::creator() const
|
||||
{
|
||||
return QString::fromStdString(m_ltAddTorrentParams.ti->creator());
|
||||
return m_creator;
|
||||
}
|
||||
|
||||
QString BitTorrent::TorrentDescriptor::comment() const
|
||||
{
|
||||
return QString::fromStdString(m_ltAddTorrentParams.ti->comment());
|
||||
return m_comment;
|
||||
}
|
||||
|
||||
const std::optional<BitTorrent::TorrentInfo> &BitTorrent::TorrentDescriptor::info() const
|
||||
|
@@ -33,7 +33,9 @@
|
||||
#include <libtorrent/add_torrent_params.hpp>
|
||||
|
||||
#include <QtContainerFwd>
|
||||
#include <QDateTime>
|
||||
#include <QMetaType>
|
||||
#include <QString>
|
||||
|
||||
#include "base/3rdparty/expected.hpp"
|
||||
#include "base/path.h"
|
||||
@@ -41,8 +43,6 @@
|
||||
#include "torrentinfo.h"
|
||||
|
||||
class QByteArray;
|
||||
class QDateTime;
|
||||
class QString;
|
||||
class QUrl;
|
||||
|
||||
namespace BitTorrent
|
||||
@@ -78,6 +78,9 @@ namespace BitTorrent
|
||||
|
||||
lt::add_torrent_params m_ltAddTorrentParams;
|
||||
std::optional<TorrentInfo> m_info;
|
||||
QDateTime m_creationDate;
|
||||
QString m_creator;
|
||||
QString m_comment;
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -322,6 +322,11 @@ TorrentImpl::TorrentImpl(SessionImpl *session, lt::session *nativeSession
|
||||
{
|
||||
if (m_ltAddTorrentParams.ti)
|
||||
{
|
||||
if (const std::time_t creationDate = m_ltAddTorrentParams.ti->creation_date(); creationDate > 0)
|
||||
m_creationDate = QDateTime::fromSecsSinceEpoch(creationDate);
|
||||
m_creator = QString::fromStdString(m_ltAddTorrentParams.ti->creator());
|
||||
m_comment = QString::fromStdString(m_ltAddTorrentParams.ti->comment());
|
||||
|
||||
// Initialize it only if torrent is added with metadata.
|
||||
// Otherwise it should be initialized in "Metadata received" handler.
|
||||
m_torrentInfo = TorrentInfo(*m_ltAddTorrentParams.ti);
|
||||
@@ -365,6 +370,12 @@ TorrentImpl::TorrentImpl(SessionImpl *session, lt::session *nativeSession
|
||||
m_urlSeeds.append(QString::fromStdString(urlSeed));
|
||||
m_nativeStatus = extensionData->status;
|
||||
|
||||
m_addedTime = QDateTime::fromSecsSinceEpoch(m_nativeStatus.added_time);
|
||||
if (m_nativeStatus.completed_time > 0)
|
||||
m_completedTime = QDateTime::fromSecsSinceEpoch(m_nativeStatus.completed_time);
|
||||
if (m_nativeStatus.last_seen_complete > 0)
|
||||
m_lastSeenComplete = QDateTime::fromSecsSinceEpoch(m_nativeStatus.last_seen_complete);
|
||||
|
||||
if (hasMetadata())
|
||||
updateProgress();
|
||||
|
||||
@@ -408,17 +419,17 @@ QString TorrentImpl::name() const
|
||||
|
||||
QDateTime TorrentImpl::creationDate() const
|
||||
{
|
||||
return m_torrentInfo.creationDate();
|
||||
return m_creationDate;
|
||||
}
|
||||
|
||||
QString TorrentImpl::creator() const
|
||||
{
|
||||
return m_torrentInfo.creator();
|
||||
return m_creator;
|
||||
}
|
||||
|
||||
QString TorrentImpl::comment() const
|
||||
{
|
||||
return m_torrentInfo.comment();
|
||||
return m_comment;
|
||||
}
|
||||
|
||||
bool TorrentImpl::isPrivate() const
|
||||
@@ -947,7 +958,52 @@ void TorrentImpl::removeAllTags()
|
||||
|
||||
QDateTime TorrentImpl::addedTime() const
|
||||
{
|
||||
return QDateTime::fromSecsSinceEpoch(m_nativeStatus.added_time);
|
||||
return m_addedTime;
|
||||
}
|
||||
|
||||
QDateTime TorrentImpl::completedTime() const
|
||||
{
|
||||
return m_completedTime;
|
||||
}
|
||||
|
||||
QDateTime TorrentImpl::lastSeenComplete() const
|
||||
{
|
||||
return m_lastSeenComplete;
|
||||
}
|
||||
|
||||
qlonglong TorrentImpl::activeTime() const
|
||||
{
|
||||
return lt::total_seconds(m_nativeStatus.active_duration);
|
||||
}
|
||||
|
||||
qlonglong TorrentImpl::finishedTime() const
|
||||
{
|
||||
return lt::total_seconds(m_nativeStatus.finished_duration);
|
||||
}
|
||||
|
||||
qlonglong TorrentImpl::timeSinceUpload() const
|
||||
{
|
||||
if (m_nativeStatus.last_upload.time_since_epoch().count() == 0)
|
||||
return -1;
|
||||
|
||||
return lt::total_seconds(lt::clock_type::now() - m_nativeStatus.last_upload);
|
||||
}
|
||||
|
||||
qlonglong TorrentImpl::timeSinceDownload() const
|
||||
{
|
||||
if (m_nativeStatus.last_download.time_since_epoch().count() == 0)
|
||||
return -1;
|
||||
|
||||
return lt::total_seconds(lt::clock_type::now() - m_nativeStatus.last_download);
|
||||
}
|
||||
|
||||
qlonglong TorrentImpl::timeSinceActivity() const
|
||||
{
|
||||
const qlonglong upTime = timeSinceUpload();
|
||||
const qlonglong downTime = timeSinceDownload();
|
||||
return ((upTime < 0) != (downTime < 0))
|
||||
? std::max(upTime, downTime)
|
||||
: std::min(upTime, downTime);
|
||||
}
|
||||
|
||||
qreal TorrentImpl::ratioLimit() const
|
||||
@@ -1266,16 +1322,6 @@ qlonglong TorrentImpl::totalUpload() const
|
||||
return m_nativeStatus.all_time_upload;
|
||||
}
|
||||
|
||||
qlonglong TorrentImpl::activeTime() const
|
||||
{
|
||||
return lt::total_seconds(m_nativeStatus.active_duration);
|
||||
}
|
||||
|
||||
qlonglong TorrentImpl::finishedTime() const
|
||||
{
|
||||
return lt::total_seconds(m_nativeStatus.finished_duration);
|
||||
}
|
||||
|
||||
qlonglong TorrentImpl::eta() const
|
||||
{
|
||||
if (isStopped()) return MAX_ETA;
|
||||
@@ -1385,45 +1431,6 @@ int TorrentImpl::totalLeechersCount() const
|
||||
return (m_nativeStatus.num_incomplete > -1) ? m_nativeStatus.num_incomplete : (m_nativeStatus.list_peers - m_nativeStatus.list_seeds);
|
||||
}
|
||||
|
||||
QDateTime TorrentImpl::lastSeenComplete() const
|
||||
{
|
||||
if (m_nativeStatus.last_seen_complete > 0)
|
||||
return QDateTime::fromSecsSinceEpoch(m_nativeStatus.last_seen_complete);
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
QDateTime TorrentImpl::completedTime() const
|
||||
{
|
||||
if (m_nativeStatus.completed_time > 0)
|
||||
return QDateTime::fromSecsSinceEpoch(m_nativeStatus.completed_time);
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
qlonglong TorrentImpl::timeSinceUpload() const
|
||||
{
|
||||
if (m_nativeStatus.last_upload.time_since_epoch().count() == 0)
|
||||
return -1;
|
||||
return lt::total_seconds(lt::clock_type::now() - m_nativeStatus.last_upload);
|
||||
}
|
||||
|
||||
qlonglong TorrentImpl::timeSinceDownload() const
|
||||
{
|
||||
if (m_nativeStatus.last_download.time_since_epoch().count() == 0)
|
||||
return -1;
|
||||
return lt::total_seconds(lt::clock_type::now() - m_nativeStatus.last_download);
|
||||
}
|
||||
|
||||
qlonglong TorrentImpl::timeSinceActivity() const
|
||||
{
|
||||
const qlonglong upTime = timeSinceUpload();
|
||||
const qlonglong downTime = timeSinceDownload();
|
||||
return ((upTime < 0) != (downTime < 0))
|
||||
? std::max(upTime, downTime)
|
||||
: std::min(upTime, downTime);
|
||||
}
|
||||
|
||||
int TorrentImpl::downloadLimit() const
|
||||
{
|
||||
return m_downloadLimit;;
|
||||
@@ -2625,11 +2632,23 @@ bool TorrentImpl::isMoveInProgress() const
|
||||
|
||||
void TorrentImpl::updateStatus(const lt::torrent_status &nativeStatus)
|
||||
{
|
||||
// Since libtorrent alerts are handled asynchronously there can be obsolete
|
||||
// "state update" event reached here after torrent was reloaded in libtorrent.
|
||||
// Just discard such events.
|
||||
if (nativeStatus.handle != m_nativeHandle) [[unlikely]]
|
||||
return;
|
||||
|
||||
const lt::torrent_status oldStatus = std::exchange(m_nativeStatus, nativeStatus);
|
||||
|
||||
if (m_nativeStatus.num_pieces != oldStatus.num_pieces)
|
||||
updateProgress();
|
||||
|
||||
if (m_nativeStatus.completed_time != oldStatus.completed_time)
|
||||
m_completedTime = (m_nativeStatus.completed_time > 0) ? QDateTime::fromSecsSinceEpoch(m_nativeStatus.completed_time) : QDateTime();
|
||||
|
||||
if (m_nativeStatus.last_seen_complete != oldStatus.last_seen_complete)
|
||||
m_lastSeenComplete = QDateTime::fromSecsSinceEpoch(m_nativeStatus.last_seen_complete);
|
||||
|
||||
updateState();
|
||||
|
||||
m_payloadRateMonitor.addSample({nativeStatus.download_payload_rate
|
||||
|
@@ -138,7 +138,15 @@ namespace BitTorrent
|
||||
int piecesCount() const override;
|
||||
int piecesHave() const override;
|
||||
qreal progress() const override;
|
||||
|
||||
QDateTime addedTime() const override;
|
||||
QDateTime completedTime() const override;
|
||||
QDateTime lastSeenComplete() const override;
|
||||
qlonglong activeTime() const override;
|
||||
qlonglong finishedTime() const override;
|
||||
qlonglong timeSinceUpload() const override;
|
||||
qlonglong timeSinceDownload() const override;
|
||||
qlonglong timeSinceActivity() const override;
|
||||
|
||||
qreal ratioLimit() const override;
|
||||
void setRatioLimit(qreal limit) override;
|
||||
@@ -181,8 +189,6 @@ namespace BitTorrent
|
||||
QString error() const override;
|
||||
qlonglong totalDownload() const override;
|
||||
qlonglong totalUpload() const override;
|
||||
qlonglong activeTime() const override;
|
||||
qlonglong finishedTime() const override;
|
||||
qlonglong eta() const override;
|
||||
QVector<qreal> filesProgress() const override;
|
||||
int seedsCount() const override;
|
||||
@@ -191,11 +197,6 @@ namespace BitTorrent
|
||||
int totalSeedsCount() const override;
|
||||
int totalPeersCount() const override;
|
||||
int totalLeechersCount() const override;
|
||||
QDateTime lastSeenComplete() const override;
|
||||
QDateTime completedTime() const override;
|
||||
qlonglong timeSinceUpload() const override;
|
||||
qlonglong timeSinceDownload() const override;
|
||||
qlonglong timeSinceActivity() const override;
|
||||
int downloadLimit() const override;
|
||||
int uploadLimit() const override;
|
||||
bool superSeeding() const override;
|
||||
@@ -342,6 +343,14 @@ namespace BitTorrent
|
||||
|
||||
InfoHash m_infoHash;
|
||||
|
||||
QDateTime m_creationDate;
|
||||
QString m_creator;
|
||||
QString m_comment;
|
||||
|
||||
QDateTime m_addedTime;
|
||||
QDateTime m_completedTime;
|
||||
QDateTime m_lastSeenComplete;
|
||||
|
||||
// m_moveFinishedTriggers is activated only when the following conditions are met:
|
||||
// all file rename jobs complete, all file move jobs complete
|
||||
QQueue<EventTrigger> m_moveFinishedTriggers;
|
||||
|
@@ -396,6 +396,8 @@ bool AutoDownloadRule::matchesSmartEpisodeFilter(const QString &articleTitle) co
|
||||
m_dataPtr->lastComputedEpisodes.append(episodeStr + u"-REPACK");
|
||||
m_dataPtr->lastComputedEpisodes.append(episodeStr + u"-PROPER");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
m_dataPtr->lastComputedEpisodes.append(episodeStr);
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2015-2024 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2012 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -29,11 +29,8 @@
|
||||
|
||||
#include "rss_parser.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QGlobalStatic>
|
||||
#include <QHash>
|
||||
#include <QMetaObject>
|
||||
#include <QRegularExpression>
|
||||
#include <QStringList>
|
||||
#include <QVariant>
|
||||
@@ -359,7 +356,7 @@ namespace
|
||||
};
|
||||
|
||||
// Ported to Qt from KDElibs4
|
||||
QDateTime parseDate(const QString &string)
|
||||
QDateTime parseDate(const QString &string, const QDateTime &fallbackDate)
|
||||
{
|
||||
const char16_t shortDay[][4] =
|
||||
{
|
||||
@@ -382,7 +379,7 @@ namespace
|
||||
|
||||
const QString str = string.trimmed();
|
||||
if (str.isEmpty())
|
||||
return QDateTime::currentDateTime();
|
||||
return fallbackDate;
|
||||
|
||||
int nyear = 6; // indexes within string to values
|
||||
int nmonth = 4;
|
||||
@@ -402,14 +399,14 @@ namespace
|
||||
const bool h1 = (parts[3] == u"-");
|
||||
const bool h2 = (parts[5] == u"-");
|
||||
if (h1 != h2)
|
||||
return QDateTime::currentDateTime();
|
||||
return fallbackDate;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check for the obsolete form "Wdy Mon DD HH:MM:SS YYYY"
|
||||
rx = QRegularExpression {u"^([A-Z][a-z]+)\\s+(\\S+)\\s+(\\d\\d)\\s+(\\d\\d):(\\d\\d):(\\d\\d)\\s+(\\d\\d\\d\\d)$"_s};
|
||||
if (str.indexOf(rx, 0, &rxMatch) != 0)
|
||||
return QDateTime::currentDateTime();
|
||||
return fallbackDate;
|
||||
|
||||
nyear = 7;
|
||||
nmonth = 2;
|
||||
@@ -427,14 +424,14 @@ namespace
|
||||
const int hour = parts[nhour].toInt(&ok[2]);
|
||||
const int minute = parts[nmin].toInt(&ok[3]);
|
||||
if (!ok[0] || !ok[1] || !ok[2] || !ok[3])
|
||||
return QDateTime::currentDateTime();
|
||||
return fallbackDate;
|
||||
|
||||
int second = 0;
|
||||
if (!parts[nsec].isEmpty())
|
||||
{
|
||||
second = parts[nsec].toInt(&ok[0]);
|
||||
if (!ok[0])
|
||||
return QDateTime::currentDateTime();
|
||||
return fallbackDate;
|
||||
}
|
||||
|
||||
const bool leapSecond = (second == 60);
|
||||
@@ -518,21 +515,21 @@ namespace
|
||||
|
||||
const QDate qDate(year, month + 1, day); // convert date, and check for out-of-range
|
||||
if (!qDate.isValid())
|
||||
return QDateTime::currentDateTime();
|
||||
return fallbackDate;
|
||||
|
||||
const QTime qTime(hour, minute, second);
|
||||
QDateTime result(qDate, qTime, Qt::UTC);
|
||||
if (offset)
|
||||
result = result.addSecs(-offset);
|
||||
if (!result.isValid())
|
||||
return QDateTime::currentDateTime(); // invalid date/time
|
||||
return fallbackDate; // invalid date/time
|
||||
|
||||
if (leapSecond)
|
||||
{
|
||||
// Validate a leap second time. Leap seconds are inserted after 23:59:59 UTC.
|
||||
// Convert the time to UTC and check that it is 00:00:00.
|
||||
if ((hour*3600 + minute*60 + 60 - offset + 86400*5) % 86400) // (max abs(offset) is 100 hours)
|
||||
return QDateTime::currentDateTime(); // the time isn't the last second of the day
|
||||
return fallbackDate; // the time isn't the last second of the day
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -550,6 +547,7 @@ RSS::Private::Parser::Parser(const QString &lastBuildDate)
|
||||
void RSS::Private::Parser::parse(const QByteArray &feedData)
|
||||
{
|
||||
QXmlStreamReader xml {feedData};
|
||||
m_fallbackDate = QDateTime::currentDateTime();
|
||||
XmlStreamEntityResolver resolver;
|
||||
xml.setEntityResolver(&resolver);
|
||||
bool foundChannel = false;
|
||||
@@ -641,7 +639,7 @@ void RSS::Private::Parser::parseRssArticle(QXmlStreamReader &xml)
|
||||
}
|
||||
else if (name == u"pubDate")
|
||||
{
|
||||
article[Article::KeyDate] = parseDate(xml.readElementText().trimmed());
|
||||
article[Article::KeyDate] = parseDate(xml.readElementText().trimmed(), m_fallbackDate);
|
||||
}
|
||||
else if (name == u"author")
|
||||
{
|
||||
@@ -755,7 +753,7 @@ void RSS::Private::Parser::parseAtomArticle(QXmlStreamReader &xml)
|
||||
{
|
||||
// ATOM uses standard compliant date, don't do fancy stuff
|
||||
const QDateTime articleDate = QDateTime::fromString(xml.readElementText().trimmed(), Qt::ISODate);
|
||||
article[Article::KeyDate] = (articleDate.isValid() ? articleDate : QDateTime::currentDateTime());
|
||||
article[Article::KeyDate] = (articleDate.isValid() ? articleDate : m_fallbackDate);
|
||||
}
|
||||
else if (name == u"author")
|
||||
{
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2015-2024 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2012 Christophe Dumez <chris@qbittorrent.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <QSet>
|
||||
@@ -66,6 +67,7 @@ namespace RSS::Private
|
||||
void parseAtomChannel(QXmlStreamReader &xml);
|
||||
void addArticle(QVariantHash article);
|
||||
|
||||
QDateTime m_fallbackDate;
|
||||
QString m_baseUrl;
|
||||
ParsingResult m_result;
|
||||
QSet<QString> m_articleIDs;
|
||||
|
@@ -30,7 +30,7 @@
|
||||
|
||||
#define QBT_VERSION_MAJOR 5
|
||||
#define QBT_VERSION_MINOR 0
|
||||
#define QBT_VERSION_BUGFIX 2
|
||||
#define QBT_VERSION_BUGFIX 3
|
||||
#define QBT_VERSION_BUILD 0
|
||||
#define QBT_VERSION_STATUS "" // Should be empty for stable releases!
|
||||
|
||||
|
@@ -106,10 +106,12 @@ void HtmlBrowser::resourceLoaded(QNetworkReply *reply)
|
||||
atts[QNetworkRequest::HttpStatusCodeAttribute] = 200;
|
||||
atts[QNetworkRequest::HttpReasonPhraseAttribute] = u"Ok"_s;
|
||||
metaData.setAttributes(atts);
|
||||
metaData.setLastModified(QDateTime::currentDateTime());
|
||||
metaData.setExpirationDate(QDateTime::currentDateTime().addDays(1));
|
||||
const auto currentDateTime = QDateTime::currentDateTime();
|
||||
metaData.setLastModified(currentDateTime);
|
||||
metaData.setExpirationDate(currentDateTime.addDays(1));
|
||||
QIODevice *dev = m_diskCache->prepare(metaData);
|
||||
if (!dev) return;
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning).pixmap(32, 32).save(dev, "PNG");
|
||||
m_diskCache->insert(dev);
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user