Backport changes to v5.0.x branch

PR #21898.
This commit is contained in:
Vladimir Golovnev 2024-12-09 07:04:06 +03:00 committed by GitHub
commit 53adb7bfa8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 195 additions and 126 deletions

View File

@ -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"

View File

@ -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))

View File

@ -1606,7 +1606,7 @@ void SessionImpl::endStartup(ResumeSessionContext *context)
reannounceToAllTrackers();
}
m_wakeupCheckTimestamp = QDateTime::currentDateTime();
m_wakeupCheckTimestamp = now;
});
m_wakeupCheckTimestamp = QDateTime::currentDateTime();
m_wakeupCheckTimer->start(30s);
@ -5526,8 +5526,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 +6201,10 @@ void SessionImpl::handleTrackerAlert(const lt::tracker_alert *alert)
if (!torrent)
return;
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 +6266,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,20 +6290,21 @@ 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)]
invoke([this, torrentHandle, nativeTrackers = std::move(nativeTrackers)]
{
TorrentImpl *torrent = m_torrents.value(torrentHandle.info_hash());
if (!torrent || torrent->isStopped())
return;
QHash<std::string, QHash<lt::tcp::endpoint, QMap<int, int>>> updatedTrackers = m_updatedTrackerStatuses.take(torrentHandle);
QHash<QString, TrackerEntryStatus> trackers;
trackers.reserve(updatedTrackers.size());
for (const lt::announce_entry &announceEntry : nativeTrackers)
@ -6363,7 +6354,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);

View File

@ -541,7 +541,6 @@ namespace BitTorrent
void populateAdditionalTrackers();
void enableIPFilter();
void disableIPFilter();
void processTrackerStatuses();
void processTorrentShareLimits(TorrentImpl *torrent);
void populateExcludedFileNamesRegExpList();
void prepareStartup();
@ -605,7 +604,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 = {});

View File

@ -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;

View File

@ -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();

View File

@ -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

View File

@ -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;
};
}

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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")
{

View File

@ -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;

View File

@ -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);

View File

@ -104,7 +104,7 @@ QVariantMap serialize(const BitTorrent::Torrent &torrent)
const qlonglong timeSinceActivity = torrent.timeSinceActivity();
return (timeSinceActivity < 0)
? Utils::DateTime::toSecsSinceEpoch(torrent.addedTime())
: (QDateTime::currentDateTime().toSecsSinceEpoch() - timeSinceActivity);
: (QDateTime::currentSecsSinceEpoch() - timeSinceActivity);
};
return {

View File

@ -129,7 +129,7 @@ void TorrentCreatorController::addTaskAction()
.sourcePath = Path(params()[KEY_SOURCE_PATH]),
.torrentFilePath = Path(params()[KEY_TORRENT_FILE_PATH]),
.comment = params()[KEY_COMMENT],
.source = params()[KEY_COMMENT],
.source = params()[KEY_SOURCE],
.trackers = params()[KEY_TRACKERS].split(u'|'),
.urlSeeds = params()[KEY_URL_SEEDS].split(u'|')
};

View File

@ -219,7 +219,7 @@ window.qBittorrent.PropTrackers = (function() {
method: "post",
data: {
hash: current_hash,
urls: selectedTrackers.join("|")
urls: selectedTrackers.map(encodeURIComponent).join("|")
},
onSuccess: function() {
updateData();

View File

@ -37,10 +37,13 @@ function submitLoginForm(event) {
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8");
xhr.addEventListener("readystatechange", () => {
if (xhr.readyState === 4) { // DONE state
if ((xhr.status === 200) && (xhr.responseText === "Ok."))
if ((xhr.status === 200) && (xhr.responseText === "Ok.")) {
location.replace(location);
else
location.reload(true);
}
else {
errorMsgElement.textContent = "QBT_TR(Invalid Username or Password.)QBT_TR[CONTEXT=HttpServer]";
}
}
});
xhr.addEventListener("error", () => {