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

View file

@ -16,7 +16,7 @@ jobs:
matrix: matrix:
libt_version: ["2.0.11"] libt_version: ["2.0.11"]
qbt_gui: ["GUI=ON"] qbt_gui: ["GUI=ON"]
qt_version: ["6.5.2"] qt_version: ["6.6.3"]
env: env:
boost_path: "${{ github.workspace }}/../boost" 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 # version requirements - older versions may work, but you are on your own
set(minBoostVersion 1.76) set(minBoostVersion 1.76)
set(minQt6Version 6.5.0) set(minQt6Version 6.6.0)
set(minOpenSSLVersion 3.0.2) set(minOpenSSLVersion 3.0.2)
set(minLibtorrent1Version 1.2.19) set(minLibtorrent1Version 1.2.19)
set(minLibtorrentVersion 2.0.10) set(minLibtorrentVersion 2.0.10)

View file

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

View file

@ -20,7 +20,7 @@ target_compile_features(qbt_common_cfg INTERFACE
) )
target_compile_definitions(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_FROM_ASCII
QT_NO_CAST_TO_ASCII QT_NO_CAST_TO_ASCII
QT_NO_CAST_FROM_BYTEARRAY QT_NO_CAST_FROM_BYTEARRAY

View file

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

View file

@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -27,13 +27,14 @@
*/ */
#include "filesearcher.h" #include "filesearcher.h"
#include "base/bittorrent/common.h"
#include "base/bittorrent/infohash.h"
void FileSearcher::search(const BitTorrent::TorrentID &id, const PathList &originalFileNames #include <QPromise>
, const Path &savePath, const Path &downloadPath, const bool forceAppendExt)
#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; bool found = false;
for (Path &fileName : fileNames) for (Path &fileName : fileNames)
@ -58,8 +59,12 @@ void FileSearcher::search(const BitTorrent::TorrentID &id, const PathList &origi
} }
return found; return found;
}; }
}
void FileSearcher::search(const PathList &originalFileNames, const Path &savePath
, const Path &downloadPath, const bool forceAppendExt, QPromise<FileSearchResult> &promise)
{
Path usedPath = savePath; Path usedPath = savePath;
PathList adjustedFileNames = originalFileNames; PathList adjustedFileNames = originalFileNames;
const bool found = findInDir(usedPath, adjustedFileNames, (forceAppendExt && downloadPath.isEmpty())); 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); 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. * 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -32,10 +32,13 @@
#include "base/path.h" #include "base/path.h"
namespace BitTorrent template <typename T> class QPromise;
struct FileSearchResult
{ {
class TorrentID; Path savePath;
} PathList fileNames;
};
class FileSearcher final : public QObject class FileSearcher final : public QObject
{ {
@ -43,12 +46,8 @@ class FileSearcher final : public QObject
Q_DISABLE_COPY_MOVE(FileSearcher) Q_DISABLE_COPY_MOVE(FileSearcher)
public: public:
FileSearcher() = default; using QObject::QObject;
public slots: void search(const PathList &originalFileNames, const Path &savePath
void search(const BitTorrent::TorrentID &id, const PathList &originalFileNames , const Path &downloadPath, bool forceAppendExt, QPromise<FileSearchResult> &promise);
, const Path &savePath, const Path &downloadPath, bool forceAppendExt);
signals:
void searchFinished(const BitTorrent::TorrentID &id, const Path &savePath, const PathList &fileNames);
}; };

View file

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

View file

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

View file

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

View file

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

View file

@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -34,6 +34,8 @@
#include "abstractfilestorage.h" #include "abstractfilestorage.h"
#include "downloadpriority.h" #include "downloadpriority.h"
template <typename T> class QFuture;
namespace BitTorrent namespace BitTorrent
{ {
class TorrentContentHandler : public QObject, public AbstractFileStorage 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 * 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. * that can be downloaded right now. It varies between 0 to 1.
*/ */
virtual QList<qreal> availableFileFractions() const = 0; virtual QFuture<QList<qreal>> fetchAvailableFileFractions() const = 0;
virtual void fetchAvailableFileFractions(std::function<void (QList<qreal>)> resultHandler) const = 0;
virtual void prioritizeFiles(const QList<DownloadPriority> &priorities) = 0; virtual void prioritizeFiles(const QList<DownloadPriority> &priorities) = 0;
virtual void flushCache() const = 0; virtual void flushCache() const = 0;

View file

@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * 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> * Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -51,7 +51,9 @@
#include <QByteArray> #include <QByteArray>
#include <QCache> #include <QCache>
#include <QDebug> #include <QDebug>
#include <QFuture>
#include <QPointer> #include <QPointer>
#include <QPromise>
#include <QSet> #include <QSet>
#include <QStringList> #include <QStringList>
#include <QUrl> #include <QUrl>
@ -67,6 +69,7 @@
#include "common.h" #include "common.h"
#include "downloadpriority.h" #include "downloadpriority.h"
#include "extensiondata.h" #include "extensiondata.h"
#include "filesearcher.h"
#include "loadtorrentparams.h" #include "loadtorrentparams.h"
#include "ltqbitarray.h" #include "ltqbitarray.h"
#include "lttypecast.h" #include "lttypecast.h"
@ -1465,48 +1468,11 @@ bool TorrentImpl::isLSDDisabled() const
return static_cast<bool>(m_nativeStatus.flags & lt::torrent_flags::disable_lsd); 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 QBitArray TorrentImpl::pieces() const
{ {
return m_pieces; 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 qreal TorrentImpl::distributedCopies() const
{ {
return m_nativeStatus.distributed_copies; return m_nativeStatus.distributed_copies;
@ -1549,7 +1515,8 @@ qreal TorrentImpl::realRatio() const
const qreal ratio = upload / static_cast<qreal>(download); const qreal ratio = upload / static_cast<qreal>(download);
Q_ASSERT(ratio >= 0); Q_ASSERT(ratio >= 0);
return (ratio > MAX_RATIO) ? MAX_RATIO : ratio;
return ratio;
} }
int TorrentImpl::uploadPayloadRate() const int TorrentImpl::uploadPayloadRate() const
@ -1751,12 +1718,6 @@ void TorrentImpl::applyFirstLastPiecePriority(const bool enabled)
m_nativeHandle.prioritize_pieces(piecePriorities); 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) 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() 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. // 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 // 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. // 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) 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); 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 else
{ {
@ -2712,8 +2678,6 @@ void TorrentImpl::setRatioLimit(qreal limit)
{ {
if (limit < USE_GLOBAL_RATIO) if (limit < USE_GLOBAL_RATIO)
limit = NO_RATIO_LIMIT; limit = NO_RATIO_LIMIT;
else if (limit > MAX_RATIO)
limit = MAX_RATIO;
if (m_ratioLimit != limit) if (m_ratioLimit != limit)
{ {
@ -2727,8 +2691,6 @@ void TorrentImpl::setSeedingTimeLimit(int limit)
{ {
if (limit < USE_GLOBAL_SEEDING_TIME) if (limit < USE_GLOBAL_SEEDING_TIME)
limit = NO_SEEDING_TIME_LIMIT; limit = NO_SEEDING_TIME_LIMIT;
else if (limit > MAX_SEEDING_TIME)
limit = MAX_SEEDING_TIME;
if (m_seedingTimeLimit != limit) if (m_seedingTimeLimit != limit)
{ {
@ -2742,8 +2704,6 @@ void TorrentImpl::setInactiveSeedingTimeLimit(int limit)
{ {
if (limit < USE_GLOBAL_INACTIVE_SEEDING_TIME) if (limit < USE_GLOBAL_INACTIVE_SEEDING_TIME)
limit = NO_INACTIVE_SEEDING_TIME_LIMIT; limit = NO_INACTIVE_SEEDING_TIME_LIMIT;
else if (limit > MAX_INACTIVE_SEEDING_TIME)
limit = MAX_SEEDING_TIME;
if (m_inactiveSeedingTimeLimit != limit) if (m_inactiveSeedingTimeLimit != limit)
{ {
@ -2930,9 +2890,9 @@ nonstd::expected<void, QString> TorrentImpl::exportToFile(const Path &path) cons
return {}; 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 try
{ {
@ -2947,13 +2907,12 @@ void TorrentImpl::fetchPeerInfo(std::function<void (QList<PeerInfo>)> resultHand
catch (const std::exception &) {} catch (const std::exception &) {}
return {}; 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 try
{ {
@ -2967,13 +2926,12 @@ void TorrentImpl::fetchURLSeeds(std::function<void (QList<QUrl>)> resultHandler)
catch (const std::exception &) {} catch (const std::exception &) {}
return {}; 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 try
{ {
@ -2984,13 +2942,12 @@ void TorrentImpl::fetchPieceAvailability(std::function<void (QList<int>)> result
catch (const std::exception &) {} catch (const std::exception &) {}
return {}; 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 try
{ {
@ -3009,13 +2966,12 @@ void TorrentImpl::fetchDownloadingPieces(std::function<void (QBitArray)> resultH
catch (const std::exception &) {} catch (const std::exception &) {}
return {}; 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)) if (!torrentInfo.isValid() || (torrentInfo.filesCount() <= 0))
return {}; return {};
@ -3049,8 +3005,7 @@ void TorrentImpl::fetchAvailableFileFractions(std::function<void (QList<qreal>)>
catch (const std::exception &) {} catch (const std::exception &) {}
return {}; return {};
} });
, std::move(resultHandler));
} }
void TorrentImpl::prioritizeFiles(const QList<DownloadPriority> &priorities) void TorrentImpl::prioritizeFiles(const QList<DownloadPriority> &priorities)
@ -3090,47 +3045,17 @@ void TorrentImpl::prioritizeFiles(const QList<DownloadPriority> &priorities)
manageActualFilePaths(); manageActualFilePaths();
} }
QList<qreal> TorrentImpl::availableFileFractions() const template <typename Func>
QFuture<std::invoke_result_t<Func>> TorrentImpl::invokeAsync(Func &&func) const
{ {
Q_ASSERT(hasMetadata()); QPromise<std::invoke_result_t<Func>> promise;
const auto future = promise.future();
const int filesCount = this->filesCount(); promise.start();
if (filesCount <= 0) return {}; m_session->invokeAsync([func = std::forward<Func>(func), promise = std::move(promise)]() mutable
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)
{ {
const TorrentInfo::PieceRange filePieces = m_torrentInfo.filePieces(i); promise.addResult(func());
promise.finish();
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);
});
}); });
return future;
} }

View file

@ -203,10 +203,7 @@ namespace BitTorrent
bool isDHTDisabled() const override; bool isDHTDisabled() const override;
bool isPEXDisabled() const override; bool isPEXDisabled() const override;
bool isLSDDisabled() const override; bool isLSDDisabled() const override;
QList<PeerInfo> peers() const override;
QBitArray pieces() const override; QBitArray pieces() const override;
QBitArray downloadingPieces() const override;
QList<int> pieceAvailability() const override;
qreal distributedCopies() const override; qreal distributedCopies() const override;
qreal maxRatio() const override; qreal maxRatio() const override;
int maxSeedingTime() const override; int maxSeedingTime() const override;
@ -220,7 +217,6 @@ namespace BitTorrent
int connectionsCount() const override; int connectionsCount() const override;
int connectionsLimit() const override; int connectionsLimit() const override;
qlonglong nextAnnounce() const override; qlonglong nextAnnounce() const override;
QList<qreal> availableFileFractions() const override;
void setName(const QString &name) override; void setName(const QString &name) override;
void setSequentialDownload(bool enable) override; void setSequentialDownload(bool enable) override;
@ -258,11 +254,11 @@ namespace BitTorrent
nonstd::expected<QByteArray, QString> exportToBuffer() const override; nonstd::expected<QByteArray, QString> exportToBuffer() const override;
nonstd::expected<void, QString> exportToFile(const Path &path) const override; nonstd::expected<void, QString> exportToFile(const Path &path) const override;
void fetchPeerInfo(std::function<void (QList<PeerInfo>)> resultHandler) const override; QFuture<QList<PeerInfo>> fetchPeerInfo() const override;
void fetchURLSeeds(std::function<void (QList<QUrl>)> resultHandler) const override; QFuture<QList<QUrl>> fetchURLSeeds() const override;
void fetchPieceAvailability(std::function<void (QList<int>)> resultHandler) const override; QFuture<QList<int>> fetchPieceAvailability() const override;
void fetchDownloadingPieces(std::function<void (QBitArray)> resultHandler) const override; QFuture<QBitArray> fetchDownloadingPieces() const override;
void fetchAvailableFileFractions(std::function<void (QList<qreal>)> resultHandler) const override; QFuture<QList<qreal>> fetchAvailableFileFractions() const override;
bool needSaveResumeData() const; bool needSaveResumeData() const;
@ -278,7 +274,6 @@ namespace BitTorrent
void requestResumeData(lt::resume_data_flags_t flags = {}); void requestResumeData(lt::resume_data_flags_t flags = {});
void deferredRequestResumeData(); void deferredRequestResumeData();
void handleMoveStorageJobFinished(const Path &path, MoveStorageContext context, bool hasOutstandingJob); 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); TrackerEntryStatus updateTrackerEntryStatus(const lt::announce_entry &announceEntry, const QHash<lt::tcp::endpoint, QMap<int, int>> &updateInfo);
void resetTrackerEntryStatuses(); void resetTrackerEntryStatuses();
@ -326,8 +321,8 @@ namespace BitTorrent
nonstd::expected<lt::entry, QString> exportTorrent() const; nonstd::expected<lt::entry, QString> exportTorrent() const;
template <typename Func, typename Callback> template <typename Func>
void invokeAsync(Func func, Callback resultHandler) const; QFuture<std::invoke_result_t<Func>> invokeAsync(Func &&func) const;
SessionImpl *const m_session = nullptr; SessionImpl *const m_session = nullptr;
lt::session *m_nativeSession = 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 {new QProcess(this)}
{ {
m_downloadProcess->setProcessEnvironment(m_manager->proxyEnvironment()); 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); m_downloadProcess->setUnixProcessParameters(QProcess::UnixProcessFlag::CloseFileDescriptors);
#endif #endif
connect(m_downloadProcess, qOverload<int, QProcess::ExitStatus>(&QProcess::finished) 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) // Load environment variables (proxy)
m_searchProcess->setProcessEnvironment(m_manager->proxyEnvironment()); m_searchProcess->setProcessEnvironment(m_manager->proxyEnvironment());
m_searchProcess->setProgram(Utils::ForeignApps::pythonInfo().executableName); 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); m_searchProcess->setUnixProcessParameters(QProcess::UnixProcessFlag::CloseFileDescriptors);
#endif #endif

View file

@ -546,7 +546,7 @@ void SearchPluginManager::update()
{ {
QProcess nova; QProcess nova;
nova.setProcessEnvironment(proxyEnvironment()); 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); nova.setUnixProcessParameters(QProcess::UnixProcessFlag::CloseFileDescriptors);
#endif #endif

View file

@ -57,7 +57,7 @@ namespace
info = {}; info = {};
QProcess proc; QProcess proc;
#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)) #ifdef Q_OS_UNIX
proc.setUnixProcessParameters(QProcess::UnixProcessFlag::CloseFileDescriptors); proc.setUnixProcessParameters(QProcess::UnixProcessFlag::CloseFileDescriptors);
#endif #endif
proc.start(exeName, {u"--version"_s}, QIODevice::ReadOnly); 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) 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); return QRegularExpression::wildcardToRegularExpression(pattern, QRegularExpression::UnanchoredWildcardConversion);
#endif
} }
QStringList Utils::String::splitCommand(const QString &command) QStringList Utils::String::splitCommand(const QString &command)

View file

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

View file

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

View file

@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * 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> * Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -33,6 +33,7 @@
#include <QApplication> #include <QApplication>
#include <QClipboard> #include <QClipboard>
#include <QFuture>
#include <QHeaderView> #include <QHeaderView>
#include <QHostAddress> #include <QHostAddress>
#include <QList> #include <QList>
@ -406,7 +407,7 @@ void PeerListWidget::loadPeers(const BitTorrent::Torrent *torrent)
return; return;
using TorrentPtr = QPointer<const BitTorrent::Torrent>; 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()) if (torrent != m_properties->getCurrentTorrent())
return; return;

View file

@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * 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> * Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -32,6 +32,7 @@
#include <QClipboard> #include <QClipboard>
#include <QDateTime> #include <QDateTime>
#include <QDebug> #include <QDebug>
#include <QFuture>
#include <QListWidgetItem> #include <QListWidgetItem>
#include <QMenu> #include <QMenu>
#include <QMessageBox> #include <QMessageBox>
@ -440,10 +441,10 @@ void PropertiesWidget::loadDynamicData()
// Update ratio info // Update ratio info
const qreal ratio = m_torrent->realRatio(); 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(); 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)") m_ui->labelSeedsVal->setText(tr("%1 (%2 total)", "%1 and %2 are numbers, e.g. 3 (10 total)")
.arg(QString::number(m_torrent->seedsCount()) .arg(QString::number(m_torrent->seedsCount())
@ -471,15 +472,15 @@ void PropertiesWidget::loadDynamicData()
if (m_torrent->hasMetadata()) 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())); 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()) if (!m_torrent->isFinished() && !m_torrent->isStopped() && !m_torrent->isQueued() && !m_torrent->isChecking())
{ {
// Pieces availability // Pieces availability
showPiecesAvailability(true); 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) if (torrent == m_torrent)
m_piecesAvailability->setAvailability(pieceAvailability); m_piecesAvailability->setAvailability(pieceAvailability);
@ -496,9 +497,8 @@ void PropertiesWidget::loadDynamicData()
qreal progress = m_torrent->progress() * 100.; qreal progress = m_torrent->progress() * 100.;
m_ui->labelProgressVal->setText(Utils::String::fromDouble(progress, 1) + u'%'); 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); m_downloadedPieces->setProgress(m_torrent->pieces(), downloadingPieces);
}); });
} }
@ -525,7 +525,7 @@ void PropertiesWidget::loadUrlSeeds()
return; return;
using TorrentPtr = QPointer<BitTorrent::Torrent>; 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) if (torrent != m_torrent)
return; 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='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()); u"<div style='background-color: \"%1\"; font-weight: bold; color: \"%2\";'>%3</div>"_s.arg(highlightedBaseColor, highlightedBaseTextColor, article->title());
if (article->date().isValid()) 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()) 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()); html += u"<div style='background-color: \"%1\";'><b>%2</b>%3</div>"_s.arg(alternateBaseColor, tr("Feed: "), article->feed()->title());
if (!article->author().isEmpty()) if (!article->author().isEmpty())

View file

@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * 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> * Copyright (C) 2006-2012 Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -33,6 +33,7 @@
#include <QFileIconProvider> #include <QFileIconProvider>
#include <QFileInfo> #include <QFileInfo>
#include <QFuture>
#include <QIcon> #include <QIcon>
#include <QMimeData> #include <QMimeData>
#include <QPointer> #include <QPointer>
@ -219,7 +220,8 @@ void TorrentContentModel::updateFilesAvailability()
Q_ASSERT(m_contentHandler && m_contentHandler->hasMetadata()); Q_ASSERT(m_contentHandler && m_contentHandler->hasMetadata());
using HandlerPtr = QPointer<BitTorrent::TorrentContentHandler>; 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) if (handler != m_contentHandler)
return; return;

View file

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

View file

@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * 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> * Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -42,6 +42,7 @@
#include <QColor> #include <QColor>
#include <QDateTime> #include <QDateTime>
#include <QFuture>
#include <QList> #include <QList>
#include <QPointer> #include <QPointer>
#include <QScopeGuard> #include <QScopeGuard>
@ -309,7 +310,7 @@ void TrackerListModel::populate()
m_items->emplace_back(std::make_shared<Item>(u"** [LSD] **", privateTorrentMessage)); m_items->emplace_back(std::make_shared<Item>(u"** [LSD] **", privateTorrentMessage));
using TorrentPtr = QPointer<const BitTorrent::Torrent>; 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) if (torrent != m_torrent)
return; return;

View file

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

View file

@ -312,10 +312,7 @@ void TransferListWidget::torrentDoubleClicked()
case PREVIEW_FILE: case PREVIEW_FILE:
if (torrentContainsPreviewableFiles(torrent)) if (torrentContainsPreviewableFiles(torrent))
{ {
auto *dialog = new PreviewSelectDialog(this, torrent); openPreviewSelectDialog(torrent);
dialog->setAttribute(Qt::WA_DeleteOnClose);
connect(dialog, &PreviewSelectDialog::readyToPreviewFile, this, &TransferListWidget::previewFile);
dialog->show();
} }
else else
{ {
@ -617,10 +614,7 @@ void TransferListWidget::previewSelectedTorrents()
{ {
if (torrentContainsPreviewableFiles(torrent)) if (torrentContainsPreviewableFiles(torrent))
{ {
auto *dialog = new PreviewSelectDialog(this, torrent); openPreviewSelectDialog(torrent);
dialog->setAttribute(Qt::WA_DeleteOnClose);
connect(dialog, &PreviewSelectDialog::readyToPreviewFile, this, &TransferListWidget::previewFile);
dialog->show();
} }
else else
{ {
@ -1449,3 +1443,13 @@ void TransferListWidget::wheelEvent(QWheelEvent *event)
QTreeView::wheelEvent(event); // event delegated to base class 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 dragMoveEvent(QDragMoveEvent *event) override;
void dropEvent(QDropEvent *event) override; void dropEvent(QDropEvent *event) override;
void wheelEvent(QWheelEvent *event) override; void wheelEvent(QWheelEvent *event) override;
void openPreviewSelectDialog(const BitTorrent::Torrent *torrent);
QModelIndex mapToSource(const QModelIndex &index) const; QModelIndex mapToSource(const QModelIndex &index) const;
QModelIndexList mapToSource(const QModelIndexList &indexes) const; QModelIndexList mapToSource(const QModelIndexList &indexes) const;
QModelIndex mapFromSource(const QModelIndex &index) const; QModelIndex mapFromSource(const QModelIndex &index) const;

View file

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

View file

@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -28,6 +28,7 @@
#include "synccontroller.h" #include "synccontroller.h"
#include <QFuture>
#include <QJsonArray> #include <QJsonArray>
#include <QJsonObject> #include <QJsonObject>
#include <QMetaObject> #include <QMetaObject>
@ -745,7 +746,7 @@ void SyncController::torrentPeersAction()
QVariantMap data; QVariantMap data;
QVariantHash peers; QVariantHash peers;
const QList<BitTorrent::PeerInfo> peersList = torrent->peers(); const QList<BitTorrent::PeerInfo> peersList = torrent->fetchPeerInfo().takeResult();
bool resolvePeerCountries = Preferences::instance()->resolvePeerCountries(); bool resolvePeerCountries = Preferences::instance()->resolvePeerCountries();

View file

@ -1,6 +1,6 @@
/* /*
* Bittorrent Client using Qt and libtorrent. * 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -32,6 +32,7 @@
#include <functional> #include <functional>
#include <QBitArray> #include <QBitArray>
#include <QFuture>
#include <QJsonArray> #include <QJsonArray>
#include <QJsonObject> #include <QJsonObject>
#include <QList> #include <QList>
@ -180,9 +181,11 @@ namespace
QJsonArray getStickyTrackers(const BitTorrent::Torrent *const torrent) QJsonArray getStickyTrackers(const BitTorrent::Torrent *const torrent)
{ {
int seedsDHT = 0, seedsPeX = 0, seedsLSD = 0, leechesDHT = 0, leechesPeX = 0, leechesLSD = 0; 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()) if (peer.isSeed())
{ {
@ -520,8 +523,8 @@ void TorrentsController::propertiesAction()
{KEY_PROP_SEEDS_TOTAL, torrent->totalSeedsCount()}, {KEY_PROP_SEEDS_TOTAL, torrent->totalSeedsCount()},
{KEY_PROP_PEERS, torrent->leechsCount()}, {KEY_PROP_PEERS, torrent->leechsCount()},
{KEY_PROP_PEERS_TOTAL, torrent->totalLeechersCount()}, {KEY_PROP_PEERS_TOTAL, torrent->totalLeechersCount()},
{KEY_PROP_RATIO, ((ratio > BitTorrent::Torrent::MAX_RATIO) ? -1 : ratio)}, {KEY_PROP_RATIO, ((ratio >= BitTorrent::Torrent::MAX_RATIO) ? -1 : ratio)},
{KEY_PROP_POPULARITY, ((popularity > BitTorrent::Torrent::MAX_RATIO) ? -1 : popularity)}, {KEY_PROP_POPULARITY, ((popularity >= BitTorrent::Torrent::MAX_RATIO) ? -1 : popularity)},
{KEY_PROP_REANNOUNCE, torrent->nextAnnounce()}, {KEY_PROP_REANNOUNCE, torrent->nextAnnounce()},
{KEY_PROP_TOTAL_SIZE, torrent->totalSize()}, {KEY_PROP_TOTAL_SIZE, torrent->totalSize()},
{KEY_PROP_PIECES_NUM, torrent->piecesCount()}, {KEY_PROP_PIECES_NUM, torrent->piecesCount()},
@ -727,7 +730,7 @@ void TorrentsController::filesAction()
{ {
const QList<BitTorrent::DownloadPriority> priorities = torrent->filePriorities(); const QList<BitTorrent::DownloadPriority> priorities = torrent->filePriorities();
const QList<qreal> fp = torrent->filesProgress(); 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(); const BitTorrent::TorrentInfo info = torrent->info();
for (const int index : asConst(fileIndexes)) for (const int index : asConst(fileIndexes))
{ {
@ -796,7 +799,7 @@ void TorrentsController::pieceStatesAction()
for (int i = 0; i < states.size(); ++i) for (int i = 0; i < states.size(); ++i)
pieceStates.append(static_cast<int>(states[i]) * 2); 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) for (int i = 0; i < states.size(); ++i)
{ {
if (dlstates[i]) if (dlstates[i])

View file

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

View file

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

View file

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

View file

@ -22,15 +22,15 @@
} }
}); });
$("urls").focus(); document.getElementById("urls").focus();
$("addWebSeedsButton").addEventListener("click", (e) => { document.getElementById("addWebSeedsButton").addEventListener("click", (e) => {
e.stopPropagation(); e.stopPropagation();
fetch("api/v2/torrents/addWebSeeds", { fetch("api/v2/torrents/addWebSeeds", {
method: "POST", method: "POST",
body: new URLSearchParams({ body: new URLSearchParams({
hash: new URLSearchParams(window.location.search).get("hash"), 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) => { .then((response) => {

View file

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

View file

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

View file

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

View file

@ -16,14 +16,14 @@
const searchParams = new URLSearchParams(window.location.search); const searchParams = new URLSearchParams(window.location.search);
const host = searchParams.get("host"); 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(); document.getElementById("cancelBtn").focus();
$("cancelBtn").addEventListener("click", (e) => { document.getElementById("cancelBtn").addEventListener("click", (e) => {
e.stopPropagation(); e.stopPropagation();
window.parent.qBittorrent.Client.closeFrameWindow(window); window.parent.qBittorrent.Client.closeFrameWindow(window);
}); });
$("confirmBtn").addEventListener("click", (e) => { document.getElementById("confirmBtn").addEventListener("click", (e) => {
e.stopPropagation(); e.stopPropagation();
fetch("api/v2/torrents/removeTrackers", { fetch("api/v2/torrents/removeTrackers", {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -55,7 +55,7 @@ window.qBittorrent.Download ??= (() => {
const option = document.createElement("option"); const option = document.createElement("option");
option.value = category.name; option.value = category.name;
option.textContent = 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(); const pref = window.parent.qBittorrent.Cache.preferences.get();
defaultSavePath = pref.save_path; defaultSavePath = pref.save_path;
$("savepath").value = defaultSavePath; document.getElementById("savepath").value = defaultSavePath;
$("startTorrent").checked = !pref.add_stopped_enabled; document.getElementById("startTorrent").checked = !pref.add_stopped_enabled;
$("addToTopOfQueue").checked = pref.add_to_top_of_queue; document.getElementById("addToTopOfQueue").checked = pref.add_to_top_of_queue;
if (pref.auto_tmm_enabled) { if (pref.auto_tmm_enabled) {
$("autoTMM").selectedIndex = 1; document.getElementById("autoTMM").selectedIndex = 1;
$("savepath").disabled = true; document.getElementById("savepath").disabled = true;
} }
else { else {
$("autoTMM").selectedIndex = 0; document.getElementById("autoTMM").selectedIndex = 0;
} }
if (pref.torrent_stop_condition === "MetadataReceived") if (pref.torrent_stop_condition === "MetadataReceived")
$("stopCondition").selectedIndex = 1; document.getElementById("stopCondition").selectedIndex = 1;
else if (pref.torrent_stop_condition === "FilesChecked") else if (pref.torrent_stop_condition === "FilesChecked")
$("stopCondition").selectedIndex = 2; document.getElementById("stopCondition").selectedIndex = 2;
else else
$("stopCondition").selectedIndex = 0; document.getElementById("stopCondition").selectedIndex = 0;
if (pref.torrent_content_layout === "Subfolder") if (pref.torrent_content_layout === "Subfolder")
$("contentLayout").selectedIndex = 1; document.getElementById("contentLayout").selectedIndex = 1;
else if (pref.torrent_content_layout === "NoSubfolder") else if (pref.torrent_content_layout === "NoSubfolder")
$("contentLayout").selectedIndex = 2; document.getElementById("contentLayout").selectedIndex = 2;
else else
$("contentLayout").selectedIndex = 0; document.getElementById("contentLayout").selectedIndex = 0;
}; };
const changeCategorySelect = (item) => { const changeCategorySelect = (item) => {
@ -97,41 +97,41 @@ window.qBittorrent.Download ??= (() => {
item.nextElementSibling.value = ""; item.nextElementSibling.value = "";
item.nextElementSibling.select(); item.nextElementSibling.select();
if ($("autoTMM").selectedIndex === 1) if (document.getElementById("autoTMM").selectedIndex === 1)
$("savepath").value = defaultSavePath; document.getElementById("savepath").value = defaultSavePath;
} }
else { else {
item.nextElementSibling.hidden = true; item.nextElementSibling.hidden = true;
const text = item.options[item.selectedIndex].textContent; const text = item.options[item.selectedIndex].textContent;
item.nextElementSibling.value = text; item.nextElementSibling.value = text;
if ($("autoTMM").selectedIndex === 1) { if (document.getElementById("autoTMM").selectedIndex === 1) {
const categoryName = item.value; const categoryName = item.value;
const category = categories[categoryName]; const category = categories[categoryName];
let savePath = defaultSavePath; let savePath = defaultSavePath;
if (category !== undefined) if (category !== undefined)
savePath = (category["savePath"] !== "") ? category["savePath"] : `${defaultSavePath}/${categoryName}`; savePath = (category["savePath"] !== "") ? category["savePath"] : `${defaultSavePath}/${categoryName}`;
$("savepath").value = savePath; document.getElementById("savepath").value = savePath;
} }
} }
}; };
const changeTMM = (item) => { const changeTMM = (item) => {
if (item.selectedIndex === 1) { 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 categoryName = categorySelect.options[categorySelect.selectedIndex].value;
const category = categories[categoryName]; const category = categories[categoryName];
$("savepath").value = (category === undefined) ? "" : category["savePath"]; document.getElementById("savepath").value = (category === undefined) ? "" : category["savePath"];
} }
else { else {
$("savepath").disabled = false; document.getElementById("savepath").disabled = false;
$("savepath").value = defaultSavePath; document.getElementById("savepath").value = defaultSavePath;
} }
}; };
$(window).addEventListener("load", async () => { window.addEventListener("load", async () => {
// user might load this page directly (via browser magnet handler) // user might load this page directly (via browser magnet handler)
// so wait for crucial initialization to complete // so wait for crucial initialization to complete
await window.parent.qBittorrent.Client.initializeCaches(); 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); Object.freeze(TriState);
const FileTree = new Class({ class FileTree {
root: null, #root = null;
nodeMap: {}, #nodeMap = {}; // Object with Number as keys is faster than anything
setRoot: function(root) { setRoot(root) {
this.root = root; this.#root = root;
this.generateNodeMap(root); this.#generateNodeMap(root);
if (this.root.isFolder) if (this.#root.isFolder)
this.root.calculateSize(); this.#root.calculateSize();
}, }
getRoot: function() { getRoot() {
return this.root; return this.#root;
}, }
generateNodeMap: function(root) { #generateNodeMap(root) {
const stack = [root]; const stack = [root];
while (stack.length > 0) { while (stack.length > 0) {
const node = stack.pop(); const node = stack.pop();
// don't store root node in map // don't store root node in map
if (node.root !== null) if (node.root !== null)
this.nodeMap[node.rowId] = node; this.#nodeMap[node.rowId] = node;
stack.push(...node.children); stack.push(...node.children);
} }
}, }
getNode: function(rowId) { getNode(rowId) {
return (this.nodeMap[rowId] === undefined) // TODO: enforce caller sites to pass `rowId` as number and not string
? null const value = this.#nodeMap[Number(rowId)];
: this.nodeMap[rowId]; return (value !== undefined) ? value : null;
}, }
getRowId: (node) => { getRowId(node) {
return node.rowId; return node.rowId;
}, }
/** /**
* Returns the nodes in DFS in-order * Returns the nodes in DFS in-order
*/ */
toArray: function() { toArray() {
const ret = []; const ret = [];
const stack = this.root.children.toReversed(); const stack = this.#root.children.toReversed();
while (stack.length > 0) { while (stack.length > 0) {
const node = stack.pop(); const node = stack.pop();
ret.push(node); ret.push(node);
@ -108,45 +108,40 @@ window.qBittorrent.FileTree ??= (() => {
} }
return ret; return ret;
} }
}); }
const FileNode = new Class({ class FileNode {
name: "", name = "";
path: "", path = "";
rowId: null, rowId = null;
size: 0, size = 0;
checked: TriState.Unchecked, checked = TriState.Unchecked;
remaining: 0, remaining = 0;
progress: 0, progress = 0;
priority: FilePriority.Normal, priority = FilePriority.Normal;
availability: 0, availability = 0;
depth: 0, depth = 0;
root: null, root = null;
data: null, data = null;
isFolder: false, isFolder = false;
children: [], children = [];
}); }
const FolderNode = new Class({
Extends: FileNode,
class FolderNode extends FileNode {
/** /**
* Will automatically tick the checkbox for a folder if all subfolders and files are also ticked * Will automatically tick the checkbox for a folder if all subfolders and files are also ticked
*/ */
autoCheckFolders: true, autoCheckFolders = true;
isFolder = true;
initialize: function() { addChild(node) {
this.isFolder = true;
},
addChild: function(node) {
this.children.push(node); this.children.push(node);
}, }
/** /**
* Calculate size of node and its children * Calculate size of node and its children
*/ */
calculateSize: function() { calculateSize() {
const stack = [this]; const stack = [this];
const visited = []; const visited = [];
@ -202,7 +197,7 @@ window.qBittorrent.FileTree ??= (() => {
stack.pop(); stack.pop();
} }
} }
}); }
return exports(); return exports();
})(); })();

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -16,34 +16,34 @@
(() => { (() => {
MochaUI.initializeTabs("aboutTabs"); MochaUI.initializeTabs("aboutTabs");
$("aboutAboutLink").addEventListener("click", () => { document.getElementById("aboutAboutLink").addEventListener("click", () => {
Array.prototype.forEach.call(document.querySelectorAll(".aboutTabContent"), (tab => tab.classList.add("invisible"))); 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"))); 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"))); 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"))); 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"))); 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"))); Array.prototype.forEach.call(document.querySelectorAll(".aboutTabContent"), (tab => tab.classList.add("invisible")));
$("aboutSoftwareUsedContent").classList.remove("invisible"); document.getElementById("aboutSoftwareUsedContent").classList.remove("invisible");
}); });
})(); })();
</script> </script>

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

@ -36,37 +36,37 @@
// Tabs // Tabs
MochaUI.initializeTabs("preferencesTabs"); 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"))); 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"))); 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"))); 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"))); 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"))); 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"))); 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"))); 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"))); Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible")));
$("AdvancedTab").classList.remove("invisible"); document.getElementById("AdvancedTab").classList.remove("invisible");
}); });
})(); })();
</script> </script>

View file

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

View file

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