Merge branch 'master' into multi_select

This commit is contained in:
justusaac 2025-05-07 00:00:01 -05:00 committed by GitHub
commit 33d9cd2a95
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
90 changed files with 2031 additions and 2139 deletions

View file

@ -21,7 +21,7 @@ jobs:
matrix:
libt_version: ["2.0.11", "1.2.20"]
qbt_gui: ["GUI=ON", "GUI=OFF"]
qt_version: ["6.5.2"]
qt_version: ["6.6.3"]
env:
boost_path: "${{ github.workspace }}/../boost"
@ -162,6 +162,7 @@ jobs:
- name: Package AppImage
run: |
rm -f "${{ runner.workspace }}/Qt/${{ matrix.qt_version }}/gcc_64/plugins/sqldrivers/libqsqlmimer.so"
./linuxdeploy-x86_64.AppImage --appdir qbittorrent --plugin qt
rm qbittorrent/apprun-hooks/*
cp .github/workflows/helper/appimage/export_vars.sh qbittorrent/apprun-hooks/export_vars.sh

View file

@ -16,7 +16,7 @@ jobs:
matrix:
libt_version: ["2.0.11"]
qbt_gui: ["GUI=ON"]
qt_version: ["6.5.2"]
qt_version: ["6.6.3"]
env:
boost_path: "${{ github.workspace }}/../boost"

View file

@ -8,7 +8,7 @@ project(qBittorrent
# version requirements - older versions may work, but you are on your own
set(minBoostVersion 1.76)
set(minQt6Version 6.5.0)
set(minQt6Version 6.6.0)
set(minOpenSSLVersion 3.0.2)
set(minLibtorrent1Version 1.2.19)
set(minLibtorrentVersion 2.0.10)

View file

@ -11,7 +11,7 @@ qBittorrent - A BitTorrent client in C++ / Qt
- OpenSSL >= 3.0.2
- Qt 6.5.0 - 6.x
- Qt 6.6.0 - 6.x
- zlib >= 1.2.11

View file

@ -20,7 +20,7 @@ target_compile_features(qbt_common_cfg INTERFACE
)
target_compile_definitions(qbt_common_cfg INTERFACE
QT_DISABLE_DEPRECATED_UP_TO=0x060500
QT_DISABLE_DEPRECATED_UP_TO=0x060600
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
QT_NO_CAST_FROM_BYTEARRAY

View file

@ -674,9 +674,7 @@ void Application::runExternalProgram(const QString &programTemplate, const BitTo
QProcess proc;
proc.setProgram(command);
proc.setArguments(args);
#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
proc.setUnixProcessParameters(QProcess::UnixProcessFlag::CloseFileDescriptors);
#endif
if (proc.startDetached())
{

View file

@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2020 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2020-2025 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
@ -27,13 +27,14 @@
*/
#include "filesearcher.h"
#include "base/bittorrent/common.h"
#include "base/bittorrent/infohash.h"
void FileSearcher::search(const BitTorrent::TorrentID &id, const PathList &originalFileNames
, const Path &savePath, const Path &downloadPath, const bool forceAppendExt)
#include <QPromise>
#include "base/bittorrent/common.h"
namespace
{
const auto findInDir = [](const Path &dirPath, PathList &fileNames, const bool forceAppendExt) -> bool
bool findInDir(const Path &dirPath, PathList &fileNames, const bool forceAppendExt)
{
bool found = false;
for (Path &fileName : fileNames)
@ -58,8 +59,12 @@ void FileSearcher::search(const BitTorrent::TorrentID &id, const PathList &origi
}
return found;
};
}
}
void FileSearcher::search(const PathList &originalFileNames, const Path &savePath
, const Path &downloadPath, const bool forceAppendExt, QPromise<FileSearchResult> &promise)
{
Path usedPath = savePath;
PathList adjustedFileNames = originalFileNames;
const bool found = findInDir(usedPath, adjustedFileNames, (forceAppendExt && downloadPath.isEmpty()));
@ -69,5 +74,5 @@ void FileSearcher::search(const BitTorrent::TorrentID &id, const PathList &origi
findInDir(usedPath, adjustedFileNames, forceAppendExt);
}
emit searchFinished(id, usedPath, adjustedFileNames);
promise.addResult(FileSearchResult {.savePath = usedPath, .fileNames = adjustedFileNames});
}

View file

@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2020 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2020-2025 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
@ -32,10 +32,13 @@
#include "base/path.h"
namespace BitTorrent
template <typename T> class QPromise;
struct FileSearchResult
{
class TorrentID;
}
Path savePath;
PathList fileNames;
};
class FileSearcher final : public QObject
{
@ -43,12 +46,8 @@ class FileSearcher final : public QObject
Q_DISABLE_COPY_MOVE(FileSearcher)
public:
FileSearcher() = default;
using QObject::QObject;
public slots:
void search(const BitTorrent::TorrentID &id, const PathList &originalFileNames
, const Path &savePath, const Path &downloadPath, bool forceAppendExt);
signals:
void searchFinished(const BitTorrent::TorrentID &id, const Path &savePath, const PathList &fileNames);
void search(const PathList &originalFileNames, const Path &savePath
, const Path &downloadPath, bool forceAppendExt, QPromise<FileSearchResult> &promise);
};

View file

@ -61,6 +61,7 @@
#include <QDeadlineTimer>
#include <QDebug>
#include <QDir>
#include <QFuture>
#include <QHostAddress>
#include <QJsonArray>
#include <QJsonDocument>
@ -69,6 +70,7 @@
#include <QMutexLocker>
#include <QNetworkAddressEntry>
#include <QNetworkInterface>
#include <QPromise>
#include <QRegularExpression>
#include <QString>
#include <QThread>
@ -470,11 +472,11 @@ SessionImpl::SessionImpl(QObject *parent)
, m_additionalTrackers(BITTORRENT_SESSION_KEY(u"AdditionalTrackers"_s))
, m_isAddTrackersFromURLEnabled(BITTORRENT_SESSION_KEY(u"AddTrackersFromURLEnabled"_s), false)
, m_additionalTrackersURL(BITTORRENT_SESSION_KEY(u"AdditionalTrackersURL"_s))
, m_globalMaxRatio(BITTORRENT_SESSION_KEY(u"GlobalMaxRatio"_s), -1, [](qreal r) { return r < 0 ? -1. : r;})
, m_globalMaxSeedingMinutes(BITTORRENT_SESSION_KEY(u"GlobalMaxSeedingMinutes"_s), Torrent::NO_SEEDING_TIME_LIMIT
, clampValue(Torrent::NO_SEEDING_TIME_LIMIT, Torrent::MAX_SEEDING_TIME))
, m_globalMaxInactiveSeedingMinutes(BITTORRENT_SESSION_KEY(u"GlobalMaxInactiveSeedingMinutes"_s), Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT
, clampValue(Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT, Torrent::MAX_INACTIVE_SEEDING_TIME))
, m_globalMaxRatio(BITTORRENT_SESSION_KEY(u"GlobalMaxRatio"_s), -1, [](qreal r) { return r < 0 ? -1. : r; })
, m_globalMaxSeedingMinutes(BITTORRENT_SESSION_KEY(u"GlobalMaxSeedingMinutes"_s)
, Torrent::NO_SEEDING_TIME_LIMIT, lowerLimited(Torrent::NO_SEEDING_TIME_LIMIT))
, m_globalMaxInactiveSeedingMinutes(BITTORRENT_SESSION_KEY(u"GlobalMaxInactiveSeedingMinutes"_s)
, Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT, lowerLimited(Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT))
, m_isAddTorrentToQueueTop(BITTORRENT_SESSION_KEY(u"AddTorrentToTopOfQueue"_s), false)
, m_isAddTorrentStopped(BITTORRENT_SESSION_KEY(u"AddTorrentStopped"_s), false)
, m_torrentStopCondition(BITTORRENT_SESSION_KEY(u"TorrentStopCondition"_s), Torrent::StopCondition::None)
@ -622,7 +624,6 @@ SessionImpl::SessionImpl(QObject *parent)
m_fileSearcher = new FileSearcher;
m_fileSearcher->moveToThread(m_ioThread.get());
connect(m_ioThread.get(), &QThread::finished, m_fileSearcher, &QObject::deleteLater);
connect(m_fileSearcher, &FileSearcher::searchFinished, this, &SessionImpl::fileSearchFinished);
m_torrentContentRemover = new TorrentContentRemover;
m_torrentContentRemover->moveToThread(m_ioThread.get());
@ -1241,7 +1242,7 @@ qreal SessionImpl::globalMaxRatio() const
void SessionImpl::setGlobalMaxRatio(qreal ratio)
{
if (ratio < 0)
ratio = -1.;
ratio = Torrent::NO_RATIO_LIMIT;
if (ratio != globalMaxRatio())
{
@ -1257,7 +1258,7 @@ int SessionImpl::globalMaxSeedingMinutes() const
void SessionImpl::setGlobalMaxSeedingMinutes(int minutes)
{
minutes = std::clamp(minutes, Torrent::NO_SEEDING_TIME_LIMIT, Torrent::MAX_SEEDING_TIME);
minutes = std::max(minutes, Torrent::NO_SEEDING_TIME_LIMIT);
if (minutes != globalMaxSeedingMinutes())
{
@ -1273,7 +1274,7 @@ int SessionImpl::globalMaxInactiveSeedingMinutes() const
void SessionImpl::setGlobalMaxInactiveSeedingMinutes(int minutes)
{
minutes = std::clamp(minutes, Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT, Torrent::MAX_INACTIVE_SEEDING_TIME);
minutes = std::max(minutes, Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT);
if (minutes != globalMaxInactiveSeedingMinutes())
{
@ -1642,11 +1643,7 @@ void SessionImpl::endStartup(ResumeSessionContext *context)
auto wakeupCheckTimer = new QTimer(this);
connect(wakeupCheckTimer, &QTimer::timeout, this, [this]
{
#if (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
const bool hasSystemSlept = m_wakeupCheckTimestamp.durationElapsed() > 100s;
#else
const bool hasSystemSlept = m_wakeupCheckTimestamp.elapsed() > std::chrono::milliseconds(100s).count();
#endif
if (hasSystemSlept)
{
LogMsg(tr("System wake-up event detected. Re-announcing to all the trackers..."));
@ -2334,19 +2331,19 @@ void SessionImpl::processTorrentShareLimits(TorrentImpl *torrent)
QString description;
if (const qreal ratio = torrent->realRatio();
(ratioLimit >= 0) && (ratio <= Torrent::MAX_RATIO) && (ratio >= ratioLimit))
(ratioLimit >= 0) && (ratio >= ratioLimit))
{
reached = true;
description = tr("Torrent reached the share ratio limit.");
}
else if (const qlonglong seedingTimeInMinutes = torrent->finishedTime() / 60;
(seedingTimeLimit >= 0) && (seedingTimeInMinutes <= Torrent::MAX_SEEDING_TIME) && (seedingTimeInMinutes >= seedingTimeLimit))
(seedingTimeLimit >= 0) && (seedingTimeInMinutes >= seedingTimeLimit))
{
reached = true;
description = tr("Torrent reached the seeding time limit.");
}
else if (const qlonglong inactiveSeedingTimeInMinutes = torrent->timeSinceActivity() / 60;
(inactiveSeedingTimeLimit >= 0) && (inactiveSeedingTimeInMinutes <= Torrent::MAX_INACTIVE_SEEDING_TIME) && (inactiveSeedingTimeInMinutes >= inactiveSeedingTimeLimit))
(inactiveSeedingTimeLimit >= 0) && (inactiveSeedingTimeInMinutes >= inactiveSeedingTimeLimit))
{
reached = true;
description = tr("Torrent reached the inactive seeding time limit.");
@ -2380,31 +2377,6 @@ void SessionImpl::processTorrentShareLimits(TorrentImpl *torrent)
}
}
void SessionImpl::fileSearchFinished(const TorrentID &id, const Path &savePath, const PathList &fileNames)
{
TorrentImpl *torrent = m_torrents.value(id);
if (torrent)
{
torrent->fileSearchFinished(savePath, fileNames);
return;
}
const auto loadingTorrentsIter = m_loadingTorrents.find(id);
if (loadingTorrentsIter != m_loadingTorrents.end())
{
LoadTorrentParams &params = loadingTorrentsIter.value();
lt::add_torrent_params &p = params.ltAddTorrentParams;
p.save_path = savePath.toString().toStdString();
const TorrentInfo torrentInfo {*p.ti};
const auto nativeIndexes = torrentInfo.nativeIndexes();
for (int i = 0; i < fileNames.size(); ++i)
p.renamed_files[nativeIndexes[i]] = fileNames[i].toString().toStdString();
m_nativeSession->async_add_torrent(p);
}
}
void SessionImpl::torrentContentRemovingFinished(const QString &torrentName, const QString &errorMessage)
{
if (errorMessage.isEmpty())
@ -2832,11 +2804,12 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr
lt::add_torrent_params &p = loadTorrentParams.ltAddTorrentParams;
p = source.ltAddTorrentParams();
bool isFindingIncompleteFiles = false;
const bool useAutoTMM = loadTorrentParams.useAutoTMM;
const Path actualSavePath = useAutoTMM ? categorySavePath(loadTorrentParams.category) : loadTorrentParams.savePath;
bool needFindIncompleteFiles = false;
PathList filePaths;
if (hasMetadata)
{
// Torrent that is being added with metadata is considered to be added as stopped
@ -2851,7 +2824,7 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr
Q_ASSERT(addTorrentParams.filePaths.isEmpty() || (addTorrentParams.filePaths.size() == torrentInfo.filesCount()));
PathList filePaths = addTorrentParams.filePaths;
filePaths = addTorrentParams.filePaths;
if (filePaths.isEmpty())
{
filePaths = torrentInfo.filePaths();
@ -2897,13 +2870,9 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr
if (!loadTorrentParams.hasFinishedStatus)
{
const Path actualDownloadPath = useAutoTMM
? categoryDownloadPath(loadTorrentParams.category) : loadTorrentParams.downloadPath;
findIncompleteFiles(torrentInfo, actualSavePath, actualDownloadPath, filePaths);
isFindingIncompleteFiles = true;
needFindIncompleteFiles = true;
}
if (!isFindingIncompleteFiles)
else
{
for (int index = 0; index < filePaths.size(); ++index)
p.renamed_files[nativeIndexes[index]] = filePaths.at(index).toString().toStdString();
@ -3002,23 +2971,51 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr
m_loadingTorrents.insert(id, loadTorrentParams);
if (infoHash.isHybrid())
m_hybridTorrentsByAltID.insert(altID, nullptr);
if (!isFindingIncompleteFiles)
if (needFindIncompleteFiles)
{
const Path actualDownloadPath = useAutoTMM
? categoryDownloadPath(loadTorrentParams.category) : loadTorrentParams.downloadPath;
findIncompleteFiles(actualSavePath, actualDownloadPath, filePaths).then(this
, [this, id](const FileSearchResult &result)
{
const auto loadingTorrentsIter = m_loadingTorrents.find(id);
Q_ASSERT(loadingTorrentsIter != m_loadingTorrents.end());
if (loadingTorrentsIter == m_loadingTorrents.end()) [[unlikely]]
return;
LoadTorrentParams &params = loadingTorrentsIter.value();
lt::add_torrent_params &p = params.ltAddTorrentParams;
p.save_path = result.savePath.toString().toStdString();
const TorrentInfo torrentInfo {*p.ti};
const auto nativeIndexes = torrentInfo.nativeIndexes();
for (int i = 0; i < result.fileNames.size(); ++i)
p.renamed_files[nativeIndexes[i]] = result.fileNames[i].toString().toStdString();
m_nativeSession->async_add_torrent(p);
});
}
else
{
m_nativeSession->async_add_torrent(p);
}
return true;
}
void SessionImpl::findIncompleteFiles(const TorrentInfo &torrentInfo, const Path &savePath
, const Path &downloadPath, const PathList &filePaths) const
QFuture<FileSearchResult> SessionImpl::findIncompleteFiles(const Path &savePath, const Path &downloadPath, const PathList &filePaths) const
{
Q_ASSERT(filePaths.isEmpty() || (filePaths.size() == torrentInfo.filesCount()));
const auto searchId = TorrentID::fromInfoHash(torrentInfo.infoHash());
const PathList originalFileNames = (filePaths.isEmpty() ? torrentInfo.filePaths() : filePaths);
QMetaObject::invokeMethod(m_fileSearcher, [=, this]
QPromise<FileSearchResult> promise;
QFuture<FileSearchResult> future = promise.future();
promise.start();
QMetaObject::invokeMethod(m_fileSearcher, [=, this, promise = std::move(promise)]() mutable
{
m_fileSearcher->search(searchId, originalFileNames, savePath, downloadPath, isAppendExtensionEnabled());
m_fileSearcher->search(filePaths, savePath, downloadPath, isAppendExtensionEnabled(), promise);
promise.finish();
});
return future;
}
void SessionImpl::enablePortMapping()

View file

@ -61,12 +61,16 @@ class QString;
class QTimer;
class QUrl;
template <typename T> class QFuture;
class BandwidthScheduler;
class FileSearcher;
class FilterParserThread;
class FreeDiskSpaceChecker;
class NativeSessionExtension;
struct FileSearchResult;
namespace BitTorrent
{
enum class MoveStorageMode;
@ -478,8 +482,7 @@ namespace BitTorrent
bool addMoveTorrentStorageJob(TorrentImpl *torrent, const Path &newPath, MoveStorageMode mode, MoveStorageContext context);
void findIncompleteFiles(const TorrentInfo &torrentInfo, const Path &savePath
, const Path &downloadPath, const PathList &filePaths = {}) const;
QFuture<FileSearchResult> findIncompleteFiles(const Path &savePath, const Path &downloadPath, const PathList &filePaths = {}) const;
void enablePortMapping();
void disablePortMapping();
@ -514,7 +517,6 @@ namespace BitTorrent
void generateResumeData();
void handleIPFilterParsed(int ruleCount);
void handleIPFilterError();
void fileSearchFinished(const TorrentID &id, const Path &savePath, const PathList &fileNames);
void torrentContentRemovingFinished(const QString &torrentName, const QString &errorMessage);
private:

View file

@ -29,6 +29,8 @@
#include "torrent.h"
#include <limits>
#include <QHash>
#include "infohash.h"
@ -51,9 +53,7 @@ namespace BitTorrent
const int Torrent::USE_GLOBAL_INACTIVE_SEEDING_TIME = -2;
const int Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT = -1;
const qreal Torrent::MAX_RATIO = 9999;
const int Torrent::MAX_SEEDING_TIME = 525600;
const int Torrent::MAX_INACTIVE_SEEDING_TIME = 525600;
const qreal Torrent::MAX_RATIO = std::numeric_limits<qreal>::infinity();
TorrentID Torrent::id() const
{

View file

@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015-2024 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2015-2025 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
@ -45,6 +45,8 @@ class QByteArray;
class QDateTime;
class QUrl;
template <typename T> class QFuture;
namespace BitTorrent
{
enum class DownloadPriority;
@ -132,8 +134,6 @@ namespace BitTorrent
static const int NO_INACTIVE_SEEDING_TIME_LIMIT;
static const qreal MAX_RATIO;
static const int MAX_SEEDING_TIME;
static const int MAX_INACTIVE_SEEDING_TIME;
using TorrentContentHandler::TorrentContentHandler;
@ -275,10 +275,7 @@ namespace BitTorrent
virtual bool isDHTDisabled() const = 0;
virtual bool isPEXDisabled() const = 0;
virtual bool isLSDDisabled() const = 0;
virtual QList<PeerInfo> peers() const = 0;
virtual QBitArray pieces() const = 0;
virtual QBitArray downloadingPieces() const = 0;
virtual QList<int> pieceAvailability() const = 0;
virtual qreal distributedCopies() const = 0;
virtual qreal maxRatio() const = 0;
virtual int maxSeedingTime() const = 0;
@ -325,10 +322,10 @@ namespace BitTorrent
virtual nonstd::expected<QByteArray, QString> exportToBuffer() const = 0;
virtual nonstd::expected<void, QString> exportToFile(const Path &path) const = 0;
virtual void fetchPeerInfo(std::function<void (QList<PeerInfo>)> resultHandler) const = 0;
virtual void fetchURLSeeds(std::function<void (QList<QUrl>)> resultHandler) const = 0;
virtual void fetchPieceAvailability(std::function<void (QList<int>)> resultHandler) const = 0;
virtual void fetchDownloadingPieces(std::function<void (QBitArray)> resultHandler) const = 0;
virtual QFuture<QList<PeerInfo>> fetchPeerInfo() const = 0;
virtual QFuture<QList<QUrl>> fetchURLSeeds() const = 0;
virtual QFuture<QList<int>> fetchPieceAvailability() const = 0;
virtual QFuture<QBitArray> fetchDownloadingPieces() const = 0;
TorrentID id() const;
bool isRunning() const;

View file

@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2022-2023 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2022-2025 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
@ -34,6 +34,8 @@
#include "abstractfilestorage.h"
#include "downloadpriority.h"
template <typename T> class QFuture;
namespace BitTorrent
{
class TorrentContentHandler : public QObject, public AbstractFileStorage
@ -52,8 +54,7 @@ namespace BitTorrent
* This is not the same as torrrent availability, it is just a fraction of pieces
* that can be downloaded right now. It varies between 0 to 1.
*/
virtual QList<qreal> availableFileFractions() const = 0;
virtual void fetchAvailableFileFractions(std::function<void (QList<qreal>)> resultHandler) const = 0;
virtual QFuture<QList<qreal>> fetchAvailableFileFractions() const = 0;
virtual void prioritizeFiles(const QList<DownloadPriority> &priorities) = 0;
virtual void flushCache() const = 0;

View file

@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015-2024 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2015-2025 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
@ -51,7 +51,9 @@
#include <QByteArray>
#include <QCache>
#include <QDebug>
#include <QFuture>
#include <QPointer>
#include <QPromise>
#include <QSet>
#include <QStringList>
#include <QUrl>
@ -67,6 +69,7 @@
#include "common.h"
#include "downloadpriority.h"
#include "extensiondata.h"
#include "filesearcher.h"
#include "loadtorrentparams.h"
#include "ltqbitarray.h"
#include "lttypecast.h"
@ -1465,48 +1468,11 @@ bool TorrentImpl::isLSDDisabled() const
return static_cast<bool>(m_nativeStatus.flags & lt::torrent_flags::disable_lsd);
}
QList<PeerInfo> TorrentImpl::peers() const
{
std::vector<lt::peer_info> nativePeers;
m_nativeHandle.get_peer_info(nativePeers);
QList<PeerInfo> peers;
peers.reserve(static_cast<decltype(peers)::size_type>(nativePeers.size()));
for (const lt::peer_info &peer : nativePeers)
peers.append(PeerInfo(peer, pieces()));
return peers;
}
QBitArray TorrentImpl::pieces() const
{
return m_pieces;
}
QBitArray TorrentImpl::downloadingPieces() const
{
if (!hasMetadata())
return {};
std::vector<lt::partial_piece_info> queue;
m_nativeHandle.get_download_queue(queue);
QBitArray result {piecesCount()};
for (const lt::partial_piece_info &info : queue)
result.setBit(LT::toUnderlyingType(info.piece_index));
return result;
}
QList<int> TorrentImpl::pieceAvailability() const
{
std::vector<int> avail;
m_nativeHandle.piece_availability(avail);
return {avail.cbegin(), avail.cend()};
}
qreal TorrentImpl::distributedCopies() const
{
return m_nativeStatus.distributed_copies;
@ -1549,7 +1515,8 @@ qreal TorrentImpl::realRatio() const
const qreal ratio = upload / static_cast<qreal>(download);
Q_ASSERT(ratio >= 0);
return (ratio > MAX_RATIO) ? MAX_RATIO : ratio;
return ratio;
}
int TorrentImpl::uploadPayloadRate() const
@ -1751,12 +1718,6 @@ void TorrentImpl::applyFirstLastPiecePriority(const bool enabled)
m_nativeHandle.prioritize_pieces(piecePriorities);
}
void TorrentImpl::fileSearchFinished(const Path &savePath, const PathList &fileNames)
{
if (m_maintenanceJob == MaintenanceJob::HandleMetadata)
endReceivedMetadataHandling(savePath, fileNames);
}
TrackerEntryStatus TorrentImpl::updateTrackerEntryStatus(const lt::announce_entry &announceEntry, const QHash<lt::tcp::endpoint, QMap<int, int>> &updateInfo)
{
const auto it = std::find_if(m_trackerEntryStatuses.begin(), m_trackerEntryStatuses.end()
@ -2150,7 +2111,7 @@ void TorrentImpl::handleSaveResumeDataAlert(const lt::save_resume_data_alert *p)
// URL seed list have been changed by libtorrent for some reason, so we need to update cached one.
// Unfortunately, URL seed list containing in "resume data" is generated according to different rules
// than the list we usually cache, so we have to request it from the appropriate source.
fetchURLSeeds([this](const QList<QUrl> &urlSeeds) { m_urlSeeds = urlSeeds; });
fetchURLSeeds().then(this, [this](const QList<QUrl> &urlSeeds) { m_urlSeeds = urlSeeds; });
}
if ((m_maintenanceJob == MaintenanceJob::HandleMetadata) && p->params.ti)
@ -2197,7 +2158,12 @@ void TorrentImpl::handleSaveResumeDataAlert(const lt::save_resume_data_alert *p)
filePaths[i] = Path(it->second);
}
m_session->findIncompleteFiles(metadata, savePath(), downloadPath(), filePaths);
m_session->findIncompleteFiles(savePath(), downloadPath(), filePaths).then(this
, [this](const FileSearchResult &result)
{
if (m_maintenanceJob == MaintenanceJob::HandleMetadata)
endReceivedMetadataHandling(result.savePath, result.fileNames);
});
}
else
{
@ -2712,8 +2678,6 @@ void TorrentImpl::setRatioLimit(qreal limit)
{
if (limit < USE_GLOBAL_RATIO)
limit = NO_RATIO_LIMIT;
else if (limit > MAX_RATIO)
limit = MAX_RATIO;
if (m_ratioLimit != limit)
{
@ -2727,8 +2691,6 @@ void TorrentImpl::setSeedingTimeLimit(int limit)
{
if (limit < USE_GLOBAL_SEEDING_TIME)
limit = NO_SEEDING_TIME_LIMIT;
else if (limit > MAX_SEEDING_TIME)
limit = MAX_SEEDING_TIME;
if (m_seedingTimeLimit != limit)
{
@ -2742,8 +2704,6 @@ void TorrentImpl::setInactiveSeedingTimeLimit(int limit)
{
if (limit < USE_GLOBAL_INACTIVE_SEEDING_TIME)
limit = NO_INACTIVE_SEEDING_TIME_LIMIT;
else if (limit > MAX_INACTIVE_SEEDING_TIME)
limit = MAX_SEEDING_TIME;
if (m_inactiveSeedingTimeLimit != limit)
{
@ -2930,9 +2890,9 @@ nonstd::expected<void, QString> TorrentImpl::exportToFile(const Path &path) cons
return {};
}
void TorrentImpl::fetchPeerInfo(std::function<void (QList<PeerInfo>)> resultHandler) const
QFuture<QList<PeerInfo>> TorrentImpl::fetchPeerInfo() const
{
invokeAsync([nativeHandle = m_nativeHandle, allPieces = pieces()]() -> QList<PeerInfo>
return invokeAsync([nativeHandle = m_nativeHandle, allPieces = pieces()]() -> QList<PeerInfo>
{
try
{
@ -2947,13 +2907,12 @@ void TorrentImpl::fetchPeerInfo(std::function<void (QList<PeerInfo>)> resultHand
catch (const std::exception &) {}
return {};
}
, std::move(resultHandler));
});
}
void TorrentImpl::fetchURLSeeds(std::function<void (QList<QUrl>)> resultHandler) const
QFuture<QList<QUrl>> TorrentImpl::fetchURLSeeds() const
{
invokeAsync([nativeHandle = m_nativeHandle]() -> QList<QUrl>
return invokeAsync([nativeHandle = m_nativeHandle]() -> QList<QUrl>
{
try
{
@ -2967,13 +2926,12 @@ void TorrentImpl::fetchURLSeeds(std::function<void (QList<QUrl>)> resultHandler)
catch (const std::exception &) {}
return {};
}
, std::move(resultHandler));
});
}
void TorrentImpl::fetchPieceAvailability(std::function<void (QList<int>)> resultHandler) const
QFuture<QList<int>> TorrentImpl::fetchPieceAvailability() const
{
invokeAsync([nativeHandle = m_nativeHandle]() -> QList<int>
return invokeAsync([nativeHandle = m_nativeHandle]() -> QList<int>
{
try
{
@ -2984,13 +2942,12 @@ void TorrentImpl::fetchPieceAvailability(std::function<void (QList<int>)> result
catch (const std::exception &) {}
return {};
}
, std::move(resultHandler));
});
}
void TorrentImpl::fetchDownloadingPieces(std::function<void (QBitArray)> resultHandler) const
QFuture<QBitArray> TorrentImpl::fetchDownloadingPieces() const
{
invokeAsync([nativeHandle = m_nativeHandle, torrentInfo = m_torrentInfo]() -> QBitArray
return invokeAsync([nativeHandle = m_nativeHandle, torrentInfo = m_torrentInfo]() -> QBitArray
{
try
{
@ -3009,13 +2966,12 @@ void TorrentImpl::fetchDownloadingPieces(std::function<void (QBitArray)> resultH
catch (const std::exception &) {}
return {};
}
, std::move(resultHandler));
});
}
void TorrentImpl::fetchAvailableFileFractions(std::function<void (QList<qreal>)> resultHandler) const
QFuture<QList<qreal>> TorrentImpl::fetchAvailableFileFractions() const
{
invokeAsync([nativeHandle = m_nativeHandle, torrentInfo = m_torrentInfo]() -> QList<qreal>
return invokeAsync([nativeHandle = m_nativeHandle, torrentInfo = m_torrentInfo]() -> QList<qreal>
{
if (!torrentInfo.isValid() || (torrentInfo.filesCount() <= 0))
return {};
@ -3049,8 +3005,7 @@ void TorrentImpl::fetchAvailableFileFractions(std::function<void (QList<qreal>)>
catch (const std::exception &) {}
return {};
}
, std::move(resultHandler));
});
}
void TorrentImpl::prioritizeFiles(const QList<DownloadPriority> &priorities)
@ -3090,47 +3045,17 @@ void TorrentImpl::prioritizeFiles(const QList<DownloadPriority> &priorities)
manageActualFilePaths();
}
QList<qreal> TorrentImpl::availableFileFractions() const
template <typename Func>
QFuture<std::invoke_result_t<Func>> TorrentImpl::invokeAsync(Func &&func) const
{
Q_ASSERT(hasMetadata());
const int filesCount = this->filesCount();
if (filesCount <= 0) return {};
const QList<int> piecesAvailability = pieceAvailability();
// libtorrent returns empty array for seeding only torrents
if (piecesAvailability.empty()) return QList<qreal>(filesCount, -1);
QList<qreal> res;
res.reserve(filesCount);
for (int i = 0; i < filesCount; ++i)
QPromise<std::invoke_result_t<Func>> promise;
const auto future = promise.future();
promise.start();
m_session->invokeAsync([func = std::forward<Func>(func), promise = std::move(promise)]() mutable
{
const TorrentInfo::PieceRange filePieces = m_torrentInfo.filePieces(i);
int availablePieces = 0;
for (const int piece : filePieces)
availablePieces += (piecesAvailability[piece] > 0) ? 1 : 0;
const qreal availability = filePieces.isEmpty()
? 1 // the file has no pieces, so it is available by default
: static_cast<qreal>(availablePieces) / filePieces.size();
res.push_back(availability);
}
return res;
}
template <typename Func, typename Callback>
void TorrentImpl::invokeAsync(Func func, Callback resultHandler) const
{
m_session->invokeAsync([session = m_session
, func = std::move(func)
, resultHandler = std::move(resultHandler)
, thisTorrent = QPointer<const TorrentImpl>(this)]() mutable
{
session->invoke([result = func(), thisTorrent, resultHandler = std::move(resultHandler)]
{
if (thisTorrent)
resultHandler(result);
});
promise.addResult(func());
promise.finish();
});
return future;
}

View file

@ -203,10 +203,7 @@ namespace BitTorrent
bool isDHTDisabled() const override;
bool isPEXDisabled() const override;
bool isLSDDisabled() const override;
QList<PeerInfo> peers() const override;
QBitArray pieces() const override;
QBitArray downloadingPieces() const override;
QList<int> pieceAvailability() const override;
qreal distributedCopies() const override;
qreal maxRatio() const override;
int maxSeedingTime() const override;
@ -220,7 +217,6 @@ namespace BitTorrent
int connectionsCount() const override;
int connectionsLimit() const override;
qlonglong nextAnnounce() const override;
QList<qreal> availableFileFractions() const override;
void setName(const QString &name) override;
void setSequentialDownload(bool enable) override;
@ -258,11 +254,11 @@ namespace BitTorrent
nonstd::expected<QByteArray, QString> exportToBuffer() const override;
nonstd::expected<void, QString> exportToFile(const Path &path) const override;
void fetchPeerInfo(std::function<void (QList<PeerInfo>)> resultHandler) const override;
void fetchURLSeeds(std::function<void (QList<QUrl>)> resultHandler) const override;
void fetchPieceAvailability(std::function<void (QList<int>)> resultHandler) const override;
void fetchDownloadingPieces(std::function<void (QBitArray)> resultHandler) const override;
void fetchAvailableFileFractions(std::function<void (QList<qreal>)> resultHandler) const override;
QFuture<QList<PeerInfo>> fetchPeerInfo() const override;
QFuture<QList<QUrl>> fetchURLSeeds() const override;
QFuture<QList<int>> fetchPieceAvailability() const override;
QFuture<QBitArray> fetchDownloadingPieces() const override;
QFuture<QList<qreal>> fetchAvailableFileFractions() const override;
bool needSaveResumeData() const;
@ -278,7 +274,6 @@ namespace BitTorrent
void requestResumeData(lt::resume_data_flags_t flags = {});
void deferredRequestResumeData();
void handleMoveStorageJobFinished(const Path &path, MoveStorageContext context, bool hasOutstandingJob);
void fileSearchFinished(const Path &savePath, const PathList &fileNames);
TrackerEntryStatus updateTrackerEntryStatus(const lt::announce_entry &announceEntry, const QHash<lt::tcp::endpoint, QMap<int, int>> &updateInfo);
void resetTrackerEntryStatuses();
@ -326,8 +321,8 @@ namespace BitTorrent
nonstd::expected<lt::entry, QString> exportTorrent() const;
template <typename Func, typename Callback>
void invokeAsync(Func func, Callback resultHandler) const;
template <typename Func>
QFuture<std::invoke_result_t<Func>> invokeAsync(Func &&func) const;
SessionImpl *const m_session = nullptr;
lt::session *m_nativeSession = nullptr;

View file

@ -42,7 +42,7 @@ SearchDownloadHandler::SearchDownloadHandler(const QString &pluginName, const QS
, m_downloadProcess {new QProcess(this)}
{
m_downloadProcess->setProcessEnvironment(m_manager->proxyEnvironment());
#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
#ifdef Q_OS_UNIX
m_downloadProcess->setUnixProcessParameters(QProcess::UnixProcessFlag::CloseFileDescriptors);
#endif
connect(m_downloadProcess, qOverload<int, QProcess::ExitStatus>(&QProcess::finished)

View file

@ -72,7 +72,7 @@ SearchHandler::SearchHandler(const QString &pattern, const QString &category, co
// Load environment variables (proxy)
m_searchProcess->setProcessEnvironment(m_manager->proxyEnvironment());
m_searchProcess->setProgram(Utils::ForeignApps::pythonInfo().executableName);
#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
#ifdef Q_OS_UNIX
m_searchProcess->setUnixProcessParameters(QProcess::UnixProcessFlag::CloseFileDescriptors);
#endif

View file

@ -546,7 +546,7 @@ void SearchPluginManager::update()
{
QProcess nova;
nova.setProcessEnvironment(proxyEnvironment());
#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
#ifdef Q_OS_UNIX
nova.setUnixProcessParameters(QProcess::UnixProcessFlag::CloseFileDescriptors);
#endif

View file

@ -57,7 +57,7 @@ namespace
info = {};
QProcess proc;
#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
#ifdef Q_OS_UNIX
proc.setUnixProcessParameters(QProcess::UnixProcessFlag::CloseFileDescriptors);
#endif
proc.start(exeName, {u"--version"_s}, QIODevice::ReadOnly);

View file

@ -61,7 +61,12 @@ QString Utils::String::fromLocal8Bit(const std::string_view string)
QString Utils::String::wildcardToRegexPattern(const QString &pattern)
{
#if (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
return QRegularExpression::wildcardToRegularExpression(pattern
, (QRegularExpression::UnanchoredWildcardConversion | QRegularExpression::NonPathWildcardConversion));
#else
return QRegularExpression::wildcardToRegularExpression(pattern, QRegularExpression::UnanchoredWildcardConversion);
#endif
}
QStringList Utils::String::splitCommand(const QString &command)

View file

@ -32,12 +32,14 @@
#include <algorithm>
#include <functional>
#include <QtVersionChecks>
#include <QAction>
#include <QByteArray>
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QFileDialog>
#include <QFuture>
#include <QList>
#include <QMenu>
#include <QMessageBox>
@ -242,14 +244,13 @@ public:
return QList<qreal>(filesCount(), 0);
}
QList<qreal> availableFileFractions() const override
QFuture<QList<qreal>> fetchAvailableFileFractions() const override
{
return QList<qreal>(filesCount(), 0);
}
void fetchAvailableFileFractions(std::function<void (QList<qreal>)> resultHandler) const override
{
resultHandler(availableFileFractions());
#if (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0))
return QtFuture::makeReadyValueFuture(QList<qreal>(filesCount(), 0));
#else
return QtFuture::makeReadyFuture(QList<qreal>(filesCount(), 0));
#endif
}
void prioritizeFiles(const QList<BitTorrent::DownloadPriority> &priorities) override

View file

@ -1031,7 +1031,7 @@
<item>
<widget class="QGroupBox" name="duplicateTorrentGroup">
<property name="title">
<string>When duplicate torrent is being added</string>
<string>When adding a duplicate torrent</string>
</property>
<layout class="QVBoxLayout" name="duplicateTorrentBoxLayout">
<item>
@ -1047,7 +1047,7 @@
<item>
<widget class="QCheckBox" name="checkConfirmMergeTrackers">
<property name="text">
<string>Ask for merging trackers when torrent is being added manually</string>
<string>Ask to merge trackers for manually added torrent</string>
</property>
<property name="checked">
<bool>true</bool>
@ -3028,9 +3028,6 @@ Disable encryption: Only connect to peers without protocol encryption</string>
<property name="enabled">
<bool>false</bool>
</property>
<property name="maximum">
<double>9998.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
@ -3290,15 +3287,9 @@ Disable encryption: Only connect to peers without protocol encryption</string>
</item>
<item>
<widget class="QSpinBox" name="searchHistoryLengthSpinBox">
<property name="buttonSymbols">
<enum>QAbstractSpinBox::ButtonSymbols::PlusMinus</enum>
</property>
<property name="maximum">
<number>99</number>
</property>
<property name="stepType">
<enum>QAbstractSpinBox::StepType::DefaultStepType</enum>
</property>
</widget>
</item>
<item>

View file

@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2023 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2023-2025 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
@ -33,6 +33,7 @@
#include <QApplication>
#include <QClipboard>
#include <QFuture>
#include <QHeaderView>
#include <QHostAddress>
#include <QList>
@ -406,7 +407,7 @@ void PeerListWidget::loadPeers(const BitTorrent::Torrent *torrent)
return;
using TorrentPtr = QPointer<const BitTorrent::Torrent>;
torrent->fetchPeerInfo([this, torrent = TorrentPtr(torrent)](const QList<BitTorrent::PeerInfo> &peers)
torrent->fetchPeerInfo().then(this, [this, torrent = TorrentPtr(torrent)](const QList<BitTorrent::PeerInfo> &peers)
{
if (torrent != m_properties->getCurrentTorrent())
return;

View file

@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2022-2024 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2022-2025 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
@ -32,6 +32,7 @@
#include <QClipboard>
#include <QDateTime>
#include <QDebug>
#include <QFuture>
#include <QListWidgetItem>
#include <QMenu>
#include <QMessageBox>
@ -440,10 +441,10 @@ void PropertiesWidget::loadDynamicData()
// Update ratio info
const qreal ratio = m_torrent->realRatio();
m_ui->labelShareRatioVal->setText(ratio > BitTorrent::Torrent::MAX_RATIO ? C_INFINITY : Utils::String::fromDouble(ratio, 2));
m_ui->labelShareRatioVal->setText(ratio >= BitTorrent::Torrent::MAX_RATIO ? C_INFINITY : Utils::String::fromDouble(ratio, 2));
const qreal popularity = m_torrent->popularity();
m_ui->labelPopularityVal->setText(popularity > BitTorrent::Torrent::MAX_RATIO ? C_INFINITY : Utils::String::fromDouble(popularity, 2));
m_ui->labelPopularityVal->setText(popularity >= BitTorrent::Torrent::MAX_RATIO ? C_INFINITY : Utils::String::fromDouble(popularity, 2));
m_ui->labelSeedsVal->setText(tr("%1 (%2 total)", "%1 and %2 are numbers, e.g. 3 (10 total)")
.arg(QString::number(m_torrent->seedsCount())
@ -471,15 +472,15 @@ void PropertiesWidget::loadDynamicData()
if (m_torrent->hasMetadata())
{
using TorrentPtr = QPointer<BitTorrent::Torrent>;
m_ui->labelTotalPiecesVal->setText(tr("%1 x %2 (have %3)", "(torrent pieces) eg 152 x 4MB (have 25)").arg(m_torrent->piecesCount()).arg(Utils::Misc::friendlyUnit(m_torrent->pieceLength())).arg(m_torrent->piecesHave()));
if (!m_torrent->isFinished() && !m_torrent->isStopped() && !m_torrent->isQueued() && !m_torrent->isChecking())
{
// Pieces availability
showPiecesAvailability(true);
m_torrent->fetchPieceAvailability([this, torrent = TorrentPtr(m_torrent)](const QList<int> &pieceAvailability)
using TorrentPtr = QPointer<BitTorrent::Torrent>;
m_torrent->fetchPieceAvailability().then(this, [this, torrent = TorrentPtr(m_torrent)](const QList<int> &pieceAvailability)
{
if (torrent == m_torrent)
m_piecesAvailability->setAvailability(pieceAvailability);
@ -496,9 +497,8 @@ void PropertiesWidget::loadDynamicData()
qreal progress = m_torrent->progress() * 100.;
m_ui->labelProgressVal->setText(Utils::String::fromDouble(progress, 1) + u'%');
m_torrent->fetchDownloadingPieces([this, torrent = TorrentPtr(m_torrent)](const QBitArray &downloadingPieces)
m_torrent->fetchDownloadingPieces().then(this, [this](const QBitArray &downloadingPieces)
{
if (torrent == m_torrent)
m_downloadedPieces->setProgress(m_torrent->pieces(), downloadingPieces);
});
}
@ -525,7 +525,7 @@ void PropertiesWidget::loadUrlSeeds()
return;
using TorrentPtr = QPointer<BitTorrent::Torrent>;
m_torrent->fetchURLSeeds([this, torrent = TorrentPtr(m_torrent)](const QList<QUrl> &urlSeeds)
m_torrent->fetchURLSeeds().then(this, [this, torrent = TorrentPtr(m_torrent)](const QList<QUrl> &urlSeeds)
{
if (torrent != m_torrent)
return;

View file

@ -631,7 +631,7 @@ void RSSWidget::renderArticle(const RSS::Article *article) const
u"<div style='border: 2px solid red; margin-left: 5px; margin-right: 5px; margin-bottom: 5px;'>" +
u"<div style='background-color: \"%1\"; font-weight: bold; color: \"%2\";'>%3</div>"_s.arg(highlightedBaseColor, highlightedBaseTextColor, article->title());
if (article->date().isValid())
html += u"<div style='background-color: \"%1\";'><b>%2</b>%3</div>"_s.arg(alternateBaseColor, tr("Date: "), QLocale::system().toString(article->date().toLocalTime()));
html += u"<div style='background-color: \"%1\";'><b>%2</b>%3</div>"_s.arg(alternateBaseColor, tr("Date: "), QLocale::system().toString(article->date().toLocalTime(), QLocale::ShortFormat));
if (m_ui->feedListWidget->currentItem() == m_ui->feedListWidget->stickyUnreadItem())
html += u"<div style='background-color: \"%1\";'><b>%2</b>%3</div>"_s.arg(alternateBaseColor, tr("Feed: "), article->feed()->title());
if (!article->author().isEmpty())

View file

@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2022-2024 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2022-2025 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006-2012 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
@ -33,6 +33,7 @@
#include <QFileIconProvider>
#include <QFileInfo>
#include <QFuture>
#include <QIcon>
#include <QMimeData>
#include <QPointer>
@ -219,7 +220,8 @@ void TorrentContentModel::updateFilesAvailability()
Q_ASSERT(m_contentHandler && m_contentHandler->hasMetadata());
using HandlerPtr = QPointer<BitTorrent::TorrentContentHandler>;
m_contentHandler->fetchAvailableFileFractions([this, handler = HandlerPtr(m_contentHandler)](const QList<qreal> &availableFileFractions)
m_contentHandler->fetchAvailableFileFractions().then(this
, [this, handler = HandlerPtr(m_contentHandler)](const QList<qreal> &availableFileFractions)
{
if (handler != m_contentHandler)
return;

View file

@ -47,9 +47,6 @@
<property name="enabled">
<bool>false</bool>
</property>
<property name="maximum">
<double>9998.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>

View file

@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2023-2024 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2023-2025 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
*
* This program is free software; you can redistribute it and/or
@ -42,6 +42,7 @@
#include <QColor>
#include <QDateTime>
#include <QFuture>
#include <QList>
#include <QPointer>
#include <QScopeGuard>
@ -309,7 +310,7 @@ void TrackerListModel::populate()
m_items->emplace_back(std::make_shared<Item>(u"** [LSD] **", privateTorrentMessage));
using TorrentPtr = QPointer<const BitTorrent::Torrent>;
m_torrent->fetchPeerInfo([this, torrent = TorrentPtr(m_torrent)](const QList<BitTorrent::PeerInfo> &peers)
m_torrent->fetchPeerInfo().then(this, [this, torrent = TorrentPtr(m_torrent)](const QList<BitTorrent::PeerInfo> &peers)
{
if (torrent != m_torrent)
return;

View file

@ -293,7 +293,7 @@ QString TransferListModel::displayValue(const BitTorrent::Torrent *torrent, cons
if (hideValues && (value <= 0))
return {};
return ((static_cast<int>(value) == -1) || (value > BitTorrent::Torrent::MAX_RATIO))
return ((static_cast<int>(value) == -1) || (value >= BitTorrent::Torrent::MAX_RATIO))
? C_INFINITY : Utils::String::fromDouble(value, 2);
};

View file

@ -312,10 +312,7 @@ void TransferListWidget::torrentDoubleClicked()
case PREVIEW_FILE:
if (torrentContainsPreviewableFiles(torrent))
{
auto *dialog = new PreviewSelectDialog(this, torrent);
dialog->setAttribute(Qt::WA_DeleteOnClose);
connect(dialog, &PreviewSelectDialog::readyToPreviewFile, this, &TransferListWidget::previewFile);
dialog->show();
openPreviewSelectDialog(torrent);
}
else
{
@ -617,10 +614,7 @@ void TransferListWidget::previewSelectedTorrents()
{
if (torrentContainsPreviewableFiles(torrent))
{
auto *dialog = new PreviewSelectDialog(this, torrent);
dialog->setAttribute(Qt::WA_DeleteOnClose);
connect(dialog, &PreviewSelectDialog::readyToPreviewFile, this, &TransferListWidget::previewFile);
dialog->show();
openPreviewSelectDialog(torrent);
}
else
{
@ -1449,3 +1443,13 @@ void TransferListWidget::wheelEvent(QWheelEvent *event)
QTreeView::wheelEvent(event); // event delegated to base class
}
void TransferListWidget::openPreviewSelectDialog(const BitTorrent::Torrent *torrent)
{
auto *dialog = new PreviewSelectDialog(this, torrent);
dialog->setAttribute(Qt::WA_DeleteOnClose);
// Qt::QueuedConnection is required to prevent a bug on wayland compositors where the preview won't open.
// It occurs when the window focus shifts immediately after TransferListWidget::previewFile has been called.
connect(dialog, &PreviewSelectDialog::readyToPreviewFile, this, &TransferListWidget::previewFile, Qt::QueuedConnection);
dialog->show();
}

View file

@ -123,6 +123,7 @@ private:
void dragMoveEvent(QDragMoveEvent *event) override;
void dropEvent(QDropEvent *event) override;
void wheelEvent(QWheelEvent *event) override;
void openPreviewSelectDialog(const BitTorrent::Torrent *torrent);
QModelIndex mapToSource(const QModelIndex &index) const;
QModelIndexList mapToSource(const QModelIndexList &indexes) const;
QModelIndex mapFromSource(const QModelIndex &index) const;

View file

@ -176,9 +176,7 @@ void Utils::Gui::openFolderSelect(const Path &path)
const int lineMaxLength = 64;
QProcess proc;
#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
proc.setUnixProcessParameters(QProcess::UnixProcessFlag::CloseFileDescriptors);
#endif
proc.start(u"xdg-mime"_s, {u"query"_s, u"default"_s, u"inode/directory"_s});
proc.waitForFinished();
const auto output = QString::fromLocal8Bit(proc.readLine(lineMaxLength).simplified());

View file

@ -96,7 +96,7 @@ QVariantMap serialize(const BitTorrent::Torrent &torrent)
const auto adjustRatio = [](const qreal ratio) -> qreal
{
return (ratio > BitTorrent::Torrent::MAX_RATIO) ? -1 : ratio;
return (ratio >= BitTorrent::Torrent::MAX_RATIO) ? -1 : ratio;
};
const auto getLastActivityTime = [&torrent]() -> qlonglong

View file

@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2018-2024 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2018-2025 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
@ -28,6 +28,7 @@
#include "synccontroller.h"
#include <QFuture>
#include <QJsonArray>
#include <QJsonObject>
#include <QMetaObject>
@ -745,7 +746,7 @@ void SyncController::torrentPeersAction()
QVariantMap data;
QVariantHash peers;
const QList<BitTorrent::PeerInfo> peersList = torrent->peers();
const QList<BitTorrent::PeerInfo> peersList = torrent->fetchPeerInfo().takeResult();
bool resolvePeerCountries = Preferences::instance()->resolvePeerCountries();

View file

@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2018-2023 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2018-2025 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
@ -32,6 +32,7 @@
#include <functional>
#include <QBitArray>
#include <QFuture>
#include <QJsonArray>
#include <QJsonObject>
#include <QList>
@ -180,9 +181,11 @@ namespace
QJsonArray getStickyTrackers(const BitTorrent::Torrent *const torrent)
{
int seedsDHT = 0, seedsPeX = 0, seedsLSD = 0, leechesDHT = 0, leechesPeX = 0, leechesLSD = 0;
for (const BitTorrent::PeerInfo &peer : asConst(torrent->peers()))
const QList<BitTorrent::PeerInfo> peersList = torrent->fetchPeerInfo().takeResult();
for (const BitTorrent::PeerInfo &peer : peersList)
{
if (peer.isConnecting()) continue;
if (peer.isConnecting())
continue;
if (peer.isSeed())
{
@ -520,8 +523,8 @@ void TorrentsController::propertiesAction()
{KEY_PROP_SEEDS_TOTAL, torrent->totalSeedsCount()},
{KEY_PROP_PEERS, torrent->leechsCount()},
{KEY_PROP_PEERS_TOTAL, torrent->totalLeechersCount()},
{KEY_PROP_RATIO, ((ratio > BitTorrent::Torrent::MAX_RATIO) ? -1 : ratio)},
{KEY_PROP_POPULARITY, ((popularity > BitTorrent::Torrent::MAX_RATIO) ? -1 : popularity)},
{KEY_PROP_RATIO, ((ratio >= BitTorrent::Torrent::MAX_RATIO) ? -1 : ratio)},
{KEY_PROP_POPULARITY, ((popularity >= BitTorrent::Torrent::MAX_RATIO) ? -1 : popularity)},
{KEY_PROP_REANNOUNCE, torrent->nextAnnounce()},
{KEY_PROP_TOTAL_SIZE, torrent->totalSize()},
{KEY_PROP_PIECES_NUM, torrent->piecesCount()},
@ -727,7 +730,7 @@ void TorrentsController::filesAction()
{
const QList<BitTorrent::DownloadPriority> priorities = torrent->filePriorities();
const QList<qreal> fp = torrent->filesProgress();
const QList<qreal> fileAvailability = torrent->availableFileFractions();
const QList<qreal> fileAvailability = torrent->fetchAvailableFileFractions().takeResult();
const BitTorrent::TorrentInfo info = torrent->info();
for (const int index : asConst(fileIndexes))
{
@ -796,7 +799,7 @@ void TorrentsController::pieceStatesAction()
for (int i = 0; i < states.size(); ++i)
pieceStates.append(static_cast<int>(states[i]) * 2);
const QBitArray dlstates = torrent->downloadingPieces();
const QBitArray dlstates = torrent->fetchDownloadingPieces().takeResult();
for (int i = 0; i < states.size(); ++i)
{
if (dlstates[i])

View file

@ -34,12 +34,15 @@ export default [
"no-undef": "off",
"no-unused-vars": "off",
"no-var": "error",
"object-shorthand": ["error", "consistent"],
"operator-assignment": "error",
"prefer-arrow-callback": "error",
"prefer-const": "error",
"prefer-template": "error",
"radix": "error",
"require-await": "error",
"PreferArrowFunctions/prefer-arrow-functions": "error",
"Stylistic/no-extra-semi": "error",
"Stylistic/no-mixed-operators": [
"error",
{

View file

@ -26,13 +26,13 @@
if (hash === null)
return;
$("peers").focus();
document.getElementById("peers").focus();
$("addPeersOk").addEventListener("click", (e) => {
document.getElementById("addPeersOk").addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
const peers = $("peers").value.trim().split(/[\r\n]+/);
const peers = document.getElementById("peers").value.trim().split(/[\r\n]+/);
if (peers.length === 0)
return;

View file

@ -22,8 +22,8 @@
}
});
$("trackersUrls").focus();
$("addTrackersButton").addEventListener("click", (e) => {
document.getElementById("trackersUrls").focus();
document.getElementById("addTrackersButton").addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
@ -31,7 +31,7 @@
method: "POST",
body: new URLSearchParams({
hash: new URLSearchParams(window.location.search).get("hash"),
urls: $("trackersUrls").value
urls: document.getElementById("trackersUrls").value
})
})
.then((response) => {

View file

@ -22,15 +22,15 @@
}
});
$("urls").focus();
$("addWebSeedsButton").addEventListener("click", (e) => {
document.getElementById("urls").focus();
document.getElementById("addWebSeedsButton").addEventListener("click", (e) => {
e.stopPropagation();
fetch("api/v2/torrents/addWebSeeds", {
method: "POST",
body: new URLSearchParams({
hash: new URLSearchParams(window.location.search).get("hash"),
urls: $("urls").value.split("\n").map(w => encodeURIComponent(w.trim())).filter(w => (w.length > 0)).join("|")
urls: document.getElementById("urls").value.split("\n").map(w => encodeURIComponent(w.trim())).filter(w => (w.length > 0)).join("|")
})
})
.then((response) => {

View file

@ -13,13 +13,13 @@
"use strict";
window.addEventListener("DOMContentLoaded", () => {
$("cancelBtn").focus();
$("cancelBtn").addEventListener("click", (e) => {
document.getElementById("cancelBtn").focus();
document.getElementById("cancelBtn").addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
window.parent.qBittorrent.Client.closeFrameWindow(window);
});
$("confirmBtn").addEventListener("click", (e) => {
document.getElementById("confirmBtn").addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();

View file

@ -13,13 +13,13 @@
"use strict";
window.addEventListener("DOMContentLoaded", () => {
$("cancelBtn").focus();
$("cancelBtn").addEventListener("click", (e) => {
document.getElementById("cancelBtn").focus();
document.getElementById("cancelBtn").addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
window.parent.qBittorrent.Client.closeFrameWindow(window);
});
$("confirmBtn").addEventListener("click", (e) => {
document.getElementById("confirmBtn").addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();

View file

@ -13,13 +13,13 @@
"use strict";
window.addEventListener("DOMContentLoaded", () => {
$("cancelBtn").focus();
$("cancelBtn").addEventListener("click", (e) => {
document.getElementById("cancelBtn").focus();
document.getElementById("cancelBtn").addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
window.parent.qBittorrent.Client.closeFrameWindow(window);
});
$("confirmBtn").addEventListener("click", (e) => {
document.getElementById("confirmBtn").addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();

View file

@ -16,14 +16,14 @@
const searchParams = new URLSearchParams(window.location.search);
const host = searchParams.get("host");
$("confirmDeleteTrackerText").textContent = "QBT_TR(Are you sure you want to remove tracker %1 from all torrents?)QBT_TR[CONTEXT=TrackersFilterWidget]".replace("%1", host);
document.getElementById("confirmDeleteTrackerText").textContent = "QBT_TR(Are you sure you want to remove tracker %1 from all torrents?)QBT_TR[CONTEXT=TrackersFilterWidget]".replace("%1", host);
$("cancelBtn").focus();
$("cancelBtn").addEventListener("click", (e) => {
document.getElementById("cancelBtn").focus();
document.getElementById("cancelBtn").addEventListener("click", (e) => {
e.stopPropagation();
window.parent.qBittorrent.Client.closeFrameWindow(window);
});
$("confirmBtn").addEventListener("click", (e) => {
document.getElementById("confirmBtn").addEventListener("click", (e) => {
e.stopPropagation();
fetch("api/v2/torrents/removeTrackers", {

View file

@ -167,22 +167,22 @@
if (encodedUrls !== null) {
const urls = encodedUrls.split("|").map(decodeURIComponent);
if (urls.length > 0)
$("urls").value = urls.join("\n");
document.getElementById("urls").value = urls.join("\n");
}
let submitted = false;
$("downloadForm").addEventListener("submit", () => {
$("startTorrentHidden").value = $("startTorrent").checked ? "false" : "true";
document.getElementById("downloadForm").addEventListener("submit", () => {
document.getElementById("startTorrentHidden").value = document.getElementById("startTorrent").checked ? "false" : "true";
$("dlLimitHidden").value = Number($("dlLimitText").value) * 1024;
$("upLimitHidden").value = Number($("upLimitText").value) * 1024;
document.getElementById("dlLimitHidden").value = Number(document.getElementById("dlLimitText").value) * 1024;
document.getElementById("upLimitHidden").value = Number(document.getElementById("upLimitText").value) * 1024;
$("download_spinner").style.display = "block";
document.getElementById("download_spinner").style.display = "block";
submitted = true;
});
$("download_frame").addEventListener("load", () => {
document.getElementById("download_frame").addEventListener("load", () => {
if (submitted)
window.parent.qBittorrent.Client.closeFrameWindow(window);
});

View file

@ -37,7 +37,7 @@
switch (event.key) {
case "Enter":
event.preventDefault();
$("applyButton").click();
document.getElementById("applyButton").click();
break;
case "Escape":
event.preventDefault();
@ -48,7 +48,7 @@
const hashes = new URLSearchParams(window.location.search).get("hashes").split("|");
const setDlLimit = () => {
const limit = Number($("dllimitUpdatevalue").value) * 1024;
const limit = Number(document.getElementById("dllimitUpdatevalue").value) * 1024;
if (hashes[0] === "global") {
fetch("api/v2/transfer/setDownloadLimit", {
method: "POST",
@ -56,7 +56,7 @@
limit: limit
})
})
.then(async (response) => {
.then((response) => {
if (!response.ok)
return;
@ -72,7 +72,7 @@
limit: limit
})
})
.then(async (response) => {
.then((response) => {
if (!response.ok)
return;
@ -81,7 +81,7 @@
}
};
$("dllimitUpdatevalue").focus();
document.getElementById("dllimitUpdatevalue").focus();
MochaUI.addDlLimitSlider(hashes);
</script>

View file

@ -18,7 +18,7 @@
switch (event.key) {
case "Enter":
event.preventDefault();
$("submitButton").click();
document.getElementById("submitButton").click();
break;
case "Escape":
event.preventDefault();
@ -30,16 +30,16 @@
const searchParams = new URLSearchParams(window.location.search);
const currentUrl = searchParams.get("url");
$("url").value = currentUrl;
$("url").focus();
$("url").setSelectionRange(0, currentUrl.length);
document.getElementById("url").value = currentUrl;
document.getElementById("url").focus();
document.getElementById("url").setSelectionRange(0, currentUrl.length);
$("submitButton").addEventListener("click", (e) => {
document.getElementById("submitButton").addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
// check field
const newUrl = $("url").value.trim();
const newUrl = document.getElementById("url").value.trim();
if (newUrl === "") {
alert("QBT_TR(URL cannot be empty)QBT_TR[CONTEXT=RSSWidget]");
return;
@ -50,7 +50,7 @@
return;
}
$("submitButton").disabled = true;
document.getElementById("submitButton").disabled = true;
fetch("api/v2/rss/setFeedURL", {
method: "POST",
@ -64,7 +64,7 @@
alert((response.status === 409)
? await response.text()
: "QBT_TR(Unable to update URL)QBT_TR[CONTEXT=RSSWidget]");
$("submitButton").disabled = false;
document.getElementById("submitButton").disabled = false;
return;
}

View file

@ -17,7 +17,7 @@
switch (event.key) {
case "Enter":
event.preventDefault();
$("editTrackerButton").click();
document.getElementById("editTrackerButton").click();
break;
case "Escape":
event.preventDefault();
@ -31,10 +31,10 @@
if (currentUrl === null)
return;
$("trackerUrl").value = currentUrl;
$("trackerUrl").focus();
document.getElementById("trackerUrl").value = currentUrl;
document.getElementById("trackerUrl").focus();
$("editTrackerButton").addEventListener("click", (e) => {
document.getElementById("editTrackerButton").addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
@ -43,7 +43,7 @@
body: new URLSearchParams({
hash: searchParams.get("hash"),
origUrl: currentUrl,
newUrl: $("trackerUrl").value
newUrl: document.getElementById("trackerUrl").value
})
})
.then((response) => {

View file

@ -17,7 +17,7 @@
switch (event.key) {
case "Enter":
event.preventDefault();
$("editWebSeedButton").click();
document.getElementById("editWebSeedButton").click();
break;
case "Escape":
event.preventDefault();
@ -28,10 +28,10 @@
const searchParams = new URLSearchParams(window.location.search);
const origUrl = searchParams.get("url");
$("url").value = decodeURIComponent(origUrl);
$("url").focus();
document.getElementById("url").value = decodeURIComponent(origUrl);
document.getElementById("url").focus();
$("editWebSeedButton").addEventListener("click", (e) => {
document.getElementById("editWebSeedButton").addEventListener("click", (e) => {
e.stopPropagation();
fetch("api/v2/torrents/editWebSeed", {
@ -39,7 +39,7 @@
body: new URLSearchParams({
hash: searchParams.get("hash"),
origUrl: origUrl,
newUrl: encodeURIComponent($("url").value.trim())
newUrl: encodeURIComponent(document.getElementById("url").value.trim())
})
})
.then((response) => {

View file

@ -19,7 +19,7 @@
switch (event.key) {
case "Enter":
event.preventDefault();
$("categoryNameButton").click();
document.getElementById("categoryNameButton").click();
break;
case "Escape":
event.preventDefault();
@ -38,25 +38,25 @@
if (!uriCategoryName)
return;
$("categoryName").disabled = true;
$("categoryName").value = window.qBittorrent.Misc.escapeHtml(uriCategoryName);
$("savePath").value = window.qBittorrent.Misc.escapeHtml(uriSavePath);
$("savePath").focus();
document.getElementById("categoryName").disabled = true;
document.getElementById("categoryName").value = window.qBittorrent.Misc.escapeHtml(uriCategoryName);
document.getElementById("savePath").value = window.qBittorrent.Misc.escapeHtml(uriSavePath);
document.getElementById("savePath").focus();
}
else if (uriAction === "createSubcategory") {
$("categoryName").value = window.qBittorrent.Misc.escapeHtml(uriCategoryName);
$("categoryName").focus();
document.getElementById("categoryName").value = window.qBittorrent.Misc.escapeHtml(uriCategoryName);
document.getElementById("categoryName").focus();
}
else {
$("categoryName").focus();
document.getElementById("categoryName").focus();
}
$("categoryNameButton").addEventListener("click", (e) => {
document.getElementById("categoryNameButton").addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
const savePath = $("savePath").value.trim();
const categoryName = $("categoryName").value.trim();
const savePath = document.getElementById("savePath").value.trim();
const categoryName = document.getElementById("categoryName").value.trim();
const verifyCategoryName = (name) => {
if ((name === null) || (name === ""))

View file

@ -18,7 +18,7 @@
switch (event.key) {
case "Enter":
event.preventDefault();
$("submitButton").click();
document.getElementById("submitButton").click();
break;
case "Escape":
event.preventDefault();
@ -27,19 +27,19 @@
}
});
$("feedURL").focus();
$("submitButton").addEventListener("click", (e) => {
document.getElementById("feedURL").focus();
document.getElementById("submitButton").addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
// check field
const feedURL = $("feedURL").value.trim();
const feedURL = document.getElementById("feedURL").value.trim();
if (feedURL === "") {
alert("QBT_TR(Name cannot be empty)QBT_TR[CONTEXT=HttpServer]");
return;
}
$("submitButton").disabled = true;
document.getElementById("submitButton").disabled = true;
const path = new URLSearchParams(window.location.search).get("path");
fetch("api/v2/rss/addFeed", {
@ -53,7 +53,7 @@
if (!response.ok) {
if (response.status === 409)
alert(await response.text());
$("submitButton").disabled = false;
document.getElementById("submitButton").disabled = false;
return;
}

View file

@ -19,7 +19,7 @@
switch (event.key) {
case "Enter":
event.preventDefault();
$("submitButton").click();
document.getElementById("submitButton").click();
break;
case "Escape":
event.preventDefault();
@ -28,19 +28,19 @@
}
});
$("folderName").focus();
$("submitButton").addEventListener("click", (e) => {
document.getElementById("folderName").focus();
document.getElementById("submitButton").addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
// check field
const folderName = $("folderName").value.trim();
const folderName = document.getElementById("folderName").value.trim();
if (folderName === "") {
alert("QBT_TR(Name cannot be empty)QBT_TR[CONTEXT=HttpServer]");
return;
}
$("submitButton").disabled = true;
document.getElementById("submitButton").disabled = true;
const path = new URLSearchParams(window.location.search).get("path");
fetch("api/v2/rss/addFolder", {
@ -53,7 +53,7 @@
if (!response.ok) {
if (response.status === 409)
alert(await response.text());
$("submitButton").disabled = false;
document.getElementById("submitButton").disabled = false;
return;
}

View file

@ -18,7 +18,7 @@
switch (event.key) {
case "Enter":
event.preventDefault();
$("submitButton").click();
document.getElementById("submitButton").click();
break;
case "Escape":
event.preventDefault();
@ -27,18 +27,18 @@
}
});
$("name").focus();
$("submitButton").addEventListener("click", (e) => {
document.getElementById("name").focus();
document.getElementById("submitButton").addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
// check field
const name = $("name").value.trim();
const name = document.getElementById("name").value.trim();
if (name === "") {
alert("QBT_TR(Name cannot be empty)QBT_TR[CONTEXT=HttpServer]");
return;
}
$("submitButton").disabled = true;
document.getElementById("submitButton").disabled = true;
fetch("api/v2/rss/setRule", {
method: "POST",

View file

@ -18,7 +18,7 @@
switch (event.key) {
case "Enter":
event.preventDefault();
$("tagNameButton").click();
document.getElementById("tagNameButton").click();
break;
case "Escape":
event.preventDefault();
@ -31,15 +31,15 @@
const uriAction = window.qBittorrent.Misc.safeTrim(searchParams.get("action"));
if (uriAction === "create")
$("legendText").textContent = "QBT_TR(Tag:)QBT_TR[CONTEXT=TagFilterWidget]";
document.getElementById("legendText").textContent = "QBT_TR(Tag:)QBT_TR[CONTEXT=TagFilterWidget]";
$("tagName").focus();
document.getElementById("tagName").focus();
$("tagNameButton").addEventListener("click", (e) => {
document.getElementById("tagNameButton").addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
const tagName = $("tagName").value.trim();
const tagName = document.getElementById("tagName").value.trim();
const verifyTagName = (name) => {
if ((name === null) || (name === ""))
@ -64,7 +64,7 @@
tags: tagName
})
})
.then(async (response) => {
.then((response) => {
if (!response.ok)
return;
@ -83,7 +83,7 @@
tags: tagName
})
})
.then(async (response) => {
.then((response) => {
if (!response.ok)
return;

View file

@ -18,7 +18,7 @@
switch (event.key) {
case "Enter":
event.preventDefault();
$("renameButton").click();
document.getElementById("renameButton").click();
break;
case "Escape":
event.preventDefault();
@ -31,15 +31,15 @@
const name = searchParams.get("name");
// set text field to current value
if (name !== null)
$("rename").value = name;
document.getElementById("rename").value = name;
$("rename").focus();
$("renameButton").addEventListener("click", (e) => {
document.getElementById("rename").focus();
document.getElementById("renameButton").addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
// check field
const name = $("rename").value.trim();
const name = document.getElementById("rename").value.trim();
if ((name === null) || (name === ""))
return;

View file

@ -18,7 +18,7 @@
switch (event.key) {
case "Enter":
event.preventDefault();
$("renameButton").click();
document.getElementById("renameButton").click();
break;
case "Escape":
event.preventDefault();
@ -29,16 +29,16 @@
const oldPath = new URLSearchParams(window.location.search).get("oldPath");
$("rename").value = oldPath;
$("rename").focus();
$("rename").setSelectionRange(0, oldPath.length);
document.getElementById("rename").value = oldPath;
document.getElementById("rename").focus();
document.getElementById("rename").setSelectionRange(0, oldPath.length);
$("renameButton").addEventListener("click", (e) => {
document.getElementById("renameButton").addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
// check field
const newPath = $("rename").value.trim();
const newPath = document.getElementById("rename").value.trim();
if (newPath === "") {
alert("QBT_TR(Name cannot be empty)QBT_TR[CONTEXT=HttpServer]");
return;
@ -49,7 +49,7 @@
return;
}
$("renameButton").disabled = true;
document.getElementById("renameButton").disabled = true;
fetch("api/v2/rss/moveItem", {
method: "POST",
@ -62,7 +62,7 @@
if (!response.ok) {
if (response.status === 409)
alert(await response.text());
$("renameButton").disabled = false;
document.getElementById("renameButton").disabled = false;
return;
}

View file

@ -19,7 +19,7 @@
switch (event.key) {
case "Enter":
event.preventDefault();
$("renameButton").click();
document.getElementById("renameButton").click();
break;
case "Escape":
event.preventDefault();
@ -34,17 +34,17 @@
const isFolder = ((searchParams.get("isFolder")) === "true");
const oldName = window.qBittorrent.Filesystem.fileName(oldPath);
$("rename").value = oldName;
$("rename").focus();
document.getElementById("rename").value = oldName;
document.getElementById("rename").focus();
if (!isFolder)
$("rename").setSelectionRange(0, oldName.lastIndexOf("."));
document.getElementById("rename").setSelectionRange(0, oldName.lastIndexOf("."));
$("renameButton").addEventListener("click", (e) => {
document.getElementById("renameButton").addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
// check field
const newName = $("rename").value.trim();
const newName = document.getElementById("rename").value.trim();
if (newName === "") {
alert("QBT_TR(Name cannot be empty)QBT_TR[CONTEXT=HttpServer]");
return;
@ -55,7 +55,7 @@
return;
}
$("renameButton").disabled = true;
document.getElementById("renameButton").disabled = true;
const parentPath = window.qBittorrent.Filesystem.folderName(oldPath);
const newPath = parentPath
@ -72,7 +72,7 @@
.then((response) => {
if (!response.ok) {
alert("QBT_TR(Failed to update name)QBT_TR[CONTEXT=HttpServer]");
$("renameButton").disabled = false;
document.getElementById("renameButton").disabled = false;
return;
}

View file

@ -80,50 +80,50 @@
// Load Multi Rename Preferences
const multiRenamePrefChecked = LocalPreferences.get("multirename_rememberPreferences", "true") === "true";
$("multirename_rememberprefs_checkbox").checked = multiRenamePrefChecked;
document.getElementById("multirename_rememberprefs_checkbox").checked = multiRenamePrefChecked;
if (multiRenamePrefChecked) {
const multirename_search = LocalPreferences.get("multirename_search", "");
fileRenamer.setSearch(multirename_search);
$("multiRenameSearch").value = multirename_search;
document.getElementById("multiRenameSearch").value = multirename_search;
const multirename_useRegex = LocalPreferences.get("multirename_useRegex", false);
fileRenamer.useRegex = multirename_useRegex === "true";
$("use_regex_search").checked = fileRenamer.useRegex;
document.getElementById("use_regex_search").checked = fileRenamer.useRegex;
const multirename_matchAllOccurrences = LocalPreferences.get("multirename_matchAllOccurrences", false);
fileRenamer.matchAllOccurrences = multirename_matchAllOccurrences === "true";
$("match_all_occurrences").checked = fileRenamer.matchAllOccurrences;
document.getElementById("match_all_occurrences").checked = fileRenamer.matchAllOccurrences;
const multirename_caseSensitive = LocalPreferences.get("multirename_caseSensitive", false);
fileRenamer.caseSensitive = multirename_caseSensitive === "true";
$("case_sensitive").checked = fileRenamer.caseSensitive;
document.getElementById("case_sensitive").checked = fileRenamer.caseSensitive;
const multirename_replace = LocalPreferences.get("multirename_replace", "");
fileRenamer.setReplacement(multirename_replace);
$("multiRenameReplace").value = multirename_replace;
document.getElementById("multiRenameReplace").value = multirename_replace;
const multirename_appliesTo = LocalPreferences.get("multirename_appliesTo", window.qBittorrent.MultiRename.AppliesTo.FilenameExtension);
fileRenamer.appliesTo = window.qBittorrent.MultiRename.AppliesTo[multirename_appliesTo];
$("applies_to_option").value = fileRenamer.appliesTo;
document.getElementById("applies_to_option").value = fileRenamer.appliesTo;
const multirename_includeFiles = LocalPreferences.get("multirename_includeFiles", true);
fileRenamer.includeFiles = multirename_includeFiles === "true";
$("include_files").checked = fileRenamer.includeFiles;
document.getElementById("include_files").checked = fileRenamer.includeFiles;
const multirename_includeFolders = LocalPreferences.get("multirename_includeFolders", false);
fileRenamer.includeFolders = multirename_includeFolders === "true";
$("include_folders").checked = fileRenamer.includeFolders;
document.getElementById("include_folders").checked = fileRenamer.includeFolders;
const multirename_fileEnumerationStart = LocalPreferences.get("multirename_fileEnumerationStart", 0);
fileRenamer.fileEnumerationStart = Number(multirename_fileEnumerationStart);
$("file_counter").value = fileRenamer.fileEnumerationStart;
document.getElementById("file_counter").value = fileRenamer.fileEnumerationStart;
const multirename_replaceAll = LocalPreferences.get("multirename_replaceAll", false);
fileRenamer.replaceAll = multirename_replaceAll === "true";
const renameButtonValue = fileRenamer.replaceAll ? "Replace All" : "Replace";
$("renameOptions").value = renameButtonValue;
$("renameButton").value = renameButtonValue;
document.getElementById("renameOptions").value = renameButtonValue;
document.getElementById("renameButton").value = renameButtonValue;
}
// Fires every time a row's selection changes
@ -133,26 +133,26 @@
};
// Setup Search Events that control renaming
$("multiRenameSearch").addEventListener("input", (e) => {
document.getElementById("multiRenameSearch").addEventListener("input", (e) => {
const sanitized = e.target.value.replace(/\n/g, "");
$("multiRenameSearch").value = sanitized;
document.getElementById("multiRenameSearch").value = sanitized;
// Search input has changed
$("multiRenameSearch").style["border-color"] = "";
document.getElementById("multiRenameSearch").style["border-color"] = "";
LocalPreferences.set("multirename_search", sanitized);
fileRenamer.setSearch(sanitized);
});
$("use_regex_search").addEventListener("change", (e) => {
document.getElementById("use_regex_search").addEventListener("change", (e) => {
fileRenamer.useRegex = e.target.checked;
LocalPreferences.set("multirename_useRegex", e.target.checked);
fileRenamer.update();
});
$("match_all_occurrences").addEventListener("change", (e) => {
document.getElementById("match_all_occurrences").addEventListener("change", (e) => {
fileRenamer.matchAllOccurrences = e.target.checked;
LocalPreferences.set("multirename_matchAllOccurrences", e.target.checked);
fileRenamer.update();
});
$("case_sensitive").addEventListener("change", (e) => {
document.getElementById("case_sensitive").addEventListener("change", (e) => {
fileRenamer.caseSensitive = e.target.checked;
LocalPreferences.set("multirename_caseSensitive", e.target.checked);
fileRenamer.update();
@ -179,35 +179,35 @@
}
};
fileRenamer.onInvalidRegex = (err) => {
$("multiRenameSearch").style["border-color"] = "#CC0033";
document.getElementById("multiRenameSearch").style["border-color"] = "#CC0033";
};
// Setup Replace Events that control renaming
$("multiRenameReplace").addEventListener("input", (e) => {
document.getElementById("multiRenameReplace").addEventListener("input", (e) => {
const sanitized = e.target.value.replace(/\n/g, "");
$("multiRenameReplace").value = sanitized;
document.getElementById("multiRenameReplace").value = sanitized;
// Replace input has changed
$("multiRenameReplace").style["border-color"] = "";
document.getElementById("multiRenameReplace").style["border-color"] = "";
LocalPreferences.set("multirename_replace", sanitized);
fileRenamer.setReplacement(sanitized);
});
$("applies_to_option").addEventListener("change", (e) => {
document.getElementById("applies_to_option").addEventListener("change", (e) => {
fileRenamer.appliesTo = e.target.value;
LocalPreferences.set("multirename_appliesTo", e.target.value);
fileRenamer.update();
});
$("include_files").addEventListener("change", (e) => {
document.getElementById("include_files").addEventListener("change", (e) => {
fileRenamer.includeFiles = e.target.checked;
LocalPreferences.set("multirename_includeFiles", e.target.checked);
fileRenamer.update();
});
$("include_folders").addEventListener("change", (e) => {
document.getElementById("include_folders").addEventListener("change", (e) => {
fileRenamer.includeFolders = e.target.checked;
LocalPreferences.set("multirename_includeFolders", e.target.checked);
fileRenamer.update();
});
$("file_counter").addEventListener("input", (e) => {
document.getElementById("file_counter").addEventListener("input", (e) => {
let value = e.target.valueAsNumber;
if (!value)
value = 0;
@ -216,46 +216,46 @@
if (value > 99999999)
value = 99999999;
fileRenamer.fileEnumerationStart = value;
$("file_counter").value = value;
document.getElementById("file_counter").value = value;
LocalPreferences.set("multirename_fileEnumerationStart", value);
fileRenamer.update();
});
// Setup Rename Operation Events
$("renameButton").addEventListener("click", (e) => {
document.getElementById("renameButton").addEventListener("click", (e) => {
// Disable Search Options
$("multiRenameSearch").disabled = true;
$("use_regex_search").disabled = true;
$("match_all_occurrences").disabled = true;
$("case_sensitive").disabled = true;
document.getElementById("multiRenameSearch").disabled = true;
document.getElementById("use_regex_search").disabled = true;
document.getElementById("match_all_occurrences").disabled = true;
document.getElementById("case_sensitive").disabled = true;
// Disable Replace Options
$("multiRenameReplace").disabled = true;
$("applies_to_option").disabled = true;
$("include_files").disabled = true;
$("include_folders").disabled = true;
$("file_counter").disabled = true;
document.getElementById("multiRenameReplace").disabled = true;
document.getElementById("applies_to_option").disabled = true;
document.getElementById("include_files").disabled = true;
document.getElementById("include_folders").disabled = true;
document.getElementById("file_counter").disabled = true;
// Disable Rename Buttons
$("renameButton").disabled = true;
$("renameOptions").disabled = true;
document.getElementById("renameButton").disabled = true;
document.getElementById("renameOptions").disabled = true;
// Clear error text
$("rename_error").textContent = "";
document.getElementById("rename_error").textContent = "";
fileRenamer.rename();
});
fileRenamer.onRenamed = (rows) => {
// Disable Search Options
$("multiRenameSearch").disabled = false;
$("use_regex_search").disabled = false;
$("match_all_occurrences").disabled = false;
$("case_sensitive").disabled = false;
document.getElementById("multiRenameSearch").disabled = false;
document.getElementById("use_regex_search").disabled = false;
document.getElementById("match_all_occurrences").disabled = false;
document.getElementById("case_sensitive").disabled = false;
// Disable Replace Options
$("multiRenameReplace").disabled = false;
$("applies_to_option").disabled = false;
$("include_files").disabled = false;
$("include_folders").disabled = false;
$("file_counter").disabled = false;
document.getElementById("multiRenameReplace").disabled = false;
document.getElementById("applies_to_option").disabled = false;
document.getElementById("include_files").disabled = false;
document.getElementById("include_folders").disabled = false;
document.getElementById("file_counter").disabled = false;
// Disable Rename Buttons
$("renameButton").disabled = false;
$("renameOptions").disabled = false;
document.getElementById("renameButton").disabled = false;
document.getElementById("renameOptions").disabled = false;
// Recreate table
let selectedRows = bulkRenameFilesTable.getSelectedRows().map(row => row.rowId.toString());
@ -266,15 +266,15 @@
// Adjust file enumeration count by 1 when replacing single files to prevent naming conflicts
if (!fileRenamer.replaceAll) {
fileRenamer.fileEnumerationStart++;
$("file_counter").value = fileRenamer.fileEnumerationStart;
document.getElementById("file_counter").value = fileRenamer.fileEnumerationStart;
}
setupTable(selectedRows);
};
fileRenamer.onRenameError = (response, row) => {
if (response.status === 409)
$("rename_error").textContent = `QBT_TR(Rename failed: file or folder already exists)QBT_TR[CONTEXT=PropertiesWidget] \`${row.renamed}\``;
document.getElementById("rename_error").textContent = `QBT_TR(Rename failed: file or folder already exists)QBT_TR[CONTEXT=PropertiesWidget] \`${row.renamed}\``;
};
$("renameOptions").addEventListener("change", (e) => {
document.getElementById("renameOptions").addEventListener("change", (e) => {
const combobox = e.target;
const replaceOperation = combobox.value;
if (replaceOperation === "Replace")
@ -284,9 +284,9 @@
else
fileRenamer.replaceAll = false;
LocalPreferences.set("multirename_replaceAll", fileRenamer.replaceAll);
$("renameButton").value = replaceOperation;
document.getElementById("renameButton").value = replaceOperation;
});
$("closeButton").addEventListener("click", (event) => {
document.getElementById("closeButton").addEventListener("click", (event) => {
event.preventDefault();
window.qBittorrent.Client.closeWindow(windowEl);
});

View file

@ -18,7 +18,7 @@
switch (event.key) {
case "Enter":
event.preventDefault();
$("renameButton").click();
document.getElementById("renameButton").click();
break;
case "Escape":
event.preventDefault();
@ -29,16 +29,16 @@
const oldName = new URLSearchParams(window.location.search).get("rule");
$("rename").value = oldName;
$("rename").focus();
$("rename").setSelectionRange(0, oldName.length);
document.getElementById("rename").value = oldName;
document.getElementById("rename").focus();
document.getElementById("rename").setSelectionRange(0, oldName.length);
$("renameButton").addEventListener("click", (e) => {
document.getElementById("renameButton").addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
// check field
const newName = $("rename").value.trim();
const newName = document.getElementById("rename").value.trim();
if (newName === "") {
alert("QBT_TR(Name cannot be empty)QBT_TR[CONTEXT=HttpServer]");
return;
@ -49,7 +49,7 @@
return;
}
$("renameButton").disabled = true;
document.getElementById("renameButton").disabled = true;
fetch("api/v2/rss/renameRule", {
method: "POST",

View file

@ -53,7 +53,7 @@ window.qBittorrent.Cache ??= (() => {
class BuildInfoCache {
#m_store = {};
async init() {
init() {
return fetch("api/v2/app/buildInfo", {
method: "GET",
cache: "no-store"
@ -80,7 +80,7 @@ window.qBittorrent.Cache ??= (() => {
// onFailure: () => {},
// onSuccess: () => {}
// }
async init(obj = {}) {
init(obj = {}) {
return fetch("api/v2/app/preferences", {
method: "GET",
cache: "no-store"
@ -153,7 +153,7 @@ window.qBittorrent.Cache ??= (() => {
class QbtVersionCache {
#m_store = "";
async init() {
init() {
return fetch("api/v2/app/version", {
method: "GET",
cache: "no-store"

View file

@ -180,15 +180,15 @@ window.addEventListener("DOMContentLoaded", () => {
let isRssPanelLoaded = false;
const saveColumnSizes = () => {
const filters_width = $("Filters").getSize().x;
const filters_width = document.getElementById("Filters").getSize().x;
LocalPreferences.set("filters_width", filters_width);
const properties_height_rel = $("propertiesPanel").getSize().y / Window.getSize().y;
const properties_height_rel = document.getElementById("propertiesPanel").getSize().y / Window.getSize().y;
LocalPreferences.set("properties_height_rel", properties_height_rel);
};
window.addEventListener("resize", window.qBittorrent.Misc.createDebounceHandler(500, (e) => {
// only save sizes if the columns are visible
if (!$("mainColumn").classList.contains("invisible"))
if (!document.getElementById("mainColumn").classList.contains("invisible"))
saveColumnSizes();
}));
@ -221,7 +221,7 @@ window.addEventListener("DOMContentLoaded", () => {
});
// start off hidden
$("searchTabColumn").classList.add("invisible");
document.getElementById("searchTabColumn").classList.add("invisible");
};
const buildRssTab = () => {
@ -232,7 +232,7 @@ window.addEventListener("DOMContentLoaded", () => {
});
// start off hidden
$("rssTabColumn").classList.add("invisible");
document.getElementById("rssTabColumn").classList.add("invisible");
};
const buildLogTab = () => {
@ -243,7 +243,7 @@ window.addEventListener("DOMContentLoaded", () => {
});
// start off hidden
$("logTabColumn").classList.add("invisible");
document.getElementById("logTabColumn").classList.add("invisible");
};
buildTransfersTab();
@ -342,28 +342,28 @@ window.addEventListener("DOMContentLoaded", () => {
// Show Top Toolbar is enabled by default
let showTopToolbar = LocalPreferences.get("show_top_toolbar", "true") === "true";
if (!showTopToolbar) {
$("showTopToolbarLink").firstElementChild.style.opacity = "0";
$("mochaToolbar").classList.add("invisible");
document.getElementById("showTopToolbarLink").firstElementChild.style.opacity = "0";
document.getElementById("mochaToolbar").classList.add("invisible");
}
// Show Status Bar is enabled by default
let showStatusBar = LocalPreferences.get("show_status_bar", "true") === "true";
if (!showStatusBar) {
$("showStatusBarLink").firstElementChild.style.opacity = "0";
$("desktopFooterWrapper").classList.add("invisible");
document.getElementById("showStatusBarLink").firstElementChild.style.opacity = "0";
document.getElementById("desktopFooterWrapper").classList.add("invisible");
}
// Show Filters Sidebar is enabled by default
let showFiltersSidebar = LocalPreferences.get("show_filters_sidebar", "true") === "true";
if (!showFiltersSidebar) {
$("showFiltersSidebarLink").firstElementChild.style.opacity = "0";
$("filtersColumn").classList.add("invisible");
$("filtersColumn_handle").classList.add("invisible");
document.getElementById("showFiltersSidebarLink").firstElementChild.style.opacity = "0";
document.getElementById("filtersColumn").classList.add("invisible");
document.getElementById("filtersColumn_handle").classList.add("invisible");
}
let speedInTitle = LocalPreferences.get("speed_in_browser_title_bar") === "true";
if (!speedInTitle)
$("speedInBrowserTitleBarLink").firstElementChild.style.opacity = "0";
document.getElementById("speedInBrowserTitleBarLink").firstElementChild.style.opacity = "0";
// After showing/hiding the toolbar + status bar
window.qBittorrent.Client.showSearchEngine(LocalPreferences.get("show_search_engine") !== "false");
@ -614,7 +614,7 @@ window.addEventListener("DOMContentLoaded", () => {
};
const updateTagList = () => {
const tagFilterList = $("tagFilterList");
const tagFilterList = document.getElementById("tagFilterList");
if (tagFilterList === null)
return;
@ -667,7 +667,7 @@ window.addEventListener("DOMContentLoaded", () => {
};
const updateTrackerList = () => {
const trackerFilterList = $("trackerFilterList");
const trackerFilterList = document.getElementById("trackerFilterList");
if (trackerFilterList === null)
return;
@ -763,7 +763,7 @@ window.addEventListener("DOMContentLoaded", () => {
})
.then(async (response) => {
if (response.ok) {
$("error_div").textContent = "";
document.getElementById("error_div").textContent = "";
const responseJSON = await response.json();
@ -933,7 +933,7 @@ window.addEventListener("DOMContentLoaded", () => {
syncData(window.qBittorrent.Client.getSyncMainDataInterval());
},
(error) => {
const errorDiv = $("error_div");
const errorDiv = document.getElementById("error_div");
if (errorDiv)
errorDiv.textContent = "QBT_TR(qBittorrent client is not reachable)QBT_TR[CONTEXT=HttpServer]";
syncRequestInProgress = false;
@ -964,12 +964,12 @@ window.addEventListener("DOMContentLoaded", () => {
if (serverState.dl_rate_limit > 0)
transfer_info += ` [${window.qBittorrent.Misc.friendlyUnit(serverState.dl_rate_limit, true)}]`;
transfer_info += ` (${window.qBittorrent.Misc.friendlyUnit(serverState.dl_info_data, false)})`;
$("DlInfos").textContent = transfer_info;
document.getElementById("DlInfos").textContent = transfer_info;
transfer_info = window.qBittorrent.Misc.friendlyUnit(serverState.up_info_speed, true);
if (serverState.up_rate_limit > 0)
transfer_info += ` [${window.qBittorrent.Misc.friendlyUnit(serverState.up_rate_limit, true)}]`;
transfer_info += ` (${window.qBittorrent.Misc.friendlyUnit(serverState.up_info_data, false)})`;
$("UpInfos").textContent = transfer_info;
document.getElementById("UpInfos").textContent = transfer_info;
document.title = (speedInTitle
? (`QBT_TR([D: %1, U: %2])QBT_TR[CONTEXT=MainWindow] `
@ -978,7 +978,7 @@ window.addEventListener("DOMContentLoaded", () => {
: "")
+ window.qBittorrent.Client.mainTitle();
$("freeSpaceOnDisk").textContent = "QBT_TR(Free space: %1)QBT_TR[CONTEXT=HttpServer]".replace("%1", window.qBittorrent.Misc.friendlyUnit(serverState.free_space_on_disk));
document.getElementById("freeSpaceOnDisk").textContent = "QBT_TR(Free space: %1)QBT_TR[CONTEXT=HttpServer]".replace("%1", window.qBittorrent.Misc.friendlyUnit(serverState.free_space_on_disk));
const externalIPsElement = document.getElementById("externalIPs");
if (window.qBittorrent.Cache.preferences.get().status_bar_external_ip) {
@ -1015,35 +1015,35 @@ window.addEventListener("DOMContentLoaded", () => {
// Statistics dialog
if (document.getElementById("statisticsContent")) {
$("AlltimeDL").textContent = window.qBittorrent.Misc.friendlyUnit(serverState.alltime_dl, false);
$("AlltimeUL").textContent = window.qBittorrent.Misc.friendlyUnit(serverState.alltime_ul, false);
$("TotalWastedSession").textContent = window.qBittorrent.Misc.friendlyUnit(serverState.total_wasted_session, false);
$("GlobalRatio").textContent = serverState.global_ratio;
$("TotalPeerConnections").textContent = serverState.total_peer_connections;
$("ReadCacheHits").textContent = `${serverState.read_cache_hits}%`;
$("TotalBuffersSize").textContent = window.qBittorrent.Misc.friendlyUnit(serverState.total_buffers_size, false);
$("WriteCacheOverload").textContent = `${serverState.write_cache_overload}%`;
$("ReadCacheOverload").textContent = `${serverState.read_cache_overload}%`;
$("QueuedIOJobs").textContent = serverState.queued_io_jobs;
$("AverageTimeInQueue").textContent = `${serverState.average_time_queue} ms`;
$("TotalQueuedSize").textContent = window.qBittorrent.Misc.friendlyUnit(serverState.total_queued_size, false);
document.getElementById("AlltimeDL").textContent = window.qBittorrent.Misc.friendlyUnit(serverState.alltime_dl, false);
document.getElementById("AlltimeUL").textContent = window.qBittorrent.Misc.friendlyUnit(serverState.alltime_ul, false);
document.getElementById("TotalWastedSession").textContent = window.qBittorrent.Misc.friendlyUnit(serverState.total_wasted_session, false);
document.getElementById("GlobalRatio").textContent = serverState.global_ratio;
document.getElementById("TotalPeerConnections").textContent = serverState.total_peer_connections;
document.getElementById("ReadCacheHits").textContent = `${serverState.read_cache_hits}%`;
document.getElementById("TotalBuffersSize").textContent = window.qBittorrent.Misc.friendlyUnit(serverState.total_buffers_size, false);
document.getElementById("WriteCacheOverload").textContent = `${serverState.write_cache_overload}%`;
document.getElementById("ReadCacheOverload").textContent = `${serverState.read_cache_overload}%`;
document.getElementById("QueuedIOJobs").textContent = serverState.queued_io_jobs;
document.getElementById("AverageTimeInQueue").textContent = `${serverState.average_time_queue} ms`;
document.getElementById("TotalQueuedSize").textContent = window.qBittorrent.Misc.friendlyUnit(serverState.total_queued_size, false);
}
switch (serverState.connection_status) {
case "connected":
$("connectionStatus").src = "images/connected.svg";
$("connectionStatus").alt = "QBT_TR(Connection status: Connected)QBT_TR[CONTEXT=MainWindow]";
$("connectionStatus").title = "QBT_TR(Connection status: Connected)QBT_TR[CONTEXT=MainWindow]";
document.getElementById("connectionStatus").src = "images/connected.svg";
document.getElementById("connectionStatus").alt = "QBT_TR(Connection status: Connected)QBT_TR[CONTEXT=MainWindow]";
document.getElementById("connectionStatus").title = "QBT_TR(Connection status: Connected)QBT_TR[CONTEXT=MainWindow]";
break;
case "firewalled":
$("connectionStatus").src = "images/firewalled.svg";
$("connectionStatus").alt = "QBT_TR(Connection status: Firewalled)QBT_TR[CONTEXT=MainWindow]";
$("connectionStatus").title = "QBT_TR(Connection status: Firewalled)QBT_TR[CONTEXT=MainWindow]";
document.getElementById("connectionStatus").src = "images/firewalled.svg";
document.getElementById("connectionStatus").alt = "QBT_TR(Connection status: Firewalled)QBT_TR[CONTEXT=MainWindow]";
document.getElementById("connectionStatus").title = "QBT_TR(Connection status: Firewalled)QBT_TR[CONTEXT=MainWindow]";
break;
default:
$("connectionStatus").src = "images/disconnected.svg";
$("connectionStatus").alt = "QBT_TR(Connection status: Disconnected)QBT_TR[CONTEXT=MainWindow]";
$("connectionStatus").title = "QBT_TR(Connection status: Disconnected)QBT_TR[CONTEXT=MainWindow]";
document.getElementById("connectionStatus").src = "images/disconnected.svg";
document.getElementById("connectionStatus").alt = "QBT_TR(Connection status: Disconnected)QBT_TR[CONTEXT=MainWindow]";
document.getElementById("connectionStatus").title = "QBT_TR(Connection status: Disconnected)QBT_TR[CONTEXT=MainWindow]";
break;
}
@ -1052,20 +1052,20 @@ window.addEventListener("DOMContentLoaded", () => {
torrentsTable.columns["priority"].force_hide = !queueing_enabled;
torrentsTable.updateColumn("priority");
if (queueing_enabled) {
$("topQueuePosItem").classList.remove("invisible");
$("increaseQueuePosItem").classList.remove("invisible");
$("decreaseQueuePosItem").classList.remove("invisible");
$("bottomQueuePosItem").classList.remove("invisible");
$("queueingButtons").classList.remove("invisible");
$("queueingMenuItems").classList.remove("invisible");
document.getElementById("topQueuePosItem").classList.remove("invisible");
document.getElementById("increaseQueuePosItem").classList.remove("invisible");
document.getElementById("decreaseQueuePosItem").classList.remove("invisible");
document.getElementById("bottomQueuePosItem").classList.remove("invisible");
document.getElementById("queueingButtons").classList.remove("invisible");
document.getElementById("queueingMenuItems").classList.remove("invisible");
}
else {
$("topQueuePosItem").classList.add("invisible");
$("increaseQueuePosItem").classList.add("invisible");
$("decreaseQueuePosItem").classList.add("invisible");
$("bottomQueuePosItem").classList.add("invisible");
$("queueingButtons").classList.add("invisible");
$("queueingMenuItems").classList.add("invisible");
document.getElementById("topQueuePosItem").classList.add("invisible");
document.getElementById("increaseQueuePosItem").classList.add("invisible");
document.getElementById("decreaseQueuePosItem").classList.add("invisible");
document.getElementById("bottomQueuePosItem").classList.add("invisible");
document.getElementById("queueingButtons").classList.add("invisible");
document.getElementById("queueingMenuItems").classList.add("invisible");
}
}
@ -1084,18 +1084,18 @@ window.addEventListener("DOMContentLoaded", () => {
const updateAltSpeedIcon = (enabled) => {
if (enabled) {
$("alternativeSpeedLimits").src = "images/slow.svg";
$("alternativeSpeedLimits").alt = "QBT_TR(Alternative speed limits: On)QBT_TR[CONTEXT=MainWindow]";
$("alternativeSpeedLimits").title = "QBT_TR(Alternative speed limits: On)QBT_TR[CONTEXT=MainWindow]";
document.getElementById("alternativeSpeedLimits").src = "images/slow.svg";
document.getElementById("alternativeSpeedLimits").alt = "QBT_TR(Alternative speed limits: On)QBT_TR[CONTEXT=MainWindow]";
document.getElementById("alternativeSpeedLimits").title = "QBT_TR(Alternative speed limits: On)QBT_TR[CONTEXT=MainWindow]";
}
else {
$("alternativeSpeedLimits").src = "images/slow_off.svg";
$("alternativeSpeedLimits").alt = "QBT_TR(Alternative speed limits: Off)QBT_TR[CONTEXT=MainWindow]";
$("alternativeSpeedLimits").title = "QBT_TR(Alternative speed limits: Off)QBT_TR[CONTEXT=MainWindow]";
document.getElementById("alternativeSpeedLimits").src = "images/slow_off.svg";
document.getElementById("alternativeSpeedLimits").alt = "QBT_TR(Alternative speed limits: Off)QBT_TR[CONTEXT=MainWindow]";
document.getElementById("alternativeSpeedLimits").title = "QBT_TR(Alternative speed limits: Off)QBT_TR[CONTEXT=MainWindow]";
}
};
$("alternativeSpeedLimits").addEventListener("click", () => {
document.getElementById("alternativeSpeedLimits").addEventListener("click", () => {
// Change icon immediately to give some feedback
updateAltSpeedIcon(!alternativeSpeedLimits);
@ -1114,33 +1114,33 @@ window.addEventListener("DOMContentLoaded", () => {
});
});
$("DlInfos").addEventListener("click", () => { globalDownloadLimitFN(); });
$("UpInfos").addEventListener("click", () => { globalUploadLimitFN(); });
document.getElementById("DlInfos").addEventListener("click", () => { globalDownloadLimitFN(); });
document.getElementById("UpInfos").addEventListener("click", () => { globalUploadLimitFN(); });
$("showTopToolbarLink").addEventListener("click", (e) => {
document.getElementById("showTopToolbarLink").addEventListener("click", (e) => {
showTopToolbar = !showTopToolbar;
LocalPreferences.set("show_top_toolbar", showTopToolbar.toString());
if (showTopToolbar) {
$("showTopToolbarLink").firstElementChild.style.opacity = "1";
$("mochaToolbar").classList.remove("invisible");
document.getElementById("showTopToolbarLink").firstElementChild.style.opacity = "1";
document.getElementById("mochaToolbar").classList.remove("invisible");
}
else {
$("showTopToolbarLink").firstElementChild.style.opacity = "0";
$("mochaToolbar").classList.add("invisible");
document.getElementById("showTopToolbarLink").firstElementChild.style.opacity = "0";
document.getElementById("mochaToolbar").classList.add("invisible");
}
MochaUI.Desktop.setDesktopSize();
});
$("showStatusBarLink").addEventListener("click", (e) => {
document.getElementById("showStatusBarLink").addEventListener("click", (e) => {
showStatusBar = !showStatusBar;
LocalPreferences.set("show_status_bar", showStatusBar.toString());
if (showStatusBar) {
$("showStatusBarLink").firstElementChild.style.opacity = "1";
$("desktopFooterWrapper").classList.remove("invisible");
document.getElementById("showStatusBarLink").firstElementChild.style.opacity = "1";
document.getElementById("desktopFooterWrapper").classList.remove("invisible");
}
else {
$("showStatusBarLink").firstElementChild.style.opacity = "0";
$("desktopFooterWrapper").classList.add("invisible");
document.getElementById("showStatusBarLink").firstElementChild.style.opacity = "0";
document.getElementById("desktopFooterWrapper").classList.add("invisible");
}
MochaUI.Desktop.setDesktopSize();
});
@ -1164,49 +1164,49 @@ window.addEventListener("DOMContentLoaded", () => {
navigator.registerProtocolHandler("magnet", templateUrl,
"qBittorrent WebUI magnet handler");
};
$("registerMagnetHandlerLink").addEventListener("click", (e) => {
document.getElementById("registerMagnetHandlerLink").addEventListener("click", (e) => {
registerMagnetHandler();
});
$("showFiltersSidebarLink").addEventListener("click", (e) => {
document.getElementById("showFiltersSidebarLink").addEventListener("click", (e) => {
showFiltersSidebar = !showFiltersSidebar;
LocalPreferences.set("show_filters_sidebar", showFiltersSidebar.toString());
if (showFiltersSidebar) {
$("showFiltersSidebarLink").firstElementChild.style.opacity = "1";
$("filtersColumn").classList.remove("invisible");
$("filtersColumn_handle").classList.remove("invisible");
document.getElementById("showFiltersSidebarLink").firstElementChild.style.opacity = "1";
document.getElementById("filtersColumn").classList.remove("invisible");
document.getElementById("filtersColumn_handle").classList.remove("invisible");
}
else {
$("showFiltersSidebarLink").firstElementChild.style.opacity = "0";
$("filtersColumn").classList.add("invisible");
$("filtersColumn_handle").classList.add("invisible");
document.getElementById("showFiltersSidebarLink").firstElementChild.style.opacity = "0";
document.getElementById("filtersColumn").classList.add("invisible");
document.getElementById("filtersColumn_handle").classList.add("invisible");
}
MochaUI.Desktop.setDesktopSize();
});
$("speedInBrowserTitleBarLink").addEventListener("click", (e) => {
document.getElementById("speedInBrowserTitleBarLink").addEventListener("click", (e) => {
speedInTitle = !speedInTitle;
LocalPreferences.set("speed_in_browser_title_bar", speedInTitle.toString());
if (speedInTitle)
$("speedInBrowserTitleBarLink").firstElementChild.style.opacity = "1";
document.getElementById("speedInBrowserTitleBarLink").firstElementChild.style.opacity = "1";
else
$("speedInBrowserTitleBarLink").firstElementChild.style.opacity = "0";
document.getElementById("speedInBrowserTitleBarLink").firstElementChild.style.opacity = "0";
processServerState();
});
$("showSearchEngineLink").addEventListener("click", (e) => {
document.getElementById("showSearchEngineLink").addEventListener("click", (e) => {
window.qBittorrent.Client.showSearchEngine(!window.qBittorrent.Client.isShowSearchEngine());
LocalPreferences.set("show_search_engine", window.qBittorrent.Client.isShowSearchEngine().toString());
updateTabDisplay();
});
$("showRssReaderLink").addEventListener("click", (e) => {
document.getElementById("showRssReaderLink").addEventListener("click", (e) => {
window.qBittorrent.Client.showRssReader(!window.qBittorrent.Client.isShowRssReader());
LocalPreferences.set("show_rss_reader", window.qBittorrent.Client.isShowRssReader().toString());
updateTabDisplay();
});
$("showLogViewerLink").addEventListener("click", (e) => {
document.getElementById("showLogViewerLink").addEventListener("click", (e) => {
window.qBittorrent.Client.showLogViewer(!window.qBittorrent.Client.isShowLogViewer());
LocalPreferences.set("show_log_viewer", window.qBittorrent.Client.isShowLogViewer().toString());
updateTabDisplay();
@ -1214,64 +1214,64 @@ window.addEventListener("DOMContentLoaded", () => {
const updateTabDisplay = () => {
if (window.qBittorrent.Client.isShowRssReader()) {
$("showRssReaderLink").firstElementChild.style.opacity = "1";
$("mainWindowTabs").classList.remove("invisible");
$("rssTabLink").classList.remove("invisible");
document.getElementById("showRssReaderLink").firstElementChild.style.opacity = "1";
document.getElementById("mainWindowTabs").classList.remove("invisible");
document.getElementById("rssTabLink").classList.remove("invisible");
if (!MochaUI.Panels.instances.RssPanel)
addRssPanel();
}
else {
$("showRssReaderLink").firstElementChild.style.opacity = "0";
$("rssTabLink").classList.add("invisible");
if ($("rssTabLink").classList.contains("selected"))
$("transfersTabLink").click();
document.getElementById("showRssReaderLink").firstElementChild.style.opacity = "0";
document.getElementById("rssTabLink").classList.add("invisible");
if (document.getElementById("rssTabLink").classList.contains("selected"))
document.getElementById("transfersTabLink").click();
}
if (window.qBittorrent.Client.isShowSearchEngine()) {
$("showSearchEngineLink").firstElementChild.style.opacity = "1";
$("mainWindowTabs").classList.remove("invisible");
$("searchTabLink").classList.remove("invisible");
document.getElementById("showSearchEngineLink").firstElementChild.style.opacity = "1";
document.getElementById("mainWindowTabs").classList.remove("invisible");
document.getElementById("searchTabLink").classList.remove("invisible");
if (!MochaUI.Panels.instances.SearchPanel)
addSearchPanel();
}
else {
$("showSearchEngineLink").firstElementChild.style.opacity = "0";
$("searchTabLink").classList.add("invisible");
if ($("searchTabLink").classList.contains("selected"))
$("transfersTabLink").click();
document.getElementById("showSearchEngineLink").firstElementChild.style.opacity = "0";
document.getElementById("searchTabLink").classList.add("invisible");
if (document.getElementById("searchTabLink").classList.contains("selected"))
document.getElementById("transfersTabLink").click();
}
if (window.qBittorrent.Client.isShowLogViewer()) {
$("showLogViewerLink").firstElementChild.style.opacity = "1";
$("mainWindowTabs").classList.remove("invisible");
$("logTabLink").classList.remove("invisible");
document.getElementById("showLogViewerLink").firstElementChild.style.opacity = "1";
document.getElementById("mainWindowTabs").classList.remove("invisible");
document.getElementById("logTabLink").classList.remove("invisible");
if (!MochaUI.Panels.instances.LogPanel)
addLogPanel();
}
else {
$("showLogViewerLink").firstElementChild.style.opacity = "0";
$("logTabLink").classList.add("invisible");
if ($("logTabLink").classList.contains("selected"))
$("transfersTabLink").click();
document.getElementById("showLogViewerLink").firstElementChild.style.opacity = "0";
document.getElementById("logTabLink").classList.add("invisible");
if (document.getElementById("logTabLink").classList.contains("selected"))
document.getElementById("transfersTabLink").click();
}
// display no tabs
if (!window.qBittorrent.Client.isShowRssReader() && !window.qBittorrent.Client.isShowSearchEngine() && !window.qBittorrent.Client.isShowLogViewer())
$("mainWindowTabs").classList.add("invisible");
document.getElementById("mainWindowTabs").classList.add("invisible");
};
$("StatisticsLink").addEventListener("click", () => { StatisticsLinkFN(); });
document.getElementById("StatisticsLink").addEventListener("click", () => { StatisticsLinkFN(); });
// main window tabs
const showTransfersTab = () => {
const showFiltersSidebar = LocalPreferences.get("show_filters_sidebar", "true") === "true";
if (showFiltersSidebar) {
$("filtersColumn").classList.remove("invisible");
$("filtersColumn_handle").classList.remove("invisible");
document.getElementById("filtersColumn").classList.remove("invisible");
document.getElementById("filtersColumn_handle").classList.remove("invisible");
}
$("mainColumn").classList.remove("invisible");
$("torrentsFilterToolbar").classList.remove("invisible");
document.getElementById("mainColumn").classList.remove("invisible");
document.getElementById("torrentsFilterToolbar").classList.remove("invisible");
customSyncMainDataInterval = null;
syncData(100);
@ -1284,10 +1284,10 @@ window.addEventListener("DOMContentLoaded", () => {
};
const hideTransfersTab = () => {
$("filtersColumn").classList.add("invisible");
$("filtersColumn_handle").classList.add("invisible");
$("mainColumn").classList.add("invisible");
$("torrentsFilterToolbar").classList.add("invisible");
document.getElementById("filtersColumn").classList.add("invisible");
document.getElementById("filtersColumn_handle").classList.add("invisible");
document.getElementById("mainColumn").classList.add("invisible");
document.getElementById("torrentsFilterToolbar").classList.add("invisible");
MochaUI.Desktop.resizePanels();
};
@ -1310,7 +1310,7 @@ window.addEventListener("DOMContentLoaded", () => {
searchTabInitialized = true;
}
$("searchTabColumn").classList.remove("invisible");
document.getElementById("searchTabColumn").classList.remove("invisible");
customSyncMainDataInterval = 30000;
hideTransfersTab();
hideRssTab();
@ -1321,7 +1321,7 @@ window.addEventListener("DOMContentLoaded", () => {
})();
const hideSearchTab = () => {
$("searchTabColumn").classList.add("invisible");
document.getElementById("searchTabColumn").classList.add("invisible");
MochaUI.Desktop.resizePanels();
};
@ -1347,7 +1347,7 @@ window.addEventListener("DOMContentLoaded", () => {
window.qBittorrent.Rss.load();
}
$("rssTabColumn").classList.remove("invisible");
document.getElementById("rssTabColumn").classList.remove("invisible");
customSyncMainDataInterval = 30000;
hideTransfersTab();
hideSearchTab();
@ -1358,7 +1358,7 @@ window.addEventListener("DOMContentLoaded", () => {
})();
const hideRssTab = () => {
$("rssTabColumn").classList.add("invisible");
document.getElementById("rssTabColumn").classList.add("invisible");
window.qBittorrent.Rss && window.qBittorrent.Rss.unload();
MochaUI.Desktop.resizePanels();
};
@ -1385,7 +1385,7 @@ window.addEventListener("DOMContentLoaded", () => {
window.qBittorrent.Log.load();
}
$("logTabColumn").classList.remove("invisible");
document.getElementById("logTabColumn").classList.remove("invisible");
customSyncMainDataInterval = 30000;
hideTransfersTab();
hideSearchTab();
@ -1396,7 +1396,7 @@ window.addEventListener("DOMContentLoaded", () => {
})();
const hideLogTab = () => {
$("logTabColumn").classList.add("invisible");
document.getElementById("logTabColumn").classList.add("invisible");
MochaUI.Desktop.resizePanels();
window.qBittorrent.Log && window.qBittorrent.Log.unload();
};
@ -1472,11 +1472,11 @@ window.addEventListener("DOMContentLoaded", () => {
tabsOnload: () => {
MochaUI.initializeTabs("panelTabs");
$("logMessageLink").addEventListener("click", (e) => {
document.getElementById("logMessageLink").addEventListener("click", (e) => {
window.qBittorrent.Log.setCurrentTab("main");
});
$("logPeerLink").addEventListener("click", (e) => {
document.getElementById("logPeerLink").addEventListener("click", (e) => {
window.qBittorrent.Log.setCurrentTab("peer");
});
},
@ -1618,7 +1618,7 @@ window.addEventListener("DOMContentLoaded", () => {
// listen for changes to torrentsFilterInput
let torrentsFilterInputTimer = -1;
$("torrentsFilterInput").addEventListener("input", () => {
document.getElementById("torrentsFilterInput").addEventListener("input", () => {
clearTimeout(torrentsFilterInputTimer);
torrentsFilterInputTimer = setTimeout(() => {
torrentsFilterInputTimer = -1;
@ -1628,24 +1628,24 @@ window.addEventListener("DOMContentLoaded", () => {
document.getElementById("torrentsFilterToolbar").addEventListener("change", (e) => { torrentsTable.updateTable(); });
$("transfersTabLink").addEventListener("click", () => { showTransfersTab(); });
$("searchTabLink").addEventListener("click", () => { showSearchTab(); });
$("rssTabLink").addEventListener("click", () => { showRssTab(); });
$("logTabLink").addEventListener("click", () => { showLogTab(); });
document.getElementById("transfersTabLink").addEventListener("click", () => { showTransfersTab(); });
document.getElementById("searchTabLink").addEventListener("click", () => { showSearchTab(); });
document.getElementById("rssTabLink").addEventListener("click", () => { showRssTab(); });
document.getElementById("logTabLink").addEventListener("click", () => { showLogTab(); });
updateTabDisplay();
const registerDragAndDrop = () => {
$("desktop").addEventListener("dragover", (ev) => {
document.getElementById("desktop").addEventListener("dragover", (ev) => {
if (ev.preventDefault)
ev.preventDefault();
});
$("desktop").addEventListener("dragenter", (ev) => {
document.getElementById("desktop").addEventListener("dragenter", (ev) => {
if (ev.preventDefault)
ev.preventDefault();
});
$("desktop").addEventListener("drop", (ev) => {
document.getElementById("desktop").addEventListener("drop", (ev) => {
if (ev.preventDefault)
ev.preventDefault();
@ -1679,7 +1679,7 @@ window.addEventListener("DOMContentLoaded", () => {
saveWindowSize(id);
}),
onContentLoaded: () => {
const fileInput = $(`${id}_iframe`).contentDocument.getElementById("fileselect");
const fileInput = document.getElementById(`${id}_iframe`).contentDocument.getElementById("fileselect");
fileInput.files = droppedFiles;
}
});
@ -1801,22 +1801,22 @@ window.addEventListener("load", async () => {
switch (previouslyUsedTab) {
case "search":
if (window.qBittorrent.Client.isShowSearchEngine())
$("searchTabLink").click();
document.getElementById("searchTabLink").click();
break;
case "rss":
if (window.qBittorrent.Client.isShowRssReader())
$("rssTabLink").click();
document.getElementById("rssTabLink").click();
break;
case "log":
if (window.qBittorrent.Client.isShowLogViewer())
$("logTabLink").click();
document.getElementById("logTabLink").click();
break;
case "transfers":
$("transfersTabLink").click();
document.getElementById("transfersTabLink").click();
break;
default:
console.error(`Unexpected 'selected_window_tab' value: ${previouslyUsedTab}`);
$("transfersTabLink").click();
document.getElementById("transfersTabLink").click();
break;
};
}
});

View file

@ -66,7 +66,7 @@ window.qBittorrent.ContextMenu ??= (() => {
};
// option diffs menu
this.menu = $(this.options.menu);
this.menu = document.getElementById(this.options.menu);
// fx
this.fx = new Fx.Tween(this.menu, {
@ -190,7 +190,7 @@ window.qBittorrent.ContextMenu ??= (() => {
e.stopPropagation();
}
// record this as the trigger
this.options.element = $(el);
this.options.element = el;
this.adjustMenuPosition(e);
// show the menu
this.show();
@ -219,7 +219,7 @@ window.qBittorrent.ContextMenu ??= (() => {
});
// hide on body click
$(document.body).addEventListener("click", () => {
document.body.addEventListener("click", () => {
this.hide();
this.options.element = null;
});
@ -292,7 +292,7 @@ window.qBittorrent.ContextMenu ??= (() => {
this.options.actions[action](element, this, action);
return this;
}
};
}
class FilterListContextMenu extends ContextMenu {
constructor(options) {
@ -316,7 +316,7 @@ window.qBittorrent.ContextMenu ??= (() => {
.setEnabled("stopTorrents", torrentsVisible)
.setEnabled("deleteTorrents", torrentsVisible);
}
};
}
class TorrentsTableContextMenu extends ContextMenu {
updateMenuItems() {
@ -457,7 +457,7 @@ window.qBittorrent.ContextMenu ??= (() => {
this.setEnabled("copyInfohash1", thereAreV1Hashes);
this.setEnabled("copyInfohash2", thereAreV2Hashes);
const contextTagList = $("contextTagList");
const contextTagList = document.getElementById("contextTagList");
for (const tag of tagMap.keys()) {
const checkbox = contextTagList.querySelector(`a[href="#Tag/${tag}"] input[type="checkbox"]`);
const count = tagCount.get(tag);
@ -477,7 +477,7 @@ window.qBittorrent.ContextMenu ??= (() => {
}
updateCategoriesSubMenu(categories) {
const contextCategoryList = $("contextCategoryList");
const contextCategoryList = document.getElementById("contextCategoryList");
[...contextCategoryList.children].forEach((el) => { el.destroy(); });
const createMenuItem = (text, imgURL, clickFn) => {
@ -527,7 +527,7 @@ window.qBittorrent.ContextMenu ??= (() => {
}
updateTagsSubMenu(tags) {
const contextTagList = $("contextTagList");
const contextTagList = document.getElementById("contextTagList");
contextTagList.replaceChildren();
const createMenuItem = (text, imgURL, clickFn) => {
@ -577,13 +577,13 @@ window.qBittorrent.ContextMenu ??= (() => {
contextTagList.appendChild(setTagItem);
}
}
};
}
class StatusesFilterContextMenu extends FilterListContextMenu {
updateMenuItems() {
this.updateTorrentActions();
}
};
}
class CategoriesFilterContextMenu extends FilterListContextMenu {
updateMenuItems() {
@ -604,7 +604,7 @@ window.qBittorrent.ContextMenu ??= (() => {
this.updateTorrentActions();
}
};
}
class TagsFilterContextMenu extends FilterListContextMenu {
updateMenuItems() {
@ -616,7 +616,7 @@ window.qBittorrent.ContextMenu ??= (() => {
this.updateTorrentActions();
}
};
}
class TrackersFilterContextMenu extends FilterListContextMenu {
updateMenuItems() {
@ -628,7 +628,7 @@ window.qBittorrent.ContextMenu ??= (() => {
this.updateTorrentActions();
}
};
}
class SearchPluginsTableContextMenu extends ContextMenu {
updateMenuItems() {
@ -642,7 +642,7 @@ window.qBittorrent.ContextMenu ??= (() => {
this.showItem("Uninstall");
}
};
}
class RssFeedContextMenu extends ContextMenu {
updateMenuItems() {
@ -715,9 +715,9 @@ window.qBittorrent.ContextMenu ??= (() => {
break;
}
}
};
}
class RssArticleContextMenu extends ContextMenu {};
class RssArticleContextMenu extends ContextMenu {}
class RssDownloaderRuleContextMenu extends ContextMenu {
adjustMenuPosition(e) {
@ -727,8 +727,8 @@ window.qBittorrent.ContextMenu ??= (() => {
this.menu.style.left = "-999em";
this.menu.style.top = "-999em";
// position the menu
let xPosMenu = e.pageX + this.options.offsets.x - $("rssdownloaderpage").offsetLeft;
let yPosMenu = e.pageY + this.options.offsets.y - $("rssdownloaderpage").offsetTop;
let xPosMenu = e.pageX + this.options.offsets.x - document.getElementById("rssdownloaderpage").offsetLeft;
let yPosMenu = e.pageY + this.options.offsets.y - document.getElementById("rssdownloaderpage").offsetTop;
if ((xPosMenu + this.menu.offsetWidth) > document.documentElement.clientWidth)
xPosMenu -= this.menu.offsetWidth;
if ((yPosMenu + this.menu.offsetHeight) > document.documentElement.clientHeight)
@ -765,7 +765,7 @@ window.qBittorrent.ContextMenu ??= (() => {
break;
}
}
};
}
return exports();
})();

View file

@ -55,7 +55,7 @@ window.qBittorrent.Download ??= (() => {
const option = document.createElement("option");
option.value = category.name;
option.textContent = category.name;
$("categorySelect").appendChild(option);
document.getElementById("categorySelect").appendChild(option);
}
});
};
@ -64,31 +64,31 @@ window.qBittorrent.Download ??= (() => {
const pref = window.parent.qBittorrent.Cache.preferences.get();
defaultSavePath = pref.save_path;
$("savepath").value = defaultSavePath;
$("startTorrent").checked = !pref.add_stopped_enabled;
$("addToTopOfQueue").checked = pref.add_to_top_of_queue;
document.getElementById("savepath").value = defaultSavePath;
document.getElementById("startTorrent").checked = !pref.add_stopped_enabled;
document.getElementById("addToTopOfQueue").checked = pref.add_to_top_of_queue;
if (pref.auto_tmm_enabled) {
$("autoTMM").selectedIndex = 1;
$("savepath").disabled = true;
document.getElementById("autoTMM").selectedIndex = 1;
document.getElementById("savepath").disabled = true;
}
else {
$("autoTMM").selectedIndex = 0;
document.getElementById("autoTMM").selectedIndex = 0;
}
if (pref.torrent_stop_condition === "MetadataReceived")
$("stopCondition").selectedIndex = 1;
document.getElementById("stopCondition").selectedIndex = 1;
else if (pref.torrent_stop_condition === "FilesChecked")
$("stopCondition").selectedIndex = 2;
document.getElementById("stopCondition").selectedIndex = 2;
else
$("stopCondition").selectedIndex = 0;
document.getElementById("stopCondition").selectedIndex = 0;
if (pref.torrent_content_layout === "Subfolder")
$("contentLayout").selectedIndex = 1;
document.getElementById("contentLayout").selectedIndex = 1;
else if (pref.torrent_content_layout === "NoSubfolder")
$("contentLayout").selectedIndex = 2;
document.getElementById("contentLayout").selectedIndex = 2;
else
$("contentLayout").selectedIndex = 0;
document.getElementById("contentLayout").selectedIndex = 0;
};
const changeCategorySelect = (item) => {
@ -97,41 +97,41 @@ window.qBittorrent.Download ??= (() => {
item.nextElementSibling.value = "";
item.nextElementSibling.select();
if ($("autoTMM").selectedIndex === 1)
$("savepath").value = defaultSavePath;
if (document.getElementById("autoTMM").selectedIndex === 1)
document.getElementById("savepath").value = defaultSavePath;
}
else {
item.nextElementSibling.hidden = true;
const text = item.options[item.selectedIndex].textContent;
item.nextElementSibling.value = text;
if ($("autoTMM").selectedIndex === 1) {
if (document.getElementById("autoTMM").selectedIndex === 1) {
const categoryName = item.value;
const category = categories[categoryName];
let savePath = defaultSavePath;
if (category !== undefined)
savePath = (category["savePath"] !== "") ? category["savePath"] : `${defaultSavePath}/${categoryName}`;
$("savepath").value = savePath;
document.getElementById("savepath").value = savePath;
}
}
};
const changeTMM = (item) => {
if (item.selectedIndex === 1) {
$("savepath").disabled = true;
document.getElementById("savepath").disabled = true;
const categorySelect = $("categorySelect");
const categorySelect = document.getElementById("categorySelect");
const categoryName = categorySelect.options[categorySelect.selectedIndex].value;
const category = categories[categoryName];
$("savepath").value = (category === undefined) ? "" : category["savePath"];
document.getElementById("savepath").value = (category === undefined) ? "" : category["savePath"];
}
else {
$("savepath").disabled = false;
$("savepath").value = defaultSavePath;
document.getElementById("savepath").disabled = false;
document.getElementById("savepath").value = defaultSavePath;
}
};
$(window).addEventListener("load", async () => {
window.addEventListener("load", async () => {
// user might load this page directly (via browser magnet handler)
// so wait for crucial initialization to complete
await window.parent.qBittorrent.Client.initializeCaches();

File diff suppressed because it is too large Load diff

View file

@ -56,51 +56,51 @@ window.qBittorrent.FileTree ??= (() => {
};
Object.freeze(TriState);
const FileTree = new Class({
root: null,
nodeMap: {},
class FileTree {
#root = null;
#nodeMap = {}; // Object with Number as keys is faster than anything
setRoot: function(root) {
this.root = root;
this.generateNodeMap(root);
setRoot(root) {
this.#root = root;
this.#generateNodeMap(root);
if (this.root.isFolder)
this.root.calculateSize();
},
if (this.#root.isFolder)
this.#root.calculateSize();
}
getRoot: function() {
return this.root;
},
getRoot() {
return this.#root;
}
generateNodeMap: function(root) {
#generateNodeMap(root) {
const stack = [root];
while (stack.length > 0) {
const node = stack.pop();
// don't store root node in map
if (node.root !== null)
this.nodeMap[node.rowId] = node;
this.#nodeMap[node.rowId] = node;
stack.push(...node.children);
}
},
}
getNode: function(rowId) {
return (this.nodeMap[rowId] === undefined)
? null
: this.nodeMap[rowId];
},
getNode(rowId) {
// TODO: enforce caller sites to pass `rowId` as number and not string
const value = this.#nodeMap[Number(rowId)];
return (value !== undefined) ? value : null;
}
getRowId: (node) => {
getRowId(node) {
return node.rowId;
},
}
/**
* Returns the nodes in DFS in-order
*/
toArray: function() {
toArray() {
const ret = [];
const stack = this.root.children.toReversed();
const stack = this.#root.children.toReversed();
while (stack.length > 0) {
const node = stack.pop();
ret.push(node);
@ -108,45 +108,40 @@ window.qBittorrent.FileTree ??= (() => {
}
return ret;
}
});
}
const FileNode = new Class({
name: "",
path: "",
rowId: null,
size: 0,
checked: TriState.Unchecked,
remaining: 0,
progress: 0,
priority: FilePriority.Normal,
availability: 0,
depth: 0,
root: null,
data: null,
isFolder: false,
children: [],
});
const FolderNode = new Class({
Extends: FileNode,
class FileNode {
name = "";
path = "";
rowId = null;
size = 0;
checked = TriState.Unchecked;
remaining = 0;
progress = 0;
priority = FilePriority.Normal;
availability = 0;
depth = 0;
root = null;
data = null;
isFolder = false;
children = [];
}
class FolderNode extends FileNode {
/**
* Will automatically tick the checkbox for a folder if all subfolders and files are also ticked
*/
autoCheckFolders: true,
autoCheckFolders = true;
isFolder = true;
initialize: function() {
this.isFolder = true;
},
addChild: function(node) {
addChild(node) {
this.children.push(node);
},
}
/**
* Calculate size of node and its children
*/
calculateSize: function() {
calculateSize() {
const stack = [this];
const visited = [];
@ -202,7 +197,7 @@ window.qBittorrent.FileTree ??= (() => {
stack.pop();
}
}
});
}
return exports();
})();

View file

@ -61,7 +61,7 @@ window.qBittorrent.LocalPreferences ??= (() => {
console.error(err);
}
}
};
}
return exports();
})();

View file

@ -151,7 +151,7 @@ let exportTorrentFN = () => {};
const initializeWindows = () => {
saveWindowSize = (windowId) => {
const size = $(windowId).getSize();
const size = document.getElementById(windowId).getSize();
LocalPreferences.set(`window_${windowId}_width`, size.x);
LocalPreferences.set(`window_${windowId}_height`, size.y);
};
@ -166,8 +166,8 @@ const initializeWindows = () => {
const addClickEvent = (el, fn) => {
["Link", "Button"].each((item) => {
if ($(el + item))
$(el + item).addEventListener("click", fn);
if (document.getElementById(el + item))
document.getElementById(el + item).addEventListener("click", fn);
});
};

View file

@ -85,7 +85,7 @@ window.qBittorrent.pathAutofill ??= (() => {
input.addEventListener("input", function() { showPathSuggestions(this, "all"); });
input.classList.add("pathAutoFillInitialized");
}
};
}
return exports();
})();

View file

@ -251,7 +251,7 @@ window.qBittorrent.PiecesBar ??= (() => {
}
const checkForParent = (id) => {
const obj = $(id);
const obj = document.getElementById(id);
if (!obj)
return;
if (!obj.parentNode)

View file

@ -142,7 +142,7 @@ window.qBittorrent.ProgressBar ??= (() => {
}
const ProgressBar_checkForParent = (id) => {
const obj = $(id);
const obj = document.getElementById(id);
if (!obj)
return;
if (!obj.parentNode)

View file

@ -208,7 +208,7 @@ window.qBittorrent.PropFiles ??= (() => {
const rowIds = [];
const fileIds = [];
let priority = FilePriority.Ignored;
const checkbox = $("tristate_cb");
const checkbox = document.getElementById("tristate_cb");
if (checkbox.state === "checked") {
setCheckboxUnchecked(checkbox);
@ -245,7 +245,7 @@ window.qBittorrent.PropFiles ??= (() => {
};
const updateGlobalCheckbox = () => {
const checkbox = $("tristate_cb");
const checkbox = document.getElementById("tristate_cb");
if (torrentFilesTable.isAllCheckboxesChecked())
setCheckboxChecked(checkbox);
else if (torrentFilesTable.isAllCheckboxesUnchecked())
@ -297,7 +297,7 @@ window.qBittorrent.PropFiles ??= (() => {
ids.forEach((id) => {
torrentFilesTable.setIgnored(id, ignore);
const combobox = $(`comboPrio${id}`);
const combobox = document.getElementById(`comboPrio${id}`);
if (combobox !== null)
selectComboboxPriority(combobox, priority);
});
@ -307,8 +307,8 @@ window.qBittorrent.PropFiles ??= (() => {
const loadTorrentFilesData = () => {
if (document.hidden)
return;
if ($("propFiles").classList.contains("invisible")
|| $("propertiesPanel_collapseToggle").classList.contains("panel-expand")) {
if (document.getElementById("propFiles").classList.contains("invisible")
|| document.getElementById("propertiesPanel_collapseToggle").classList.contains("panel-expand")) {
// Tab changed, don't do anything
return;
}
@ -586,10 +586,10 @@ window.qBittorrent.PropFiles ??= (() => {
// listen for changes to torrentFilesFilterInput
let torrentFilesFilterInputTimer = -1;
$("torrentFilesFilterInput").addEventListener("input", () => {
document.getElementById("torrentFilesFilterInput").addEventListener("input", () => {
clearTimeout(torrentFilesFilterInputTimer);
const value = $("torrentFilesFilterInput").value;
const value = document.getElementById("torrentFilesFilterInput").value;
torrentFilesTable.setFilter(value);
torrentFilesFilterInputTimer = setTimeout(() => {

View file

@ -40,37 +40,37 @@ window.qBittorrent.PropGeneral ??= (() => {
const piecesBar = new window.qBittorrent.PiecesBar.PiecesBar([], {
height: 18
});
$("progress").appendChild(piecesBar);
document.getElementById("progress").appendChild(piecesBar);
const clearData = () => {
document.getElementById("progressPercentage").textContent = "";
$("time_elapsed").textContent = "";
$("eta").textContent = "";
$("nb_connections").textContent = "";
$("total_downloaded").textContent = "";
$("total_uploaded").textContent = "";
$("dl_speed").textContent = "";
$("up_speed").textContent = "";
$("dl_limit").textContent = "";
$("up_limit").textContent = "";
$("total_wasted").textContent = "";
$("seeds").textContent = "";
$("peers").textContent = "";
$("share_ratio").textContent = "";
$("popularity").textContent = "";
$("reannounce").textContent = "";
$("last_seen").textContent = "";
$("total_size").textContent = "";
$("pieces").textContent = "";
$("created_by").textContent = "";
$("addition_date").textContent = "";
$("completion_date").textContent = "";
$("creation_date").textContent = "";
$("torrent_hash_v1").textContent = "";
$("torrent_hash_v2").textContent = "";
$("save_path").textContent = "";
$("comment").textContent = "";
$("private").textContent = "";
document.getElementById("time_elapsed").textContent = "";
document.getElementById("eta").textContent = "";
document.getElementById("nb_connections").textContent = "";
document.getElementById("total_downloaded").textContent = "";
document.getElementById("total_uploaded").textContent = "";
document.getElementById("dl_speed").textContent = "";
document.getElementById("up_speed").textContent = "";
document.getElementById("dl_limit").textContent = "";
document.getElementById("up_limit").textContent = "";
document.getElementById("total_wasted").textContent = "";
document.getElementById("seeds").textContent = "";
document.getElementById("peers").textContent = "";
document.getElementById("share_ratio").textContent = "";
document.getElementById("popularity").textContent = "";
document.getElementById("reannounce").textContent = "";
document.getElementById("last_seen").textContent = "";
document.getElementById("total_size").textContent = "";
document.getElementById("pieces").textContent = "";
document.getElementById("created_by").textContent = "";
document.getElementById("addition_date").textContent = "";
document.getElementById("completion_date").textContent = "";
document.getElementById("creation_date").textContent = "";
document.getElementById("torrent_hash_v1").textContent = "";
document.getElementById("torrent_hash_v2").textContent = "";
document.getElementById("save_path").textContent = "";
document.getElementById("comment").textContent = "";
document.getElementById("private").textContent = "";
piecesBar.clear();
};
@ -78,8 +78,8 @@ window.qBittorrent.PropGeneral ??= (() => {
const loadTorrentData = () => {
if (document.hidden)
return;
if ($("propGeneral").classList.contains("invisible")
|| $("propertiesPanel_collapseToggle").classList.contains("panel-expand")) {
if (document.getElementById("propGeneral").classList.contains("invisible")
|| document.getElementById("propertiesPanel_collapseToggle").classList.contains("panel-expand")) {
// Tab changed, don't do anything
return;
}
@ -100,13 +100,13 @@ window.qBittorrent.PropGeneral ??= (() => {
})
.then(async (response) => {
if (!response.ok) {
$("error_div").textContent = "QBT_TR(qBittorrent client is not reachable)QBT_TR[CONTEXT=HttpServer]";
document.getElementById("error_div").textContent = "QBT_TR(qBittorrent client is not reachable)QBT_TR[CONTEXT=HttpServer]";
clearTimeout(loadTorrentDataTimer);
loadTorrentDataTimer = loadTorrentData.delay(10000);
return;
}
$("error_div").textContent = "";
document.getElementById("error_div").textContent = "";
const data = await response.json();
if (data) {
@ -119,70 +119,70 @@ window.qBittorrent.PropGeneral ??= (() => {
.replace("%1", window.qBittorrent.Misc.friendlyDuration(data.time_elapsed))
.replace("%2", window.qBittorrent.Misc.friendlyDuration(data.seeding_time))
: window.qBittorrent.Misc.friendlyDuration(data.time_elapsed);
$("time_elapsed").textContent = timeElapsed;
document.getElementById("time_elapsed").textContent = timeElapsed;
$("eta").textContent = window.qBittorrent.Misc.friendlyDuration(data.eta, window.qBittorrent.Misc.MAX_ETA);
document.getElementById("eta").textContent = window.qBittorrent.Misc.friendlyDuration(data.eta, window.qBittorrent.Misc.MAX_ETA);
const nbConnections = "QBT_TR(%1 (%2 max))QBT_TR[CONTEXT=PropertiesWidget]"
.replace("%1", data.nb_connections)
.replace("%2", ((data.nb_connections_limit < 0) ? "∞" : data.nb_connections_limit));
$("nb_connections").textContent = nbConnections;
document.getElementById("nb_connections").textContent = nbConnections;
const totalDownloaded = "QBT_TR(%1 (%2 this session))QBT_TR[CONTEXT=PropertiesWidget]"
.replace("%1", window.qBittorrent.Misc.friendlyUnit(data.total_downloaded))
.replace("%2", window.qBittorrent.Misc.friendlyUnit(data.total_downloaded_session));
$("total_downloaded").textContent = totalDownloaded;
document.getElementById("total_downloaded").textContent = totalDownloaded;
const totalUploaded = "QBT_TR(%1 (%2 this session))QBT_TR[CONTEXT=PropertiesWidget]"
.replace("%1", window.qBittorrent.Misc.friendlyUnit(data.total_uploaded))
.replace("%2", window.qBittorrent.Misc.friendlyUnit(data.total_uploaded_session));
$("total_uploaded").textContent = totalUploaded;
document.getElementById("total_uploaded").textContent = totalUploaded;
const dlSpeed = "QBT_TR(%1 (%2 avg.))QBT_TR[CONTEXT=PropertiesWidget]"
.replace("%1", window.qBittorrent.Misc.friendlyUnit(data.dl_speed, true))
.replace("%2", window.qBittorrent.Misc.friendlyUnit(data.dl_speed_avg, true));
$("dl_speed").textContent = dlSpeed;
document.getElementById("dl_speed").textContent = dlSpeed;
const upSpeed = "QBT_TR(%1 (%2 avg.))QBT_TR[CONTEXT=PropertiesWidget]"
.replace("%1", window.qBittorrent.Misc.friendlyUnit(data.up_speed, true))
.replace("%2", window.qBittorrent.Misc.friendlyUnit(data.up_speed_avg, true));
$("up_speed").textContent = upSpeed;
document.getElementById("up_speed").textContent = upSpeed;
const dlLimit = (data.dl_limit === -1)
? "∞"
: window.qBittorrent.Misc.friendlyUnit(data.dl_limit, true);
$("dl_limit").textContent = dlLimit;
document.getElementById("dl_limit").textContent = dlLimit;
const upLimit = (data.up_limit === -1)
? "∞"
: window.qBittorrent.Misc.friendlyUnit(data.up_limit, true);
$("up_limit").textContent = upLimit;
document.getElementById("up_limit").textContent = upLimit;
$("total_wasted").textContent = window.qBittorrent.Misc.friendlyUnit(data.total_wasted);
document.getElementById("total_wasted").textContent = window.qBittorrent.Misc.friendlyUnit(data.total_wasted);
const seeds = "QBT_TR(%1 (%2 total))QBT_TR[CONTEXT=PropertiesWidget]"
.replace("%1", data.seeds)
.replace("%2", data.seeds_total);
$("seeds").textContent = seeds;
document.getElementById("seeds").textContent = seeds;
const peers = "QBT_TR(%1 (%2 total))QBT_TR[CONTEXT=PropertiesWidget]"
.replace("%1", data.peers)
.replace("%2", data.peers_total);
$("peers").textContent = peers;
document.getElementById("peers").textContent = peers;
$("share_ratio").textContent = data.share_ratio.toFixed(2);
document.getElementById("share_ratio").textContent = data.share_ratio.toFixed(2);
$("popularity").textContent = data.popularity.toFixed(2);
document.getElementById("popularity").textContent = data.popularity.toFixed(2);
$("reannounce").textContent = window.qBittorrent.Misc.friendlyDuration(data.reannounce);
document.getElementById("reannounce").textContent = window.qBittorrent.Misc.friendlyDuration(data.reannounce);
const lastSeen = (data.last_seen >= 0)
? new Date(data.last_seen * 1000).toLocaleString()
: "QBT_TR(Never)QBT_TR[CONTEXT=PropertiesWidget]";
$("last_seen").textContent = lastSeen;
document.getElementById("last_seen").textContent = lastSeen;
const totalSize = (data.total_size >= 0) ? window.qBittorrent.Misc.friendlyUnit(data.total_size) : "";
$("total_size").textContent = totalSize;
document.getElementById("total_size").textContent = totalSize;
const pieces = (data.pieces_num >= 0)
? "QBT_TR(%1 x %2 (have %3))QBT_TR[CONTEXT=PropertiesWidget]"
@ -190,40 +190,40 @@ window.qBittorrent.PropGeneral ??= (() => {
.replace("%2", window.qBittorrent.Misc.friendlyUnit(data.piece_size))
.replace("%3", data.pieces_have)
: "";
$("pieces").textContent = pieces;
document.getElementById("pieces").textContent = pieces;
$("created_by").textContent = data.created_by;
document.getElementById("created_by").textContent = data.created_by;
const additionDate = (data.addition_date >= 0)
? new Date(data.addition_date * 1000).toLocaleString()
: "QBT_TR(Unknown)QBT_TR[CONTEXT=HttpServer]";
$("addition_date").textContent = additionDate;
document.getElementById("addition_date").textContent = additionDate;
const completionDate = (data.completion_date >= 0)
? new Date(data.completion_date * 1000).toLocaleString()
: "";
$("completion_date").textContent = completionDate;
document.getElementById("completion_date").textContent = completionDate;
const creationDate = (data.creation_date >= 0)
? new Date(data.creation_date * 1000).toLocaleString()
: "";
$("creation_date").textContent = creationDate;
document.getElementById("creation_date").textContent = creationDate;
const torrentHashV1 = (data.infohash_v1 !== "")
? data.infohash_v1
: "QBT_TR(N/A)QBT_TR[CONTEXT=PropertiesWidget]";
$("torrent_hash_v1").textContent = torrentHashV1;
document.getElementById("torrent_hash_v1").textContent = torrentHashV1;
const torrentHashV2 = (data.infohash_v2 !== "")
? data.infohash_v2
: "QBT_TR(N/A)QBT_TR[CONTEXT=PropertiesWidget]";
$("torrent_hash_v2").textContent = torrentHashV2;
document.getElementById("torrent_hash_v2").textContent = torrentHashV2;
$("save_path").textContent = data.save_path;
document.getElementById("save_path").textContent = data.save_path;
$("comment").innerHTML = window.qBittorrent.Misc.parseHtmlLinks(window.qBittorrent.Misc.escapeHtml(data.comment));
document.getElementById("comment").innerHTML = window.qBittorrent.Misc.parseHtmlLinks(window.qBittorrent.Misc.escapeHtml(data.comment));
$("private").textContent = (data.has_metadata
document.getElementById("private").textContent = (data.has_metadata
? (data.private
? "QBT_TR(Yes)QBT_TR[CONTEXT=PropertiesWidget]"
: "QBT_TR(No)QBT_TR[CONTEXT=PropertiesWidget]")
@ -246,13 +246,13 @@ window.qBittorrent.PropGeneral ??= (() => {
})
.then(async (response) => {
if (!response.ok) {
$("error_div").textContent = "QBT_TR(qBittorrent client is not reachable)QBT_TR[CONTEXT=HttpServer]";
document.getElementById("error_div").textContent = "QBT_TR(qBittorrent client is not reachable)QBT_TR[CONTEXT=HttpServer]";
clearTimeout(loadTorrentDataTimer);
loadTorrentDataTimer = loadTorrentData.delay(10000);
return;
}
$("error_div").textContent = "";
document.getElementById("error_div").textContent = "";
const data = await response.json();
if (data)

View file

@ -45,8 +45,8 @@ window.qBittorrent.PropPeers ??= (() => {
const loadTorrentPeersData = () => {
if (document.hidden)
return;
if ($("propPeers").classList.contains("invisible")
|| $("propertiesPanel_collapseToggle").classList.contains("panel-expand")) {
if (document.getElementById("propPeers").classList.contains("invisible")
|| document.getElementById("propertiesPanel_collapseToggle").classList.contains("panel-expand")) {
syncTorrentPeersLastResponseId = 0;
torrentPeersTable.clear();
return;
@ -73,7 +73,7 @@ window.qBittorrent.PropPeers ??= (() => {
const responseJSON = await response.json();
$("error_div").textContent = "";
document.getElementById("error_div").textContent = "";
if (responseJSON) {
const full_update = (responseJSON["full_update"] === true);
if (full_update)

View file

@ -45,8 +45,8 @@ window.qBittorrent.PropTrackers ??= (() => {
const loadTrackersData = () => {
if (document.hidden)
return;
if ($("propTrackers").classList.contains("invisible")
|| $("propertiesPanel_collapseToggle").classList.contains("panel-expand")) {
if (document.getElementById("propTrackers").classList.contains("invisible")
|| document.getElementById("propertiesPanel_collapseToggle").classList.contains("panel-expand")) {
// Tab changed, don't do anything
return;
}

View file

@ -45,8 +45,8 @@ window.qBittorrent.PropWebseeds ??= (() => {
const loadWebSeedsData = () => {
if (document.hidden)
return;
if ($("propWebSeeds").classList.contains("invisible")
|| $("propertiesPanel_collapseToggle").classList.contains("panel-expand")) {
if (document.getElementById("propWebSeeds").classList.contains("invisible")
|| document.getElementById("propertiesPanel_collapseToggle").classList.contains("panel-expand")) {
// Tab changed, don't do anything
return;
}

View file

@ -22,7 +22,7 @@ window.qBittorrent.MultiRename ??= (() => {
// Search Options
_inner_search: "",
setSearch(val) {
setSearch: function(val) {
this._inner_search = val;
this._inner_update();
this.onChanged(this.matchedFiles);
@ -33,7 +33,7 @@ window.qBittorrent.MultiRename ??= (() => {
// Replacement Options
_inner_replacement: "",
setReplacement(val) {
setReplacement: function(val) {
this._inner_replacement = val;
this._inner_update();
this.onChanged(this.matchedFiles);

View file

@ -107,7 +107,7 @@ window.qBittorrent.Search ??= (() => {
const init = () => {
// load "Search in" preference from local storage
$("searchInTorrentName").value = (LocalPreferences.get("search_in_filter") === "names") ? "names" : "everywhere";
document.getElementById("searchInTorrentName").value = (LocalPreferences.get("search_in_filter") === "names") ? "names" : "everywhere";
const searchResultsTableContextMenu = new window.qBittorrent.ContextMenu.ContextMenu({
targets: "#searchResultsTableDiv tbody tr",
menu: "searchResultsTableMenu",
@ -128,12 +128,12 @@ window.qBittorrent.Search ??= (() => {
// listen for changes to searchInNameFilter
let searchInNameFilterTimer = -1;
$("searchInNameFilter").addEventListener("input", () => {
document.getElementById("searchInNameFilter").addEventListener("input", () => {
clearTimeout(searchInNameFilterTimer);
searchInNameFilterTimer = setTimeout(() => {
searchInNameFilterTimer = -1;
const value = $("searchInNameFilter").value;
const value = document.getElementById("searchInNameFilter").value;
searchText.filterPattern = value;
searchFilterChanged();
}, window.qBittorrent.Misc.FILTER_INPUT_DELAY);
@ -200,15 +200,15 @@ window.qBittorrent.Search ??= (() => {
document.getElementById("startSearchButton").lastChild.textContent = "QBT_TR(Search)QBT_TR[CONTEXT=SearchEngineWidget]";
});
listItem.appendChild(tabElem);
$("searchTabs").appendChild(listItem);
document.getElementById("searchTabs").appendChild(listItem);
searchResultsTabsContextMenu.addTarget(listItem);
// unhide the results elements
if (numSearchTabs() >= 1) {
$("searchResultsNoSearches").classList.add("invisible");
$("searchResultsFilters").classList.remove("invisible");
$("searchResultsTableContainer").classList.remove("invisible");
$("searchTabsToolbar").classList.remove("invisible");
document.getElementById("searchResultsNoSearches").classList.add("invisible");
document.getElementById("searchResultsFilters").classList.remove("invisible");
document.getElementById("searchResultsTableContainer").classList.remove("invisible");
document.getElementById("searchTabsToolbar").classList.remove("invisible");
}
// select new tab
@ -268,12 +268,12 @@ window.qBittorrent.Search ??= (() => {
resetSearchState();
resetFilters();
$("numSearchResultsVisible").textContent = 0;
$("numSearchResultsTotal").textContent = 0;
$("searchResultsNoSearches").classList.remove("invisible");
$("searchResultsFilters").classList.add("invisible");
$("searchResultsTableContainer").classList.add("invisible");
$("searchTabsToolbar").classList.add("invisible");
document.getElementById("numSearchResultsVisible").textContent = 0;
document.getElementById("numSearchResultsTotal").textContent = 0;
document.getElementById("searchResultsNoSearches").classList.remove("invisible");
document.getElementById("searchResultsFilters").classList.add("invisible");
document.getElementById("searchResultsTableContainer").classList.add("invisible");
document.getElementById("searchTabsToolbar").classList.add("invisible");
}
else if (isTabSelected && newTabToSelect) {
setActiveTab(newTabToSelect);
@ -335,23 +335,23 @@ window.qBittorrent.Search ??= (() => {
// restore filters
searchText.pattern = state.searchPattern;
searchText.filterPattern = state.filterPattern;
$("searchInNameFilter").value = state.filterPattern;
document.getElementById("searchInNameFilter").value = state.filterPattern;
searchSeedsFilter.min = state.seedsFilter.min;
searchSeedsFilter.max = state.seedsFilter.max;
$("searchMinSeedsFilter").value = state.seedsFilter.min;
$("searchMaxSeedsFilter").value = state.seedsFilter.max;
document.getElementById("searchMinSeedsFilter").value = state.seedsFilter.min;
document.getElementById("searchMaxSeedsFilter").value = state.seedsFilter.max;
searchSizeFilter.min = state.sizeFilter.min;
searchSizeFilter.minUnit = state.sizeFilter.minUnit;
searchSizeFilter.max = state.sizeFilter.max;
searchSizeFilter.maxUnit = state.sizeFilter.maxUnit;
$("searchMinSizeFilter").value = state.sizeFilter.min;
$("searchMinSizePrefix").value = state.sizeFilter.minUnit;
$("searchMaxSizeFilter").value = state.sizeFilter.max;
$("searchMaxSizePrefix").value = state.sizeFilter.maxUnit;
document.getElementById("searchMinSizeFilter").value = state.sizeFilter.min;
document.getElementById("searchMinSizePrefix").value = state.sizeFilter.minUnit;
document.getElementById("searchMaxSizeFilter").value = state.sizeFilter.max;
document.getElementById("searchMaxSizePrefix").value = state.sizeFilter.maxUnit;
const currentSearchPattern = $("searchPattern").value.trim();
const currentSearchPattern = document.getElementById("searchPattern").value.trim();
if (state.running && (state.searchPattern === currentSearchPattern)) {
// allow search to be stopped
document.getElementById("startSearchButton").lastChild.textContent = "QBT_TR(Stop)QBT_TR[CONTEXT=SearchEngineWidget]";
@ -360,7 +360,7 @@ window.qBittorrent.Search ??= (() => {
searchResultsTable.setSortedColumn(state.sort.column, state.sort.reverse);
$("searchInTorrentName").value = state.searchIn;
document.getElementById("searchInTorrentName").value = state.searchIn;
}
// must restore all filters before calling updateTable
@ -370,8 +370,8 @@ window.qBittorrent.Search ??= (() => {
if (rowsToSelect.length > 0)
searchResultsTable.reselectRows(rowsToSelect);
$("numSearchResultsVisible").textContent = searchResultsTable.getFilteredAndSortedRows().length;
$("numSearchResultsTotal").textContent = searchResultsTable.getRowSize();
document.getElementById("numSearchResultsVisible").textContent = searchResultsTable.getFilteredAndSortedRows().length;
document.getElementById("numSearchResultsTotal").textContent = searchResultsTable.getRowSize();
};
const getStatusIconElement = (text, image) => {
@ -386,7 +386,7 @@ window.qBittorrent.Search ??= (() => {
};
const updateStatusIconElement = (searchId, text, image) => {
const searchTab = $(`${searchTabIdPrefix}${searchId}`);
const searchTab = document.getElementById(`${searchTabIdPrefix}${searchId}`);
if (searchTab) {
const statusIcon = searchTab.querySelector(".statusIcon");
statusIcon.alt = text;
@ -439,7 +439,7 @@ window.qBittorrent.Search ??= (() => {
};
const getSelectedSearchId = () => {
const selectedTab = $("searchTabs").querySelector("li.selected");
const selectedTab = document.getElementById("searchTabs").querySelector("li.selected");
return selectedTab ? getSearchIdFromTab(selectedTab) : null;
};
@ -448,9 +448,9 @@ window.qBittorrent.Search ??= (() => {
const state = searchState.get(currentSearchId);
const isSearchRunning = state && state.running;
if (!isSearchRunning || searchPatternChanged) {
const pattern = $("searchPattern").value.trim();
const category = $("categorySelect").value;
const plugins = $("pluginsSelect").value;
const pattern = document.getElementById("searchPattern").value.trim();
const category = document.getElementById("categorySelect").value;
const plugins = document.getElementById("pluginsSelect").value;
if (!pattern || !category || !plugins)
return;
@ -506,7 +506,7 @@ window.qBittorrent.Search ??= (() => {
const manageSearchPlugins = () => {
const id = "searchPlugins";
if (!$(id)) {
if (!document.getElementById(id)) {
new MochaUI.Window({
id: id,
title: "QBT_TR(Search plugins)QBT_TR[CONTEXT=PluginSelectDlg]",
@ -541,7 +541,7 @@ window.qBittorrent.Search ??= (() => {
const onSearchPatternChanged = () => {
const currentSearchId = getSelectedSearchId();
const state = searchState.get(currentSearchId);
const currentSearchPattern = $("searchPattern").value.trim();
const currentSearchPattern = document.getElementById("searchPattern").value.trim();
// start a new search if pattern has changed, otherwise allow the search to be stopped
if (state && (state.searchPattern === currentSearchPattern)) {
searchPatternChanged = false;
@ -554,11 +554,11 @@ window.qBittorrent.Search ??= (() => {
};
const categorySelected = () => {
selectedCategory = $("categorySelect").value;
selectedCategory = document.getElementById("categorySelect").value;
};
const pluginSelected = () => {
selectedPlugin = $("pluginsSelect").value;
selectedPlugin = document.getElementById("pluginsSelect").value;
if (selectedPlugin !== prevSelectedPlugin) {
prevSelectedPlugin = selectedPlugin;
@ -567,18 +567,18 @@ window.qBittorrent.Search ??= (() => {
};
const reselectCategory = () => {
for (let i = 0; i < $("categorySelect").options.length; ++i) {
if ($("categorySelect").options[i].get("value") === selectedCategory)
$("categorySelect").options[i].selected = true;
for (let i = 0; i < document.getElementById("categorySelect").options.length; ++i) {
if (document.getElementById("categorySelect").options[i].get("value") === selectedCategory)
document.getElementById("categorySelect").options[i].selected = true;
}
categorySelected();
};
const reselectPlugin = () => {
for (let i = 0; i < $("pluginsSelect").options.length; ++i) {
if ($("pluginsSelect").options[i].get("value") === selectedPlugin)
$("pluginsSelect").options[i].selected = true;
for (let i = 0; i < document.getElementById("pluginsSelect").options.length; ++i) {
if (document.getElementById("pluginsSelect").options[i].get("value") === selectedPlugin)
document.getElementById("pluginsSelect").options[i].selected = true;
}
pluginSelected();
@ -603,7 +603,7 @@ window.qBittorrent.Search ??= (() => {
option.value = category.id;
option.textContent = category.name;
categoryOptions.push(option);
};
}
// first category is "All Categories"
if (categoryOptions.length > 1) {
@ -614,10 +614,10 @@ window.qBittorrent.Search ??= (() => {
categoryOptions.splice(1, 0, option);
}
$("categorySelect").replaceChildren(...categoryOptions);
document.getElementById("categorySelect").replaceChildren(...categoryOptions);
};
const selectedPlugin = $("pluginsSelect").value;
const selectedPlugin = document.getElementById("pluginsSelect").value;
if ((selectedPlugin === "all") || (selectedPlugin === "enabled")) {
const uniqueCategories = {};
@ -675,9 +675,9 @@ window.qBittorrent.Search ??= (() => {
const searchPluginsEmpty = (searchPlugins.length === 0);
if (!searchPluginsEmpty) {
$("searchResultsNoPlugins").classList.add("invisible");
document.getElementById("searchResultsNoPlugins").classList.add("invisible");
if (numSearchTabs() === 0)
$("searchResultsNoSearches").classList.remove("invisible");
document.getElementById("searchResultsNoSearches").classList.remove("invisible");
// sort plugins alphabetically
const allPlugins = searchPlugins.sort((left, right) => {
@ -695,11 +695,11 @@ window.qBittorrent.Search ??= (() => {
pluginOptions.splice(2, 0, createOption("──────────", undefined, true));
}
$("pluginsSelect").replaceChildren(...pluginOptions);
document.getElementById("pluginsSelect").replaceChildren(...pluginOptions);
$("searchPattern").disabled = searchPluginsEmpty;
$("categorySelect").disabled = searchPluginsEmpty;
$("pluginsSelect").disabled = searchPluginsEmpty;
document.getElementById("searchPattern").disabled = searchPluginsEmpty;
document.getElementById("categorySelect").disabled = searchPluginsEmpty;
document.getElementById("pluginsSelect").disabled = searchPluginsEmpty;
document.getElementById("startSearchButton").disabled = searchPluginsEmpty;
if (window.qBittorrent.SearchPlugins !== undefined)
@ -721,25 +721,25 @@ window.qBittorrent.Search ??= (() => {
const resetFilters = () => {
searchText.filterPattern = "";
$("searchInNameFilter").value = "";
document.getElementById("searchInNameFilter").value = "";
searchSeedsFilter.min = 0;
searchSeedsFilter.max = 0;
$("searchMinSeedsFilter").value = searchSeedsFilter.min;
$("searchMaxSeedsFilter").value = searchSeedsFilter.max;
document.getElementById("searchMinSeedsFilter").value = searchSeedsFilter.min;
document.getElementById("searchMaxSeedsFilter").value = searchSeedsFilter.max;
searchSizeFilter.min = 0.00;
searchSizeFilter.minUnit = 2; // B = 0, KiB = 1, MiB = 2, GiB = 3, TiB = 4, PiB = 5, EiB = 6
searchSizeFilter.max = 0.00;
searchSizeFilter.maxUnit = 3;
$("searchMinSizeFilter").value = searchSizeFilter.min;
$("searchMinSizePrefix").value = searchSizeFilter.minUnit;
$("searchMaxSizeFilter").value = searchSizeFilter.max;
$("searchMaxSizePrefix").value = searchSizeFilter.maxUnit;
document.getElementById("searchMinSizeFilter").value = searchSizeFilter.min;
document.getElementById("searchMinSizePrefix").value = searchSizeFilter.minUnit;
document.getElementById("searchMaxSizeFilter").value = searchSizeFilter.max;
document.getElementById("searchMaxSizePrefix").value = searchSizeFilter.maxUnit;
};
const getSearchInTorrentName = () => {
return ($("searchInTorrentName").value === "names") ? "names" : "everywhere";
return (document.getElementById("searchInTorrentName").value === "names") ? "names" : "everywhere";
};
const searchInTorrentName = () => {
@ -748,29 +748,29 @@ window.qBittorrent.Search ??= (() => {
};
const searchSeedsFilterChanged = () => {
searchSeedsFilter.min = $("searchMinSeedsFilter").value;
searchSeedsFilter.max = $("searchMaxSeedsFilter").value;
searchSeedsFilter.min = document.getElementById("searchMinSeedsFilter").value;
searchSeedsFilter.max = document.getElementById("searchMaxSeedsFilter").value;
searchFilterChanged();
};
const searchSizeFilterChanged = () => {
searchSizeFilter.min = $("searchMinSizeFilter").value;
searchSizeFilter.minUnit = $("searchMinSizePrefix").value;
searchSizeFilter.max = $("searchMaxSizeFilter").value;
searchSizeFilter.maxUnit = $("searchMaxSizePrefix").value;
searchSizeFilter.min = document.getElementById("searchMinSizeFilter").value;
searchSizeFilter.minUnit = document.getElementById("searchMinSizePrefix").value;
searchSizeFilter.max = document.getElementById("searchMaxSizeFilter").value;
searchSizeFilter.maxUnit = document.getElementById("searchMaxSizePrefix").value;
searchFilterChanged();
};
const searchSizeFilterPrefixChanged = () => {
if ((Number($("searchMinSizeFilter").value) !== 0) || (Number($("searchMaxSizeFilter").value) !== 0))
if ((Number(document.getElementById("searchMinSizeFilter").value) !== 0) || (Number(document.getElementById("searchMaxSizeFilter").value) !== 0))
searchSizeFilterChanged();
};
const searchFilterChanged = () => {
searchResultsTable.updateTable();
$("numSearchResultsVisible").textContent = searchResultsTable.getFilteredAndSortedRows().length;
document.getElementById("numSearchResultsVisible").textContent = searchResultsTable.getFilteredAndSortedRows().length;
};
const loadSearchResultsData = function(searchId) {
@ -799,7 +799,7 @@ window.qBittorrent.Search ??= (() => {
return;
}
$("error_div").textContent = "";
document.getElementById("error_div").textContent = "";
const state = searchState.get(searchId);
// check if user stopped the search prior to receiving the response
@ -842,8 +842,8 @@ window.qBittorrent.Search ??= (() => {
for (const row of newRows)
searchResultsTable.updateRowData(row);
$("numSearchResultsVisible").textContent = searchResultsTable.getFilteredAndSortedRows().length;
$("numSearchResultsTotal").textContent = searchResultsTable.getRowSize();
document.getElementById("numSearchResultsVisible").textContent = searchResultsTable.getFilteredAndSortedRows().length;
document.getElementById("numSearchResultsTotal").textContent = searchResultsTable.getRowSize();
searchResultsTable.updateTable();
}

View file

@ -30,7 +30,7 @@
MochaUI.extend({
addUpLimitSlider: (hashes) => {
if ($("uplimitSliderarea")) {
if (document.getElementById("uplimitSliderarea")) {
// Get global upload limit
fetch("api/v2/transfer/uploadLimit", {
method: "GET",
@ -61,29 +61,29 @@ MochaUI.extend({
if (up_limit < 0)
up_limit = 0;
maximum = 10000;
new Slider($("uplimitSliderarea"), $("uplimitSliderknob"), {
new Slider(document.getElementById("uplimitSliderarea"), document.getElementById("uplimitSliderknob"), {
steps: maximum,
offset: 0,
initialStep: Math.round(up_limit),
onChange: (pos) => {
if (pos > 0) {
$("uplimitUpdatevalue").value = pos;
$("upLimitUnit").style.visibility = "visible";
document.getElementById("uplimitUpdatevalue").value = pos;
document.getElementById("upLimitUnit").style.visibility = "visible";
}
else {
$("uplimitUpdatevalue").value = "∞";
$("upLimitUnit").style.visibility = "hidden";
document.getElementById("uplimitUpdatevalue").value = "∞";
document.getElementById("upLimitUnit").style.visibility = "hidden";
}
}
});
// Set default value
if (up_limit === 0) {
$("uplimitUpdatevalue").value = "∞";
$("upLimitUnit").style.visibility = "hidden";
document.getElementById("uplimitUpdatevalue").value = "∞";
document.getElementById("upLimitUnit").style.visibility = "hidden";
}
else {
$("uplimitUpdatevalue").value = Math.round(up_limit);
$("upLimitUnit").style.visibility = "visible";
document.getElementById("uplimitUpdatevalue").value = Math.round(up_limit);
document.getElementById("upLimitUnit").style.visibility = "visible";
}
}
else {
@ -108,29 +108,29 @@ MochaUI.extend({
}
if (up_limit < 0)
up_limit = 0;
new Slider($("uplimitSliderarea"), $("uplimitSliderknob"), {
new Slider(document.getElementById("uplimitSliderarea"), document.getElementById("uplimitSliderknob"), {
steps: maximum,
offset: 0,
initialStep: Math.round(up_limit / 1024),
onChange: (pos) => {
if (pos > 0) {
$("uplimitUpdatevalue").value = pos;
$("upLimitUnit").style.visibility = "visible";
document.getElementById("uplimitUpdatevalue").value = pos;
document.getElementById("upLimitUnit").style.visibility = "visible";
}
else {
$("uplimitUpdatevalue").value = "∞";
$("upLimitUnit").style.visibility = "hidden";
document.getElementById("uplimitUpdatevalue").value = "∞";
document.getElementById("upLimitUnit").style.visibility = "hidden";
}
}
});
// Set default value
if (up_limit === 0) {
$("uplimitUpdatevalue").value = "∞";
$("upLimitUnit").style.visibility = "hidden";
document.getElementById("uplimitUpdatevalue").value = "∞";
document.getElementById("upLimitUnit").style.visibility = "hidden";
}
else {
$("uplimitUpdatevalue").value = Math.round(up_limit / 1024);
$("upLimitUnit").style.visibility = "visible";
document.getElementById("uplimitUpdatevalue").value = Math.round(up_limit / 1024);
document.getElementById("upLimitUnit").style.visibility = "visible";
}
});
}
@ -139,7 +139,7 @@ MochaUI.extend({
},
addDlLimitSlider: (hashes) => {
if ($("dllimitSliderarea")) {
if (document.getElementById("dllimitSliderarea")) {
// Get global upload limit
fetch("api/v2/transfer/downloadLimit", {
method: "GET",
@ -170,29 +170,29 @@ MochaUI.extend({
if (dl_limit < 0)
dl_limit = 0;
maximum = 10000;
new Slider($("dllimitSliderarea"), $("dllimitSliderknob"), {
new Slider(document.getElementById("dllimitSliderarea"), document.getElementById("dllimitSliderknob"), {
steps: maximum,
offset: 0,
initialStep: Math.round(dl_limit),
onChange: (pos) => {
if (pos > 0) {
$("dllimitUpdatevalue").value = pos;
$("dlLimitUnit").style.visibility = "visible";
document.getElementById("dllimitUpdatevalue").value = pos;
document.getElementById("dlLimitUnit").style.visibility = "visible";
}
else {
$("dllimitUpdatevalue").value = "∞";
$("dlLimitUnit").style.visibility = "hidden";
document.getElementById("dllimitUpdatevalue").value = "∞";
document.getElementById("dlLimitUnit").style.visibility = "hidden";
}
}
});
// Set default value
if (dl_limit === 0) {
$("dllimitUpdatevalue").value = "∞";
$("dlLimitUnit").style.visibility = "hidden";
document.getElementById("dllimitUpdatevalue").value = "∞";
document.getElementById("dlLimitUnit").style.visibility = "hidden";
}
else {
$("dllimitUpdatevalue").value = Math.round(dl_limit);
$("dlLimitUnit").style.visibility = "visible";
document.getElementById("dllimitUpdatevalue").value = Math.round(dl_limit);
document.getElementById("dlLimitUnit").style.visibility = "visible";
}
}
else {
@ -217,29 +217,29 @@ MochaUI.extend({
}
if (dl_limit < 0)
dl_limit = 0;
new Slider($("dllimitSliderarea"), $("dllimitSliderknob"), {
new Slider(document.getElementById("dllimitSliderarea"), document.getElementById("dllimitSliderknob"), {
steps: maximum,
offset: 0,
initialStep: Math.round(dl_limit / 1024),
onChange: (pos) => {
if (pos > 0) {
$("dllimitUpdatevalue").value = pos;
$("dlLimitUnit").style.visibility = "visible";
document.getElementById("dllimitUpdatevalue").value = pos;
document.getElementById("dlLimitUnit").style.visibility = "visible";
}
else {
$("dllimitUpdatevalue").value = "∞";
$("dlLimitUnit").style.visibility = "hidden";
document.getElementById("dllimitUpdatevalue").value = "∞";
document.getElementById("dlLimitUnit").style.visibility = "hidden";
}
}
});
// Set default value
if (dl_limit === 0) {
$("dllimitUpdatevalue").value = "∞";
$("dlLimitUnit").style.visibility = "hidden";
document.getElementById("dllimitUpdatevalue").value = "∞";
document.getElementById("dlLimitUnit").style.visibility = "hidden";
}
else {
$("dllimitUpdatevalue").value = Math.round(dl_limit / 1024);
$("dlLimitUnit").style.visibility = "visible";
document.getElementById("dllimitUpdatevalue").value = Math.round(dl_limit / 1024);
document.getElementById("dlLimitUnit").style.visibility = "visible";
}
});
}

View file

@ -18,7 +18,7 @@
switch (event.key) {
case "Enter":
event.preventDefault();
$("setLocationButton").click();
document.getElementById("setLocationButton").click();
break;
case "Escape":
event.preventDefault();
@ -32,17 +32,17 @@
// set text field to current value
if (path !== null)
$("setLocation").value = decodeURIComponent(path);
document.getElementById("setLocation").value = decodeURIComponent(path);
$("setLocation").focus();
$("setLocationButton").addEventListener("click", (e) => {
document.getElementById("setLocation").focus();
document.getElementById("setLocationButton").addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
// check field
const location = $("setLocation").value.trim();
const location = document.getElementById("setLocation").value.trim();
if ((location === null) || (location === "")) {
$("error_div").textContent = "QBT_TR(Save path is empty)QBT_TR[CONTEXT=TorrentsController]";
document.getElementById("error_div").textContent = "QBT_TR(Save path is empty)QBT_TR[CONTEXT=TorrentsController]";
return;
}
@ -55,7 +55,7 @@
})
.then(async (response) => {
if (!response.ok) {
$("error_div").textContent = await response.text();
document.getElementById("error_div").textContent = await response.text();
return;
}

View file

@ -20,7 +20,7 @@
switch (event.key) {
case "Enter":
event.preventDefault();
$("save").click();
document.getElementById("save").click();
break;
case "Escape":
event.preventDefault();
@ -56,23 +56,23 @@
else {
setSelectedRadioValue("shareLimit", "custom");
if (values.ratioLimit >= 0) {
$("setRatio").checked = true;
$("ratio").value = values.ratioLimit.toFixed(2);
document.getElementById("setRatio").checked = true;
document.getElementById("ratio").value = values.ratioLimit.toFixed(2);
}
if (values.seedingTimeLimit >= 0) {
$("setTotalMinutes").checked = true;
$("totalMinutes").value = values.seedingTimeLimit;
document.getElementById("setTotalMinutes").checked = true;
document.getElementById("totalMinutes").value = values.seedingTimeLimit;
}
if (values.inactiveSeedingTimeLimit >= 0) {
$("setInactiveMinutes").checked = true;
$("inactiveMinutes").value = values.inactiveSeedingTimeLimit;
document.getElementById("setInactiveMinutes").checked = true;
document.getElementById("inactiveMinutes").value = values.inactiveSeedingTimeLimit;
}
}
shareLimitChanged();
$("default").focus();
$("save").addEventListener("click", (e) => {
document.getElementById("default").focus();
document.getElementById("save").addEventListener("click", (e) => {
e.preventDefault();
e.stopPropagation();
@ -91,9 +91,9 @@
ratioLimitValue = seedingTimeLimitValue = inactiveSeedingTimeLimitValue = NoLimit;
}
else if (shareLimit === "custom") {
ratioLimitValue = $("setRatio").checked ? $("ratio").value : -1;
seedingTimeLimitValue = $("setTotalMinutes").checked ? $("totalMinutes").value : -1;
inactiveSeedingTimeLimitValue = $("setInactiveMinutes").checked ? $("inactiveMinutes").value : -1;
ratioLimitValue = document.getElementById("setRatio").checked ? document.getElementById("ratio").value : -1;
seedingTimeLimitValue = document.getElementById("setTotalMinutes").checked ? document.getElementById("totalMinutes").value : -1;
inactiveSeedingTimeLimitValue = document.getElementById("setInactiveMinutes").checked ? document.getElementById("inactiveMinutes").value : -1;
}
else {
return;
@ -108,7 +108,7 @@
inactiveSeedingTimeLimit: inactiveSeedingTimeLimitValue
})
})
.then(async (response) => {
.then((response) => {
if (!response.ok)
return;
@ -139,26 +139,26 @@
const shareLimitChanged = () => {
const customShareLimit = getSelectedRadioValue("shareLimit") === "custom";
$("setRatio").disabled = !customShareLimit;
$("setTotalMinutes").disabled = !customShareLimit;
$("setInactiveMinutes").disabled = !customShareLimit;
document.getElementById("setRatio").disabled = !customShareLimit;
document.getElementById("setTotalMinutes").disabled = !customShareLimit;
document.getElementById("setInactiveMinutes").disabled = !customShareLimit;
enableInputBoxes();
$("save").disabled = !isFormValid();
document.getElementById("save").disabled = !isFormValid();
};
const enableInputBoxes = () => {
$("ratio").disabled = $("setRatio").disabled || !$("setRatio").checked;
$("totalMinutes").disabled = $("setTotalMinutes").disabled || !$("setTotalMinutes").checked;
$("inactiveMinutes").disabled = $("setInactiveMinutes").disabled || !$("setInactiveMinutes").checked;
document.getElementById("ratio").disabled = document.getElementById("setRatio").disabled || !document.getElementById("setRatio").checked;
document.getElementById("totalMinutes").disabled = document.getElementById("setTotalMinutes").disabled || !document.getElementById("setTotalMinutes").checked;
document.getElementById("inactiveMinutes").disabled = document.getElementById("setInactiveMinutes").disabled || !document.getElementById("setInactiveMinutes").checked;
$("save").disabled = !isFormValid();
document.getElementById("save").disabled = !isFormValid();
};
const isFormValid = () => {
return !((getSelectedRadioValue("shareLimit") === "custom") && !$("setRatio").checked
&& !$("setTotalMinutes").checked && !$("setInactiveMinutes").checked);
return !((getSelectedRadioValue("shareLimit") === "custom") && !document.getElementById("setRatio").checked
&& !document.getElementById("setTotalMinutes").checked && !document.getElementById("setInactiveMinutes").checked);
};
</script>
</head>
@ -172,17 +172,17 @@
<div style="margin-left: 40px; margin-bottom: 5px;">
<input type="checkbox" id="setRatio" class="shareLimitInput" onclick="enableInputBoxes()">
<label id="ratioLabel" for="setRatio">QBT_TR(ratio)QBT_TR[CONTEXT=UpDownRatioDialog]</label>
<input type="number" id="ratio" value="0.00" step=".01" min="0" max="9999" class="shareLimitInput" aria-labelledby="ratioLabel">
<input type="number" id="ratio" value="0.00" step=".01" min="0" class="shareLimitInput" aria-labelledby="ratioLabel">
</div>
<div style="margin-left: 40px; margin-bottom: 5px;">
<input type="checkbox" id="setTotalMinutes" class="shareLimitInput" onclick="enableInputBoxes()">
<label id="totalMinutesLabel" for="setTotalMinutes">QBT_TR(total minutes)QBT_TR[CONTEXT=UpDownRatioDialog]</label>
<input type="number" id="totalMinutes" value="0" step="1" min="0" max="525600" class="shareLimitInput" aria-labelledby="totalMinutesLabel">
<input type="number" id="totalMinutes" value="0" step="1" min="0" class="shareLimitInput" aria-labelledby="totalMinutesLabel">
</div>
<div style="margin-left: 40px; margin-bottom: 5px;">
<input type="checkbox" id="setInactiveMinutes" class="shareLimitInput" onclick="enableInputBoxes()">
<label id="inactiveMinutesLabel" for="setInactiveMinutes">QBT_TR(inactive minutes)QBT_TR[CONTEXT=UpDownRatioDialog]</label>
<input type="number" id="inactiveMinutes" value="0" step="1" min="0" max="525600" class="shareLimitInput" aria-labelledby="inactiveMinutesLabel">
<input type="number" id="inactiveMinutes" value="0" step="1" min="0" class="shareLimitInput" aria-labelledby="inactiveMinutesLabel">
</div>
<div style="text-align: center; padding-top: 10px;">
<input type="button" value="QBT_TR(Save)QBT_TR[CONTEXT=HttpServer]" id="save">

View file

@ -160,23 +160,23 @@
let submitted = false;
$("uploadForm").addEventListener("submit", () => {
$("startTorrentHidden").value = $("startTorrent").checked ? "false" : "true";
document.getElementById("uploadForm").addEventListener("submit", () => {
document.getElementById("startTorrentHidden").value = document.getElementById("startTorrent").checked ? "false" : "true";
$("dlLimitHidden").value = Number($("dlLimitText").value) * 1024;
$("upLimitHidden").value = Number($("upLimitText").value) * 1024;
document.getElementById("dlLimitHidden").value = Number(document.getElementById("dlLimitText").value) * 1024;
document.getElementById("upLimitHidden").value = Number(document.getElementById("upLimitText").value) * 1024;
$("upload_spinner").style.display = "block";
document.getElementById("upload_spinner").style.display = "block";
submitted = true;
});
$("upload_frame").addEventListener("load", () => {
document.getElementById("upload_frame").addEventListener("load", () => {
if (submitted)
window.parent.qBittorrent.Client.closeFrameWindow(window);
});
if ((Browser.platform === "ios") || ((Browser.platform === "mac") && (navigator.maxTouchPoints > 1)))
$("fileselect").accept = ".torrent";
document.getElementById("fileselect").accept = ".torrent";
window.qBittorrent.pathAutofill.attachPathAutofill();
</script>

View file

@ -37,7 +37,7 @@
switch (event.key) {
case "Enter":
event.preventDefault();
$("applyButton").click();
document.getElementById("applyButton").click();
break;
case "Escape":
event.preventDefault();
@ -48,7 +48,7 @@
const hashes = new URLSearchParams(window.location.search).get("hashes").split("|");
const setUpLimit = () => {
const limit = Number($("uplimitUpdatevalue").value) * 1024;
const limit = Number(document.getElementById("uplimitUpdatevalue").value) * 1024;
if (hashes[0] === "global") {
fetch("api/v2/transfer/setUploadLimit", {
method: "POST",
@ -81,7 +81,7 @@
}
};
$("uplimitUpdatevalue").focus();
document.getElementById("uplimitUpdatevalue").focus();
MochaUI.addUpLimitSlider(hashes);
</script>

View file

@ -855,12 +855,12 @@
const qbtVersion = window.parent.qBittorrent.Cache.qbtVersion.get();
const buildInfo = window.parent.qBittorrent.Cache.buildInfo.get();
$("qbittorrentVersion").textContent = `qBittorrent ${qbtVersion} QBT_TR(WebUI)QBT_TR[CONTEXT=OptionsDialog]`;
$("qtVersion").textContent = buildInfo.qt;
$("libtorrentVersion").textContent = buildInfo.libtorrent;
$("boostVersion").textContent = buildInfo.boost;
$("opensslVersion").textContent = buildInfo.openssl;
$("zlibVersion").textContent = buildInfo.zlib;
$("qbittorrentVersion").textContent += ` (${buildInfo.bitness}-bit)`;
document.getElementById("qbittorrentVersion").textContent = `qBittorrent ${qbtVersion} QBT_TR(WebUI)QBT_TR[CONTEXT=OptionsDialog]`;
document.getElementById("qtVersion").textContent = buildInfo.qt;
document.getElementById("libtorrentVersion").textContent = buildInfo.libtorrent;
document.getElementById("boostVersion").textContent = buildInfo.boost;
document.getElementById("opensslVersion").textContent = buildInfo.openssl;
document.getElementById("zlibVersion").textContent = buildInfo.zlib;
document.getElementById("qbittorrentVersion").textContent += ` (${buildInfo.bitness}-bit)`;
})();
</script>

View file

@ -16,34 +16,34 @@
(() => {
MochaUI.initializeTabs("aboutTabs");
$("aboutAboutLink").addEventListener("click", () => {
document.getElementById("aboutAboutLink").addEventListener("click", () => {
Array.prototype.forEach.call(document.querySelectorAll(".aboutTabContent"), (tab => tab.classList.add("invisible")));
$("aboutAboutContent").classList.remove("invisible");
document.getElementById("aboutAboutContent").classList.remove("invisible");
});
$("aboutAuthorLink").addEventListener("click", () => {
document.getElementById("aboutAuthorLink").addEventListener("click", () => {
Array.prototype.forEach.call(document.querySelectorAll(".aboutTabContent"), (tab => tab.classList.add("invisible")));
$("aboutAuthorContent").classList.remove("invisible");
document.getElementById("aboutAuthorContent").classList.remove("invisible");
});
$("aboutSpecialThanksLink").addEventListener("click", () => {
document.getElementById("aboutSpecialThanksLink").addEventListener("click", () => {
Array.prototype.forEach.call(document.querySelectorAll(".aboutTabContent"), (tab => tab.classList.add("invisible")));
$("aboutSpecialThanksContent").classList.remove("invisible");
document.getElementById("aboutSpecialThanksContent").classList.remove("invisible");
});
$("aboutTranslatorsLink").addEventListener("click", () => {
document.getElementById("aboutTranslatorsLink").addEventListener("click", () => {
Array.prototype.forEach.call(document.querySelectorAll(".aboutTabContent"), (tab => tab.classList.add("invisible")));
$("aboutTranslatorsContent").classList.remove("invisible");
document.getElementById("aboutTranslatorsContent").classList.remove("invisible");
});
$("aboutLicenseLink").addEventListener("click", () => {
document.getElementById("aboutLicenseLink").addEventListener("click", () => {
Array.prototype.forEach.call(document.querySelectorAll(".aboutTabContent"), (tab => tab.classList.add("invisible")));
$("aboutLicenseContent").classList.remove("invisible");
document.getElementById("aboutLicenseContent").classList.remove("invisible");
});
$("aboutSoftwareUsedLink").addEventListener("click", () => {
document.getElementById("aboutSoftwareUsedLink").addEventListener("click", () => {
Array.prototype.forEach.call(document.querySelectorAll(".aboutTabContent"), (tab => tab.classList.add("invisible")));
$("aboutSoftwareUsedContent").classList.remove("invisible");
document.getElementById("aboutSoftwareUsedContent").classList.remove("invisible");
});
})();
</script>

View file

@ -61,11 +61,11 @@
}
});
$("newPluginPath").select();
document.getElementById("newPluginPath").select();
};
const newPluginOk = () => {
const path = $("newPluginPath").value.trim();
const path = document.getElementById("newPluginPath").value.trim();
if (path) {
fetch("api/v2/search/installPlugin", {
method: "POST",

View file

@ -188,7 +188,7 @@
let selectedLogLevels = JSON.parse(LocalPreferences.get("qbt_selected_log_levels")) || ["1", "2", "4", "8"];
const init = () => {
for (const option of $("logLevelSelect").options)
for (const option of document.getElementById("logLevelSelect").options)
option.toggleAttribute("selected", selectedLogLevels.includes(option.value));
selectBox = new vanillaSelectBox("#logLevelSelect", {
@ -282,7 +282,7 @@
};
const filterTextChanged = () => {
const value = $("filterTextInput").value.trim();
const value = document.getElementById("filterTextInput").value.trim();
if (inputtedFilterText !== value) {
inputtedFilterText = value;
logFilterChanged();
@ -306,14 +306,14 @@
currentSelectedTab = tab;
if (currentSelectedTab === "main") {
selectBox.enable();
$("logMessageView").classList.remove("invisible");
$("logPeerView").classList.add("invisible");
document.getElementById("logMessageView").classList.remove("invisible");
document.getElementById("logPeerView").classList.add("invisible");
resetTableTimer("peer");
}
else {
selectBox.disable();
$("logMessageView").classList.add("invisible");
$("logPeerView").classList.remove("invisible");
document.getElementById("logMessageView").classList.add("invisible");
document.getElementById("logPeerView").classList.remove("invisible");
resetTableTimer("main");
}
@ -331,8 +331,8 @@
if (curTab === undefined)
curTab = currentSelectedTab;
$("numFilteredLogs").textContent = tableInfo[curTab].instance.filteredLength;
$("numTotalLogs").textContent = tableInfo[curTab].instance.getRowSize();
document.getElementById("numFilteredLogs").textContent = tableInfo[curTab].instance.filteredLength;
document.getElementById("numTotalLogs").textContent = tableInfo[curTab].instance.getRowSize();
};
const syncLogData = (curTab) => {
@ -368,7 +368,7 @@
})
.then(async (response) => {
if (!response.ok) {
const errorDiv = $("error_div");
const errorDiv = document.getElementById("error_div");
if (errorDiv)
errorDiv.textContent = "QBT_TR(qBittorrent client is not reachable)QBT_TR[CONTEXT=HttpServer]";
tableInfo[curTab].progress = false;
@ -376,9 +376,9 @@
return;
}
$("error_div").textContent = "";
document.getElementById("error_div").textContent = "";
if ($("logTabColumn").classList.contains("invisible"))
if (document.getElementById("logTabColumn").classList.contains("invisible"))
return;
const responseJSON = await response.json();

File diff suppressed because it is too large Load diff

View file

@ -36,37 +36,37 @@
// Tabs
MochaUI.initializeTabs("preferencesTabs");
$("PrefBehaviorLink").addEventListener("click", (e) => {
document.getElementById("PrefBehaviorLink").addEventListener("click", (e) => {
Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible")));
$("BehaviorTab").classList.remove("invisible");
document.getElementById("BehaviorTab").classList.remove("invisible");
});
$("PrefDownloadsLink").addEventListener("click", (e) => {
document.getElementById("PrefDownloadsLink").addEventListener("click", (e) => {
Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible")));
$("DownloadsTab").classList.remove("invisible");
document.getElementById("DownloadsTab").classList.remove("invisible");
});
$("PrefConnectionLink").addEventListener("click", (e) => {
document.getElementById("PrefConnectionLink").addEventListener("click", (e) => {
Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible")));
$("ConnectionTab").classList.remove("invisible");
document.getElementById("ConnectionTab").classList.remove("invisible");
});
$("PrefSpeedLink").addEventListener("click", (e) => {
document.getElementById("PrefSpeedLink").addEventListener("click", (e) => {
Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible")));
$("SpeedTab").classList.remove("invisible");
document.getElementById("SpeedTab").classList.remove("invisible");
});
$("PrefBittorrentLink").addEventListener("click", (e) => {
document.getElementById("PrefBittorrentLink").addEventListener("click", (e) => {
Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible")));
$("BittorrentTab").classList.remove("invisible");
document.getElementById("BittorrentTab").classList.remove("invisible");
});
$("PrefRSSLink").addEventListener("click", (e) => {
document.getElementById("PrefRSSLink").addEventListener("click", (e) => {
Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible")));
$("RSSTab").classList.remove("invisible");
document.getElementById("RSSTab").classList.remove("invisible");
});
$("PrefWebUILink").addEventListener("click", (e) => {
document.getElementById("PrefWebUILink").addEventListener("click", (e) => {
Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible")));
$("WebUITab").classList.remove("invisible");
document.getElementById("WebUITab").classList.remove("invisible");
});
$("PrefAdvancedLink").addEventListener("click", (e) => {
document.getElementById("PrefAdvancedLink").addEventListener("click", (e) => {
Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible")));
$("AdvancedTab").classList.remove("invisible");
document.getElementById("AdvancedTab").classList.remove("invisible");
});
})();
</script>

View file

@ -218,7 +218,7 @@
const pref = window.parent.qBittorrent.Cache.preferences.get();
if (!pref.rss_processing_enabled)
$("rssFetchingDisabled").classList.remove("invisible");
document.getElementById("rssFetchingDisabled").classList.remove("invisible");
const rssFeedContextMenu = new window.qBittorrent.ContextMenu.RssFeedContextMenu({
targets: "#rssFeedTableDiv tbody tr",
@ -232,7 +232,7 @@
if ((row.full_data.dataPath.slice(0, selectedPath.length) === selectedPath) && (row.full_data.dataUid !== ""))
feedsToUpdate.add(row);
}
};
}
feedsToUpdate.forEach((feed) => refreshFeed(feed.full_data.dataUid));
},
markRead: markSelectedAsRead,
@ -263,13 +263,13 @@
}
});
rssFeedContextMenu.addTarget($("rssFeedTableDiv"));
rssFeedContextMenu.addTarget(document.getElementById("rssFeedTableDiv"));
// deselect feed when clicking on empty part of table
$("rssFeedTableDiv").addEventListener("click", (e) => {
document.getElementById("rssFeedTableDiv").addEventListener("click", (e) => {
rssFeedTable.deselectAll();
rssFeedTable.deselectRow();
});
$("rssFeedTableDiv").addEventListener("contextmenu", (e) => {
document.getElementById("rssFeedTableDiv").addEventListener("contextmenu", (e) => {
if (e.target.nodeName === "DIV") {
rssFeedTable.deselectAll();
rssFeedTable.deselectRow();

View file

@ -370,30 +370,30 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also
const pref = window.parent.qBittorrent.Cache.preferences.get();
if (!pref.rss_auto_downloading_enabled)
$("rssDownloaderDisabled").classList.remove("invisible");
document.getElementById("rssDownloaderDisabled").classList.remove("invisible");
// recalculate height
const warningHeight = $("rssDownloaderDisabled").getBoundingClientRect().height;
const warningHeight = document.getElementById("rssDownloaderDisabled").getBoundingClientRect().height;
$("leftRssDownloaderColumn").style.height = `calc(100% - ${warningHeight}px)`;
$("centerRssDownloaderColumn").style.height = `calc(100% - ${warningHeight}px)`;
$("rightRssDownloaderColumn").style.height = `calc(100% - ${warningHeight}px)`;
document.getElementById("leftRssDownloaderColumn").style.height = `calc(100% - ${warningHeight}px)`;
document.getElementById("centerRssDownloaderColumn").style.height = `calc(100% - ${warningHeight}px)`;
document.getElementById("rightRssDownloaderColumn").style.height = `calc(100% - ${warningHeight}px)`;
$("rulesTable").style.height = `calc(100% - ${$("rulesTableDesc").getBoundingClientRect().height}px)`;
$("rssDownloaderArticlesTable").style.height = `calc(100% - ${$("articleTableDesc").getBoundingClientRect().height}px)`;
document.getElementById("rulesTable").style.height = `calc(100% - ${document.getElementById("rulesTableDesc").getBoundingClientRect().height}px)`;
document.getElementById("rssDownloaderArticlesTable").style.height = `calc(100% - ${document.getElementById("articleTableDesc").getBoundingClientRect().height}px)`;
const centerRowNotTableHeight = $("saveButton").getBoundingClientRect().height
+ $("ruleSettings").getBoundingClientRect().height + 15;
const centerRowNotTableHeight = document.getElementById("saveButton").getBoundingClientRect().height
+ document.getElementById("ruleSettings").getBoundingClientRect().height + 15;
$("rssDownloaderFeeds").style.height = `calc(100% - ${centerRowNotTableHeight}px)`;
document.getElementById("rssDownloaderFeeds").style.height = `calc(100% - ${centerRowNotTableHeight}px)`;
// firefox calculates the height of the table inside fieldset differently and thus doesn't need the offset
if (navigator.userAgent.toLowerCase().includes("firefox")) {
$("rssDownloaderFeedsTable").style.height = "100%";
document.getElementById("rssDownloaderFeedsTable").style.height = "100%";
}
else {
const outsideTableHeight = ($("rssDownloaderFeedsTable").getBoundingClientRect().top - $("rssDownloaderFeeds").getBoundingClientRect().top) - 10;
$("rssDownloaderFeedsTable").style.height = `calc(100% - ${outsideTableHeight}px)`;
const outsideTableHeight = (document.getElementById("rssDownloaderFeedsTable").getBoundingClientRect().top - document.getElementById("rssDownloaderFeeds").getBoundingClientRect().top) - 10;
document.getElementById("rssDownloaderFeedsTable").style.height = `calc(100% - ${outsideTableHeight}px)`;
}
const rssDownloaderRuleContextMenu = new window.qBittorrent.ContextMenu.RssDownloaderRuleContextMenu({
@ -419,9 +419,9 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also
rssDownloaderFeedSelectionTable.setup("rssDownloaderFeedSelectionTableDiv", "rssDownloaderFeedSelectionFixedHeaderDiv");
rssDownloaderArticlesTable.setup("rssDownloaderArticlesTableDiv", "rssDownloaderArticlesFixedHeaderDiv");
rssDownloaderRuleContextMenu.addTarget($("rulesTable"));
rssDownloaderRuleContextMenu.addTarget(document.getElementById("rulesTable"));
// deselect feed when clicking on empty part of table
$("rulesTable").addEventListener("click", (e) => {
document.getElementById("rulesTable").addEventListener("click", (e) => {
if (e.target.nodeName === "DIV") {
rssDownloaderRulesTable.deselectAll();
rssDownloaderRulesTable.deselectRow();
@ -439,7 +439,7 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also
const responseJSON = await response.json();
const combobox = $("assignCategoryCombobox");
const combobox = document.getElementById("assignCategoryCombobox");
for (const cat in responseJSON) {
if (!Object.hasOwn(responseJSON, cat))
continue;
@ -475,8 +475,8 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also
};
flatten(responseJSON);
});
$("savetoDifferentDir").addEventListener("click", () => {
$("saveToText").disabled = !$("savetoDifferentDir").checked;
document.getElementById("savetoDifferentDir").addEventListener("click", () => {
document.getElementById("saveToText").disabled = !document.getElementById("savetoDifferentDir").checked;
});
updateRulesList();
};
@ -599,27 +599,27 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also
const lastSelectedRow = rssDownloaderRulesTable.selectedRows.at(-1);
const rule = rssDownloaderRulesTable.getRow(lastSelectedRow).full_data.name;
rulesList[rule].useRegex = $("useRegEx").checked;
rulesList[rule].mustContain = $("mustContainText").value;
rulesList[rule].mustNotContain = $("mustNotContainText").value;
rulesList[rule].episodeFilter = $("episodeFilterText").value;
rulesList[rule].smartFilter = $("useSmartFilter").checked;
rulesList[rule].ignoreDays = Number($("ignoreDaysValue").value);
rulesList[rule].useRegex = document.getElementById("useRegEx").checked;
rulesList[rule].mustContain = document.getElementById("mustContainText").value;
rulesList[rule].mustNotContain = document.getElementById("mustNotContainText").value;
rulesList[rule].episodeFilter = document.getElementById("episodeFilterText").value;
rulesList[rule].smartFilter = document.getElementById("useSmartFilter").checked;
rulesList[rule].ignoreDays = Number(document.getElementById("ignoreDaysValue").value);
rulesList[rule].affectedFeeds = [...rssDownloaderFeedSelectionTable.getRowValues()]
.filter((row) => row.full_data.checked)
.map((row) => row.full_data.url);
rulesList[rule].torrentParams.category = $("assignCategoryCombobox").value;
rulesList[rule].torrentParams.tags = $("ruleAddTags").value.split(",");
if ($("savetoDifferentDir").checked) {
rulesList[rule].torrentParams.save_path = $("saveToText").value;
rulesList[rule].torrentParams.category = document.getElementById("assignCategoryCombobox").value;
rulesList[rule].torrentParams.tags = document.getElementById("ruleAddTags").value.split(",");
if (document.getElementById("savetoDifferentDir").checked) {
rulesList[rule].torrentParams.save_path = document.getElementById("saveToText").value;
rulesList[rule].torrentParams.use_auto_tmm = false;
}
else {
rulesList[rule].torrentParams.save_path = "";
}
switch ($("addStoppedCombobox").value) {
switch (document.getElementById("addStoppedCombobox").value) {
case "default":
rulesList[rule].torrentParams.stopped = null;
break;
@ -631,7 +631,7 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also
break;
}
switch ($("contentLayoutCombobox").value) {
switch (document.getElementById("contentLayoutCombobox").value) {
case "Default":
rulesList[rule].torrentParams.content_layout = null;
break;
@ -701,89 +701,89 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also
const showRule = (ruleName) => {
if (ruleName === "") {
// disable all
$("saveButton").disabled = true;
$("useRegEx").disabled = true;
$("mustContainText").disabled = true;
$("mustNotContainText").disabled = true;
$("episodeFilterText").disabled = true;
$("useSmartFilter").disabled = true;
$("assignCategoryCombobox").disabled = true;
$("ruleAddTags").disabled = true;
$("savetoDifferentDir").disabled = true;
$("saveToText").disabled = true;
$("ignoreDaysValue").disabled = true;
$("addStoppedCombobox").disabled = true;
$("contentLayoutCombobox").disabled = true;
document.getElementById("saveButton").disabled = true;
document.getElementById("useRegEx").disabled = true;
document.getElementById("mustContainText").disabled = true;
document.getElementById("mustNotContainText").disabled = true;
document.getElementById("episodeFilterText").disabled = true;
document.getElementById("useSmartFilter").disabled = true;
document.getElementById("assignCategoryCombobox").disabled = true;
document.getElementById("ruleAddTags").disabled = true;
document.getElementById("savetoDifferentDir").disabled = true;
document.getElementById("saveToText").disabled = true;
document.getElementById("ignoreDaysValue").disabled = true;
document.getElementById("addStoppedCombobox").disabled = true;
document.getElementById("contentLayoutCombobox").disabled = true;
// reset all boxes
$("useRegEx").checked = false;
$("mustContainText").value = "";
$("mustNotContainText").value = "";
$("episodeFilterText").value = "";
$("useSmartFilter").checked = false;
$("assignCategoryCombobox").value = "default";
$("ruleAddTags").value = "";
$("savetoDifferentDir").checked = false;
$("saveToText").value = "";
$("ignoreDaysValue").value = 0;
$("lastMatchText").textContent = "QBT_TR(Last Match: Unknown)QBT_TR[CONTEXT=AutomatedRssDownloader]";
$("addStoppedCombobox").value = "default";
$("contentLayoutCombobox").value = "Default";
document.getElementById("useRegEx").checked = false;
document.getElementById("mustContainText").value = "";
document.getElementById("mustNotContainText").value = "";
document.getElementById("episodeFilterText").value = "";
document.getElementById("useSmartFilter").checked = false;
document.getElementById("assignCategoryCombobox").value = "default";
document.getElementById("ruleAddTags").value = "";
document.getElementById("savetoDifferentDir").checked = false;
document.getElementById("saveToText").value = "";
document.getElementById("ignoreDaysValue").value = 0;
document.getElementById("lastMatchText").textContent = "QBT_TR(Last Match: Unknown)QBT_TR[CONTEXT=AutomatedRssDownloader]";
document.getElementById("addStoppedCombobox").value = "default";
document.getElementById("contentLayoutCombobox").value = "Default";
rssDownloaderFeedSelectionTable.clear();
rssDownloaderArticlesTable.clear();
$("mustContainText").title = "";
$("mustNotContainText").title = "";
$("episodeFilterText").title = "";
document.getElementById("mustContainText").title = "";
document.getElementById("mustNotContainText").title = "";
document.getElementById("episodeFilterText").title = "";
}
else {
// enable all
$("saveButton").disabled = false;
$("useRegEx").disabled = false;
$("mustContainText").disabled = false;
$("mustNotContainText").disabled = false;
$("episodeFilterText").disabled = false;
$("useSmartFilter").disabled = false;
$("assignCategoryCombobox").disabled = false;
$("ruleAddTags").disabled = false;
$("savetoDifferentDir").disabled = false;
$("ignoreDaysValue").disabled = false;
$("addStoppedCombobox").disabled = false;
$("contentLayoutCombobox").disabled = false;
document.getElementById("saveButton").disabled = false;
document.getElementById("useRegEx").disabled = false;
document.getElementById("mustContainText").disabled = false;
document.getElementById("mustNotContainText").disabled = false;
document.getElementById("episodeFilterText").disabled = false;
document.getElementById("useSmartFilter").disabled = false;
document.getElementById("assignCategoryCombobox").disabled = false;
document.getElementById("ruleAddTags").disabled = false;
document.getElementById("savetoDifferentDir").disabled = false;
document.getElementById("ignoreDaysValue").disabled = false;
document.getElementById("addStoppedCombobox").disabled = false;
document.getElementById("contentLayoutCombobox").disabled = false;
// load rule settings
$("useRegEx").checked = rulesList[ruleName].useRegex;
$("mustContainText").value = rulesList[ruleName].mustContain;
$("mustNotContainText").value = rulesList[ruleName].mustNotContain;
$("episodeFilterText").value = rulesList[ruleName].episodeFilter;
$("useSmartFilter").checked = rulesList[ruleName].smartFilter;
document.getElementById("useRegEx").checked = rulesList[ruleName].useRegex;
document.getElementById("mustContainText").value = rulesList[ruleName].mustContain;
document.getElementById("mustNotContainText").value = rulesList[ruleName].mustNotContain;
document.getElementById("episodeFilterText").value = rulesList[ruleName].episodeFilter;
document.getElementById("useSmartFilter").checked = rulesList[ruleName].smartFilter;
$("assignCategoryCombobox").value = rulesList[ruleName].torrentParams.category ? rulesList[ruleName].torrentParams.category : "default";
$("ruleAddTags").value = rulesList[ruleName].torrentParams.tags.join(",");
$("savetoDifferentDir").checked = rulesList[ruleName].torrentParams.save_path !== "";
$("saveToText").disabled = !$("savetoDifferentDir").checked;
$("saveToText").value = rulesList[ruleName].torrentParams.save_path;
$("ignoreDaysValue").value = rulesList[ruleName].ignoreDays;
document.getElementById("assignCategoryCombobox").value = rulesList[ruleName].torrentParams.category ? rulesList[ruleName].torrentParams.category : "default";
document.getElementById("ruleAddTags").value = rulesList[ruleName].torrentParams.tags.join(",");
document.getElementById("savetoDifferentDir").checked = rulesList[ruleName].torrentParams.save_path !== "";
document.getElementById("saveToText").disabled = !document.getElementById("savetoDifferentDir").checked;
document.getElementById("saveToText").value = rulesList[ruleName].torrentParams.save_path;
document.getElementById("ignoreDaysValue").value = rulesList[ruleName].ignoreDays;
// calculate days since last match
if (rulesList[ruleName].lastMatch !== "") {
const timeDiffInMs = new Date().getTime() - new Date(rulesList[ruleName].lastMatch).getTime();
const daysAgo = Math.floor(timeDiffInMs / (1000 * 60 * 60 * 24)).toString();
$("lastMatchText").textContent = " QBT_TR(Last Match: %1 days ago)QBT_TR[CONTEXT=AutomatedRssDownloader]".replace("%1", daysAgo);
document.getElementById("lastMatchText").textContent = " QBT_TR(Last Match: %1 days ago)QBT_TR[CONTEXT=AutomatedRssDownloader]".replace("%1", daysAgo);
}
else {
$("lastMatchText").textContent = "QBT_TR(Last Match: Unknown)QBT_TR[CONTEXT=AutomatedRssDownloader]";
document.getElementById("lastMatchText").textContent = "QBT_TR(Last Match: Unknown)QBT_TR[CONTEXT=AutomatedRssDownloader]";
}
if ((rulesList[ruleName].torrentParams.stopped === undefined) || (rulesList[ruleName].torrentParams.stopped === null))
$("addStoppedCombobox").value = "default";
document.getElementById("addStoppedCombobox").value = "default";
else
$("addStoppedCombobox").value = rulesList[ruleName].torrentParams.stopped ? "always" : "never";
document.getElementById("addStoppedCombobox").value = rulesList[ruleName].torrentParams.stopped ? "always" : "never";
if ((rulesList[ruleName].torrentParams.content_layout === undefined) || (rulesList[ruleName].torrentParams.content_layout === null))
$("contentLayoutCombobox").value = "Default";
document.getElementById("contentLayoutCombobox").value = "Default";
else
$("contentLayoutCombobox").value = rulesList[ruleName].torrentParams.content_layout;
document.getElementById("contentLayoutCombobox").value = rulesList[ruleName].torrentParams.content_layout;
setElementTitles();
@ -804,7 +804,7 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also
const setElementTitles = () => {
let mainPart;
if ($("useRegEx").checked) {
if (document.getElementById("useRegEx").checked) {
mainPart = "QBT_TR(Regex mode: use Perl-compatible regular expressions)QBT_TR[CONTEXT=AutomatedRssDownloader]\n\n";
}
else {
@ -818,8 +818,8 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also
const secondPart = "QBT_TR(An expression with an empty %1 clause (e.g. %2))QBT_TR[CONTEXT=AutomatedRssDownloader]"
.replace("%1", "|").replace("%2", "expr|");
$("mustContainText").title = `${mainPart}${secondPart}QBT_TR( will match all articles.)QBT_TR[CONTEXT=AutomatedRssDownloader]`;
$("mustNotContainText").title = `${mainPart}${secondPart}QBT_TR( will exclude all articles.)QBT_TR[CONTEXT=AutomatedRssDownloader]`;
document.getElementById("mustContainText").title = `${mainPart}${secondPart}QBT_TR( will match all articles.)QBT_TR[CONTEXT=AutomatedRssDownloader]`;
document.getElementById("mustNotContainText").title = `${mainPart}${secondPart}QBT_TR( will exclude all articles.)QBT_TR[CONTEXT=AutomatedRssDownloader]`;
let episodeFilterTitle = "QBT_TR(Matches articles based on episode filter.)QBT_TR[CONTEXT=AutomatedRssDownloader]\n\n"
+ "QBT_TR(Example: )QBT_TR[CONTEXT=AutomatedRssDownloader]"
@ -835,7 +835,7 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also
+ " ● QBT_TR(Infinite range: <b>1x25-;</b> matches episodes 25 and upward of season one, and all episodes of later seasons)QBT_TR[CONTEXT=AutomatedRssDownloader]";
episodeFilterTitle = episodeFilterTitle.replace(/<b>/g, "").replace(/<\/b>/g, "");
$("episodeFilterText").title = episodeFilterTitle;
document.getElementById("episodeFilterText").title = episodeFilterTitle;
};
return exports();

View file

@ -80,9 +80,7 @@ private slots:
{
const Utils::Version<1> version1 {1};
QCOMPARE(version1[0], 1);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 3, 0))
QVERIFY_THROWS_EXCEPTION(std::out_of_range, version1[1]);
#endif
QCOMPARE(version1.majorNumber(), 1);
// should not compile:
// version1.minorNumber();
@ -92,9 +90,7 @@ private slots:
const Utils::Version<2, 1> version2 {2};
QCOMPARE(version2[0], 2);
QCOMPARE(version2[1], 0);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 3, 0))
QVERIFY_THROWS_EXCEPTION(std::out_of_range, version2[2]);
#endif
QCOMPARE(version2.majorNumber(), 2);
QCOMPARE(version2.minorNumber(), 0);
// should not compile:
@ -105,9 +101,7 @@ private slots:
QCOMPARE(version3[0], 3);
QCOMPARE(version3[1], 2);
QCOMPARE(version3[2], 0);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 3, 0))
QVERIFY_THROWS_EXCEPTION(std::out_of_range, version3[3]);
#endif
QCOMPARE(version3.majorNumber(), 3);
QCOMPARE(version3.minorNumber(), 2);
QCOMPARE(version3.revisionNumber(), 0);
@ -119,9 +113,7 @@ private slots:
QCOMPARE(version4[1], 11);
QCOMPARE(version4[2], 12);
QCOMPARE(version4[3], 13);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 3, 0))
QVERIFY_THROWS_EXCEPTION(std::out_of_range, version4[4]);
#endif
QCOMPARE(version4.majorNumber(), 10);
QCOMPARE(version4.minorNumber(), 11);
QCOMPARE(version4.revisionNumber(), 12);