mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-08-19 12:59:56 -07:00
commit
53adb7bfa8
18 changed files with 195 additions and 126 deletions
|
@ -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_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_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_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_ENGLISH} "Uninstall qBittorrent"
|
||||||
LangString inst_uninstall_link_description ${LANG_ITALIAN} "Disinstalla qBittorrent"
|
LangString inst_uninstall_link_description ${LANG_ITALIAN} "Disinstalla qBittorrent"
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ namespace
|
||||||
{
|
{
|
||||||
const QString DB_CONNECTION_NAME = u"ResumeDataStorage"_s;
|
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_META = u"meta"_s;
|
||||||
const QString DB_TABLE_TORRENTS = u"torrents"_s;
|
const QString DB_TABLE_TORRENTS = u"torrents"_s;
|
||||||
|
@ -628,7 +628,31 @@ void BitTorrent::DBResumeDataStorage::updateDB(const int fromVersion) const
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fromVersion <= 6)
|
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});
|
const QString updateMetaVersionQuery = makeUpdateStatement(DB_TABLE_META, {DB_COLUMN_NAME, DB_COLUMN_VALUE});
|
||||||
if (!query.prepare(updateMetaVersionQuery))
|
if (!query.prepare(updateMetaVersionQuery))
|
||||||
|
|
|
@ -1606,7 +1606,7 @@ void SessionImpl::endStartup(ResumeSessionContext *context)
|
||||||
reannounceToAllTrackers();
|
reannounceToAllTrackers();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_wakeupCheckTimestamp = QDateTime::currentDateTime();
|
m_wakeupCheckTimestamp = now;
|
||||||
});
|
});
|
||||||
m_wakeupCheckTimestamp = QDateTime::currentDateTime();
|
m_wakeupCheckTimestamp = QDateTime::currentDateTime();
|
||||||
m_wakeupCheckTimer->start(30s);
|
m_wakeupCheckTimer->start(30s);
|
||||||
|
@ -5526,8 +5526,6 @@ void SessionImpl::readAlerts()
|
||||||
|
|
||||||
// Some torrents may become "finished" after different alerts handling.
|
// Some torrents may become "finished" after different alerts handling.
|
||||||
processPendingFinishedTorrents();
|
processPendingFinishedTorrents();
|
||||||
|
|
||||||
processTrackerStatuses();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SessionImpl::handleAddTorrentAlert(const lt::add_torrent_alert *alert)
|
void SessionImpl::handleAddTorrentAlert(const lt::add_torrent_alert *alert)
|
||||||
|
@ -6203,7 +6201,10 @@ void SessionImpl::handleTrackerAlert(const lt::tracker_alert *alert)
|
||||||
if (!torrent)
|
if (!torrent)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
const auto prevSize = m_updatedTrackerStatuses.size();
|
||||||
QMap<int, int> &updateInfo = m_updatedTrackerStatuses[torrent->nativeHandle()][std::string(alert->tracker_url())][alert->local_endpoint];
|
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)
|
if (alert->type() == lt::tracker_reply_alert::alert_type)
|
||||||
{
|
{
|
||||||
|
@ -6265,17 +6266,6 @@ void SessionImpl::handleTorrentConflictAlert(const lt::torrent_conflict_alert *a
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
void SessionImpl::saveStatistics() const
|
||||||
{
|
{
|
||||||
if (!m_isStatisticsDirty)
|
if (!m_isStatisticsDirty)
|
||||||
|
@ -6300,20 +6290,21 @@ void SessionImpl::loadStatistics()
|
||||||
m_previouslyUploaded = value[u"AlltimeUL"_s].toLongLong();
|
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
|
try
|
||||||
{
|
{
|
||||||
std::vector<lt::announce_entry> nativeTrackers = torrentHandle.trackers();
|
std::vector<lt::announce_entry> nativeTrackers = torrentHandle.trackers();
|
||||||
invoke([this, torrentHandle, nativeTrackers = std::move(nativeTrackers)
|
invoke([this, torrentHandle, nativeTrackers = std::move(nativeTrackers)]
|
||||||
, updatedTrackers = std::move(updatedTrackers)]
|
|
||||||
{
|
{
|
||||||
TorrentImpl *torrent = m_torrents.value(torrentHandle.info_hash());
|
TorrentImpl *torrent = m_torrents.value(torrentHandle.info_hash());
|
||||||
if (!torrent || torrent->isStopped())
|
if (!torrent || torrent->isStopped())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
QHash<std::string, QHash<lt::tcp::endpoint, QMap<int, int>>> updatedTrackers = m_updatedTrackerStatuses.take(torrentHandle);
|
||||||
|
|
||||||
QHash<QString, TrackerEntryStatus> trackers;
|
QHash<QString, TrackerEntryStatus> trackers;
|
||||||
trackers.reserve(updatedTrackers.size());
|
trackers.reserve(updatedTrackers.size());
|
||||||
for (const lt::announce_entry &announceEntry : nativeTrackers)
|
for (const lt::announce_entry &announceEntry : nativeTrackers)
|
||||||
|
@ -6363,7 +6354,7 @@ void SessionImpl::handleRemovedTorrent(const TorrentID &torrentID, const QString
|
||||||
m_removingTorrents.erase(removingTorrentDataIter);
|
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();
|
const auto secsSinceNow = lt::duration_cast<lt::seconds>(timePoint - m_ltNow + lt::milliseconds(500)).count();
|
||||||
return m_qNow.addSecs(secsSinceNow);
|
return m_qNow.addSecs(secsSinceNow);
|
||||||
|
|
|
@ -541,7 +541,6 @@ namespace BitTorrent
|
||||||
void populateAdditionalTrackers();
|
void populateAdditionalTrackers();
|
||||||
void enableIPFilter();
|
void enableIPFilter();
|
||||||
void disableIPFilter();
|
void disableIPFilter();
|
||||||
void processTrackerStatuses();
|
|
||||||
void processTorrentShareLimits(TorrentImpl *torrent);
|
void processTorrentShareLimits(TorrentImpl *torrent);
|
||||||
void populateExcludedFileNamesRegExpList();
|
void populateExcludedFileNamesRegExpList();
|
||||||
void prepareStartup();
|
void prepareStartup();
|
||||||
|
@ -605,7 +604,7 @@ namespace BitTorrent
|
||||||
void saveStatistics() const;
|
void saveStatistics() const;
|
||||||
void loadStatistics();
|
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 = {});
|
void handleRemovedTorrent(const TorrentID &torrentID, const QString &partfileRemoveError = {});
|
||||||
|
|
||||||
|
|
|
@ -215,7 +215,15 @@ namespace BitTorrent
|
||||||
virtual int piecesCount() const = 0;
|
virtual int piecesCount() const = 0;
|
||||||
virtual int piecesHave() const = 0;
|
virtual int piecesHave() const = 0;
|
||||||
virtual qreal progress() const = 0;
|
virtual qreal progress() const = 0;
|
||||||
|
|
||||||
virtual QDateTime addedTime() 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
|
// Share limits
|
||||||
virtual qreal ratioLimit() const = 0;
|
virtual qreal ratioLimit() const = 0;
|
||||||
|
@ -254,8 +262,6 @@ namespace BitTorrent
|
||||||
virtual QString error() const = 0;
|
virtual QString error() const = 0;
|
||||||
virtual qlonglong totalDownload() const = 0;
|
virtual qlonglong totalDownload() const = 0;
|
||||||
virtual qlonglong totalUpload() const = 0;
|
virtual qlonglong totalUpload() const = 0;
|
||||||
virtual qlonglong activeTime() const = 0;
|
|
||||||
virtual qlonglong finishedTime() const = 0;
|
|
||||||
virtual qlonglong eta() const = 0;
|
virtual qlonglong eta() const = 0;
|
||||||
virtual int seedsCount() const = 0;
|
virtual int seedsCount() const = 0;
|
||||||
virtual int peersCount() const = 0;
|
virtual int peersCount() const = 0;
|
||||||
|
@ -263,11 +269,6 @@ namespace BitTorrent
|
||||||
virtual int totalSeedsCount() const = 0;
|
virtual int totalSeedsCount() const = 0;
|
||||||
virtual int totalPeersCount() const = 0;
|
virtual int totalPeersCount() const = 0;
|
||||||
virtual int totalLeechersCount() 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 downloadLimit() const = 0;
|
||||||
virtual int uploadLimit() const = 0;
|
virtual int uploadLimit() const = 0;
|
||||||
virtual bool superSeeding() const = 0;
|
virtual bool superSeeding() const = 0;
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include <libtorrent/file_storage.hpp>
|
#include <libtorrent/file_storage.hpp>
|
||||||
#include <libtorrent/torrent_info.hpp>
|
#include <libtorrent/torrent_info.hpp>
|
||||||
|
|
||||||
|
#include <QtSystemDetection>
|
||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
|
@ -123,7 +124,14 @@ void TorrentCreator::run()
|
||||||
// need to sort the file names by natural sort order
|
// need to sort the file names by natural sort order
|
||||||
QStringList dirs = {m_params.sourcePath.data()};
|
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())
|
while (dirIter.hasNext())
|
||||||
{
|
{
|
||||||
const QString filePath = dirIter.next();
|
const QString filePath = dirIter.next();
|
||||||
|
@ -138,7 +146,12 @@ void TorrentCreator::run()
|
||||||
{
|
{
|
||||||
QStringList tmpNames; // natural sort files within each dir
|
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())
|
while (fileIter.hasNext())
|
||||||
{
|
{
|
||||||
const QFileInfo fileInfo = fileIter.nextFileInfo();
|
const QFileInfo fileInfo = fileIter.nextFileInfo();
|
||||||
|
|
|
@ -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
|
||||||
|
@ -35,9 +35,7 @@
|
||||||
#include <libtorrent/write_resume_data.hpp>
|
#include <libtorrent/write_resume_data.hpp>
|
||||||
|
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QDateTime>
|
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QString>
|
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
#include "base/global.h"
|
#include "base/global.h"
|
||||||
|
@ -147,7 +145,13 @@ BitTorrent::TorrentDescriptor::TorrentDescriptor(lt::add_torrent_params ltAddTor
|
||||||
: m_ltAddTorrentParams {std::move(ltAddTorrentParams)}
|
: m_ltAddTorrentParams {std::move(ltAddTorrentParams)}
|
||||||
{
|
{
|
||||||
if (m_ltAddTorrentParams.ti && m_ltAddTorrentParams.ti->is_valid())
|
if (m_ltAddTorrentParams.ti && m_ltAddTorrentParams.ti->is_valid())
|
||||||
|
{
|
||||||
m_info.emplace(*m_ltAddTorrentParams.ti);
|
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
|
BitTorrent::InfoHash BitTorrent::TorrentDescriptor::infoHash() const
|
||||||
|
@ -166,18 +170,17 @@ QString BitTorrent::TorrentDescriptor::name() const
|
||||||
|
|
||||||
QDateTime BitTorrent::TorrentDescriptor::creationDate() const
|
QDateTime BitTorrent::TorrentDescriptor::creationDate() const
|
||||||
{
|
{
|
||||||
return ((m_ltAddTorrentParams.ti->creation_date() != 0)
|
return m_creationDate;
|
||||||
? QDateTime::fromSecsSinceEpoch(m_ltAddTorrentParams.ti->creation_date()) : QDateTime());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString BitTorrent::TorrentDescriptor::creator() const
|
QString BitTorrent::TorrentDescriptor::creator() const
|
||||||
{
|
{
|
||||||
return QString::fromStdString(m_ltAddTorrentParams.ti->creator());
|
return m_creator;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString BitTorrent::TorrentDescriptor::comment() const
|
QString BitTorrent::TorrentDescriptor::comment() const
|
||||||
{
|
{
|
||||||
return QString::fromStdString(m_ltAddTorrentParams.ti->comment());
|
return m_comment;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::optional<BitTorrent::TorrentInfo> &BitTorrent::TorrentDescriptor::info() const
|
const std::optional<BitTorrent::TorrentInfo> &BitTorrent::TorrentDescriptor::info() const
|
||||||
|
|
|
@ -33,7 +33,9 @@
|
||||||
#include <libtorrent/add_torrent_params.hpp>
|
#include <libtorrent/add_torrent_params.hpp>
|
||||||
|
|
||||||
#include <QtContainerFwd>
|
#include <QtContainerFwd>
|
||||||
|
#include <QDateTime>
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
#include "base/3rdparty/expected.hpp"
|
#include "base/3rdparty/expected.hpp"
|
||||||
#include "base/path.h"
|
#include "base/path.h"
|
||||||
|
@ -41,8 +43,6 @@
|
||||||
#include "torrentinfo.h"
|
#include "torrentinfo.h"
|
||||||
|
|
||||||
class QByteArray;
|
class QByteArray;
|
||||||
class QDateTime;
|
|
||||||
class QString;
|
|
||||||
class QUrl;
|
class QUrl;
|
||||||
|
|
||||||
namespace BitTorrent
|
namespace BitTorrent
|
||||||
|
@ -78,6 +78,9 @@ namespace BitTorrent
|
||||||
|
|
||||||
lt::add_torrent_params m_ltAddTorrentParams;
|
lt::add_torrent_params m_ltAddTorrentParams;
|
||||||
std::optional<TorrentInfo> m_info;
|
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 (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.
|
// Initialize it only if torrent is added with metadata.
|
||||||
// Otherwise it should be initialized in "Metadata received" handler.
|
// Otherwise it should be initialized in "Metadata received" handler.
|
||||||
m_torrentInfo = TorrentInfo(*m_ltAddTorrentParams.ti);
|
m_torrentInfo = TorrentInfo(*m_ltAddTorrentParams.ti);
|
||||||
|
@ -365,6 +370,12 @@ TorrentImpl::TorrentImpl(SessionImpl *session, lt::session *nativeSession
|
||||||
m_urlSeeds.append(QString::fromStdString(urlSeed));
|
m_urlSeeds.append(QString::fromStdString(urlSeed));
|
||||||
m_nativeStatus = extensionData->status;
|
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())
|
if (hasMetadata())
|
||||||
updateProgress();
|
updateProgress();
|
||||||
|
|
||||||
|
@ -408,17 +419,17 @@ QString TorrentImpl::name() const
|
||||||
|
|
||||||
QDateTime TorrentImpl::creationDate() const
|
QDateTime TorrentImpl::creationDate() const
|
||||||
{
|
{
|
||||||
return m_torrentInfo.creationDate();
|
return m_creationDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString TorrentImpl::creator() const
|
QString TorrentImpl::creator() const
|
||||||
{
|
{
|
||||||
return m_torrentInfo.creator();
|
return m_creator;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString TorrentImpl::comment() const
|
QString TorrentImpl::comment() const
|
||||||
{
|
{
|
||||||
return m_torrentInfo.comment();
|
return m_comment;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TorrentImpl::isPrivate() const
|
bool TorrentImpl::isPrivate() const
|
||||||
|
@ -947,7 +958,52 @@ void TorrentImpl::removeAllTags()
|
||||||
|
|
||||||
QDateTime TorrentImpl::addedTime() const
|
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
|
qreal TorrentImpl::ratioLimit() const
|
||||||
|
@ -1266,16 +1322,6 @@ qlonglong TorrentImpl::totalUpload() const
|
||||||
return m_nativeStatus.all_time_upload;
|
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
|
qlonglong TorrentImpl::eta() const
|
||||||
{
|
{
|
||||||
if (isStopped()) return MAX_ETA;
|
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);
|
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
|
int TorrentImpl::downloadLimit() const
|
||||||
{
|
{
|
||||||
return m_downloadLimit;;
|
return m_downloadLimit;;
|
||||||
|
@ -2625,11 +2632,23 @@ bool TorrentImpl::isMoveInProgress() const
|
||||||
|
|
||||||
void TorrentImpl::updateStatus(const lt::torrent_status &nativeStatus)
|
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);
|
const lt::torrent_status oldStatus = std::exchange(m_nativeStatus, nativeStatus);
|
||||||
|
|
||||||
if (m_nativeStatus.num_pieces != oldStatus.num_pieces)
|
if (m_nativeStatus.num_pieces != oldStatus.num_pieces)
|
||||||
updateProgress();
|
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();
|
updateState();
|
||||||
|
|
||||||
m_payloadRateMonitor.addSample({nativeStatus.download_payload_rate
|
m_payloadRateMonitor.addSample({nativeStatus.download_payload_rate
|
||||||
|
|
|
@ -138,7 +138,15 @@ namespace BitTorrent
|
||||||
int piecesCount() const override;
|
int piecesCount() const override;
|
||||||
int piecesHave() const override;
|
int piecesHave() const override;
|
||||||
qreal progress() const override;
|
qreal progress() const override;
|
||||||
|
|
||||||
QDateTime addedTime() 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;
|
qreal ratioLimit() const override;
|
||||||
void setRatioLimit(qreal limit) override;
|
void setRatioLimit(qreal limit) override;
|
||||||
|
@ -181,8 +189,6 @@ namespace BitTorrent
|
||||||
QString error() const override;
|
QString error() const override;
|
||||||
qlonglong totalDownload() const override;
|
qlonglong totalDownload() const override;
|
||||||
qlonglong totalUpload() const override;
|
qlonglong totalUpload() const override;
|
||||||
qlonglong activeTime() const override;
|
|
||||||
qlonglong finishedTime() const override;
|
|
||||||
qlonglong eta() const override;
|
qlonglong eta() const override;
|
||||||
QVector<qreal> filesProgress() const override;
|
QVector<qreal> filesProgress() const override;
|
||||||
int seedsCount() const override;
|
int seedsCount() const override;
|
||||||
|
@ -191,11 +197,6 @@ namespace BitTorrent
|
||||||
int totalSeedsCount() const override;
|
int totalSeedsCount() const override;
|
||||||
int totalPeersCount() const override;
|
int totalPeersCount() const override;
|
||||||
int totalLeechersCount() 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 downloadLimit() const override;
|
||||||
int uploadLimit() const override;
|
int uploadLimit() const override;
|
||||||
bool superSeeding() const override;
|
bool superSeeding() const override;
|
||||||
|
@ -342,6 +343,14 @@ namespace BitTorrent
|
||||||
|
|
||||||
InfoHash m_infoHash;
|
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:
|
// m_moveFinishedTriggers is activated only when the following conditions are met:
|
||||||
// all file rename jobs complete, all file move jobs complete
|
// all file rename jobs complete, all file move jobs complete
|
||||||
QQueue<EventTrigger> m_moveFinishedTriggers;
|
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"-REPACK");
|
||||||
m_dataPtr->lastComputedEpisodes.append(episodeStr + u"-PROPER");
|
m_dataPtr->lastComputedEpisodes.append(episodeStr + u"-PROPER");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_dataPtr->lastComputedEpisodes.append(episodeStr);
|
m_dataPtr->lastComputedEpisodes.append(episodeStr);
|
||||||
|
|
|
@ -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>
|
||||||
* Copyright (C) 2012 Christophe Dumez <chris@qbittorrent.org>
|
* Copyright (C) 2012 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
|
@ -29,11 +29,8 @@
|
||||||
|
|
||||||
#include "rss_parser.h"
|
#include "rss_parser.h"
|
||||||
|
|
||||||
#include <QDateTime>
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QGlobalStatic>
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QMetaObject>
|
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
@ -359,7 +356,7 @@ namespace
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ported to Qt from KDElibs4
|
// Ported to Qt from KDElibs4
|
||||||
QDateTime parseDate(const QString &string)
|
QDateTime parseDate(const QString &string, const QDateTime &fallbackDate)
|
||||||
{
|
{
|
||||||
const char16_t shortDay[][4] =
|
const char16_t shortDay[][4] =
|
||||||
{
|
{
|
||||||
|
@ -382,7 +379,7 @@ namespace
|
||||||
|
|
||||||
const QString str = string.trimmed();
|
const QString str = string.trimmed();
|
||||||
if (str.isEmpty())
|
if (str.isEmpty())
|
||||||
return QDateTime::currentDateTime();
|
return fallbackDate;
|
||||||
|
|
||||||
int nyear = 6; // indexes within string to values
|
int nyear = 6; // indexes within string to values
|
||||||
int nmonth = 4;
|
int nmonth = 4;
|
||||||
|
@ -402,14 +399,14 @@ namespace
|
||||||
const bool h1 = (parts[3] == u"-");
|
const bool h1 = (parts[3] == u"-");
|
||||||
const bool h2 = (parts[5] == u"-");
|
const bool h2 = (parts[5] == u"-");
|
||||||
if (h1 != h2)
|
if (h1 != h2)
|
||||||
return QDateTime::currentDateTime();
|
return fallbackDate;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Check for the obsolete form "Wdy Mon DD HH:MM:SS YYYY"
|
// 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};
|
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)
|
if (str.indexOf(rx, 0, &rxMatch) != 0)
|
||||||
return QDateTime::currentDateTime();
|
return fallbackDate;
|
||||||
|
|
||||||
nyear = 7;
|
nyear = 7;
|
||||||
nmonth = 2;
|
nmonth = 2;
|
||||||
|
@ -427,14 +424,14 @@ namespace
|
||||||
const int hour = parts[nhour].toInt(&ok[2]);
|
const int hour = parts[nhour].toInt(&ok[2]);
|
||||||
const int minute = parts[nmin].toInt(&ok[3]);
|
const int minute = parts[nmin].toInt(&ok[3]);
|
||||||
if (!ok[0] || !ok[1] || !ok[2] || !ok[3])
|
if (!ok[0] || !ok[1] || !ok[2] || !ok[3])
|
||||||
return QDateTime::currentDateTime();
|
return fallbackDate;
|
||||||
|
|
||||||
int second = 0;
|
int second = 0;
|
||||||
if (!parts[nsec].isEmpty())
|
if (!parts[nsec].isEmpty())
|
||||||
{
|
{
|
||||||
second = parts[nsec].toInt(&ok[0]);
|
second = parts[nsec].toInt(&ok[0]);
|
||||||
if (!ok[0])
|
if (!ok[0])
|
||||||
return QDateTime::currentDateTime();
|
return fallbackDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool leapSecond = (second == 60);
|
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
|
const QDate qDate(year, month + 1, day); // convert date, and check for out-of-range
|
||||||
if (!qDate.isValid())
|
if (!qDate.isValid())
|
||||||
return QDateTime::currentDateTime();
|
return fallbackDate;
|
||||||
|
|
||||||
const QTime qTime(hour, minute, second);
|
const QTime qTime(hour, minute, second);
|
||||||
QDateTime result(qDate, qTime, Qt::UTC);
|
QDateTime result(qDate, qTime, Qt::UTC);
|
||||||
if (offset)
|
if (offset)
|
||||||
result = result.addSecs(-offset);
|
result = result.addSecs(-offset);
|
||||||
if (!result.isValid())
|
if (!result.isValid())
|
||||||
return QDateTime::currentDateTime(); // invalid date/time
|
return fallbackDate; // invalid date/time
|
||||||
|
|
||||||
if (leapSecond)
|
if (leapSecond)
|
||||||
{
|
{
|
||||||
// Validate a leap second time. Leap seconds are inserted after 23:59:59 UTC.
|
// 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.
|
// 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)
|
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;
|
return result;
|
||||||
|
@ -550,6 +547,7 @@ RSS::Private::Parser::Parser(const QString &lastBuildDate)
|
||||||
void RSS::Private::Parser::parse(const QByteArray &feedData)
|
void RSS::Private::Parser::parse(const QByteArray &feedData)
|
||||||
{
|
{
|
||||||
QXmlStreamReader xml {feedData};
|
QXmlStreamReader xml {feedData};
|
||||||
|
m_fallbackDate = QDateTime::currentDateTime();
|
||||||
XmlStreamEntityResolver resolver;
|
XmlStreamEntityResolver resolver;
|
||||||
xml.setEntityResolver(&resolver);
|
xml.setEntityResolver(&resolver);
|
||||||
bool foundChannel = false;
|
bool foundChannel = false;
|
||||||
|
@ -641,7 +639,7 @@ void RSS::Private::Parser::parseRssArticle(QXmlStreamReader &xml)
|
||||||
}
|
}
|
||||||
else if (name == u"pubDate")
|
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")
|
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
|
// ATOM uses standard compliant date, don't do fancy stuff
|
||||||
const QDateTime articleDate = QDateTime::fromString(xml.readElementText().trimmed(), Qt::ISODate);
|
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")
|
else if (name == u"author")
|
||||||
{
|
{
|
||||||
|
|
|
@ -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>
|
||||||
* Copyright (C) 2012 Christophe Dumez <chris@qbittorrent.org>
|
* Copyright (C) 2012 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
|
@ -29,6 +29,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <QDateTime>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
@ -66,6 +67,7 @@ namespace RSS::Private
|
||||||
void parseAtomChannel(QXmlStreamReader &xml);
|
void parseAtomChannel(QXmlStreamReader &xml);
|
||||||
void addArticle(QVariantHash article);
|
void addArticle(QVariantHash article);
|
||||||
|
|
||||||
|
QDateTime m_fallbackDate;
|
||||||
QString m_baseUrl;
|
QString m_baseUrl;
|
||||||
ParsingResult m_result;
|
ParsingResult m_result;
|
||||||
QSet<QString> m_articleIDs;
|
QSet<QString> m_articleIDs;
|
||||||
|
|
|
@ -106,10 +106,12 @@ void HtmlBrowser::resourceLoaded(QNetworkReply *reply)
|
||||||
atts[QNetworkRequest::HttpStatusCodeAttribute] = 200;
|
atts[QNetworkRequest::HttpStatusCodeAttribute] = 200;
|
||||||
atts[QNetworkRequest::HttpReasonPhraseAttribute] = u"Ok"_s;
|
atts[QNetworkRequest::HttpReasonPhraseAttribute] = u"Ok"_s;
|
||||||
metaData.setAttributes(atts);
|
metaData.setAttributes(atts);
|
||||||
metaData.setLastModified(QDateTime::currentDateTime());
|
const auto currentDateTime = QDateTime::currentDateTime();
|
||||||
metaData.setExpirationDate(QDateTime::currentDateTime().addDays(1));
|
metaData.setLastModified(currentDateTime);
|
||||||
|
metaData.setExpirationDate(currentDateTime.addDays(1));
|
||||||
QIODevice *dev = m_diskCache->prepare(metaData);
|
QIODevice *dev = m_diskCache->prepare(metaData);
|
||||||
if (!dev) return;
|
if (!dev)
|
||||||
|
return;
|
||||||
|
|
||||||
QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning).pixmap(32, 32).save(dev, "PNG");
|
QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning).pixmap(32, 32).save(dev, "PNG");
|
||||||
m_diskCache->insert(dev);
|
m_diskCache->insert(dev);
|
||||||
|
|
|
@ -104,7 +104,7 @@ QVariantMap serialize(const BitTorrent::Torrent &torrent)
|
||||||
const qlonglong timeSinceActivity = torrent.timeSinceActivity();
|
const qlonglong timeSinceActivity = torrent.timeSinceActivity();
|
||||||
return (timeSinceActivity < 0)
|
return (timeSinceActivity < 0)
|
||||||
? Utils::DateTime::toSecsSinceEpoch(torrent.addedTime())
|
? Utils::DateTime::toSecsSinceEpoch(torrent.addedTime())
|
||||||
: (QDateTime::currentDateTime().toSecsSinceEpoch() - timeSinceActivity);
|
: (QDateTime::currentSecsSinceEpoch() - timeSinceActivity);
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -129,7 +129,7 @@ void TorrentCreatorController::addTaskAction()
|
||||||
.sourcePath = Path(params()[KEY_SOURCE_PATH]),
|
.sourcePath = Path(params()[KEY_SOURCE_PATH]),
|
||||||
.torrentFilePath = Path(params()[KEY_TORRENT_FILE_PATH]),
|
.torrentFilePath = Path(params()[KEY_TORRENT_FILE_PATH]),
|
||||||
.comment = params()[KEY_COMMENT],
|
.comment = params()[KEY_COMMENT],
|
||||||
.source = params()[KEY_COMMENT],
|
.source = params()[KEY_SOURCE],
|
||||||
.trackers = params()[KEY_TRACKERS].split(u'|'),
|
.trackers = params()[KEY_TRACKERS].split(u'|'),
|
||||||
.urlSeeds = params()[KEY_URL_SEEDS].split(u'|')
|
.urlSeeds = params()[KEY_URL_SEEDS].split(u'|')
|
||||||
};
|
};
|
||||||
|
|
|
@ -219,7 +219,7 @@ window.qBittorrent.PropTrackers = (function() {
|
||||||
method: "post",
|
method: "post",
|
||||||
data: {
|
data: {
|
||||||
hash: current_hash,
|
hash: current_hash,
|
||||||
urls: selectedTrackers.join("|")
|
urls: selectedTrackers.map(encodeURIComponent).join("|")
|
||||||
},
|
},
|
||||||
onSuccess: function() {
|
onSuccess: function() {
|
||||||
updateData();
|
updateData();
|
||||||
|
|
|
@ -37,11 +37,14 @@ function submitLoginForm(event) {
|
||||||
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8");
|
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8");
|
||||||
xhr.addEventListener("readystatechange", () => {
|
xhr.addEventListener("readystatechange", () => {
|
||||||
if (xhr.readyState === 4) { // DONE state
|
if (xhr.readyState === 4) { // DONE state
|
||||||
if ((xhr.status === 200) && (xhr.responseText === "Ok."))
|
if ((xhr.status === 200) && (xhr.responseText === "Ok.")) {
|
||||||
location.replace(location);
|
location.replace(location);
|
||||||
else
|
location.reload(true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
errorMsgElement.textContent = "QBT_TR(Invalid Username or Password.)QBT_TR[CONTEXT=HttpServer]";
|
errorMsgElement.textContent = "QBT_TR(Invalid Username or Password.)QBT_TR[CONTEXT=HttpServer]";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
xhr.addEventListener("error", () => {
|
xhr.addEventListener("error", () => {
|
||||||
errorMsgElement.textContent = (xhr.responseText !== "")
|
errorMsgElement.textContent = (xhr.responseText !== "")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue