Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display external address #20118

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
2 changes: 2 additions & 0 deletions src/base/bittorrent/session.h
Expand Up @@ -440,6 +440,8 @@ namespace BitTorrent
virtual qsizetype torrentsCount() const = 0;
virtual const SessionStatus &status() const = 0;
virtual const CacheStatus &cacheStatus() const = 0;
virtual QString getLastExternalIPv6Address() const = 0;
virtual QString getLastExternalIPv4Address() const = 0;
OdinVex marked this conversation as resolved.
Show resolved Hide resolved
virtual bool isListening() const = 0;

virtual MaxRatioAction maxRatioAction() const = 0;
Expand Down
32 changes: 27 additions & 5 deletions src/base/bittorrent/sessionimpl.cpp
Expand Up @@ -4795,6 +4795,16 @@ void SessionImpl::setTrackerFilteringEnabled(const bool enabled)
}
}

QString SessionImpl::getLastExternalIPv6Address() const
{
return m_lastExternalIPv6Address;
}

QString SessionImpl::getLastExternalIPv4Address() const
{
return m_lastExternalIPv4Address;
}

bool SessionImpl::isListening() const
{
return m_nativeSessionExtension->isSessionListening();
Expand Down Expand Up @@ -5793,15 +5803,27 @@ void SessionImpl::handleListenFailedAlert(const lt::listen_failed_alert *p)

void SessionImpl::handleExternalIPAlert(const lt::external_ip_alert *p)
{
const QString externalIP {toString(p->external_address)};
QString externalIP {toString(p->external_address)};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't look like you need to remove the const:

Suggested change
QString externalIP {toString(p->external_address)};
const QString externalIP {toString(p->external_address)};

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought I added that back with the latest commit.

LogMsg(tr("Detected external IP. IP: \"%1\"")
.arg(externalIP), Log::INFO);

if (m_lastExternalIP != externalIP)
if (externalIP.indexOf(u':') >= 0)
{
if (isReannounceWhenAddressChangedEnabled() && !m_lastExternalIP.isEmpty())
reannounceToAllTrackers();
m_lastExternalIP = externalIP;
if (m_lastExternalIPv6Address != externalIP)
{
if (isReannounceWhenAddressChangedEnabled() && !m_lastExternalIPv6Address.isEmpty())
reannounceToAllTrackers();
m_lastExternalIPv6Address = externalIP;
}
}
else
{
if (m_lastExternalIPv4Address != externalIP)
{
if (isReannounceWhenAddressChangedEnabled() && !m_lastExternalIPv4Address.isEmpty())
reannounceToAllTrackers();
m_lastExternalIPv4Address = externalIP;
}
}
}

Expand Down
6 changes: 5 additions & 1 deletion src/base/bittorrent/sessionimpl.h
Expand Up @@ -425,6 +425,9 @@ namespace BitTorrent
void topTorrentsQueuePos(const QVector<TorrentID> &ids) override;
void bottomTorrentsQueuePos(const QVector<TorrentID> &ids) override;

QString getLastExternalIPv6Address() const override;
QString getLastExternalIPv4Address() const override;

// Torrent interface
void handleTorrentNeedSaveResumeData(const TorrentImpl *torrent);
void handleTorrentSaveResumeDataRequested(const TorrentImpl *torrent);
Expand Down Expand Up @@ -773,7 +776,8 @@ namespace BitTorrent

QList<MoveStorageJob> m_moveStorageQueue;

QString m_lastExternalIP;
QString m_lastExternalIPv6Address;
QString m_lastExternalIPv4Address;

bool m_needUpgradeDownloadPath = false;

Expand Down
7 changes: 7 additions & 0 deletions src/gui/mainwindow.cpp
Expand Up @@ -1360,6 +1360,7 @@ void MainWindow::showStatusBar(bool show)
{
// Create status bar
m_statusBar = new StatusBar;
connect(m_statusBar.data(), &StatusBar::showExternalAddressesButtonClicked, this, &MainWindow::showExternalAddressesInLog);
connect(m_statusBar.data(), &StatusBar::connectionButtonClicked, this, &MainWindow::showConnectionSettings);
connect(m_statusBar.data(), &StatusBar::alternativeSpeedsButtonClicked, this, &MainWindow::toggleAlternativeSpeeds);
setStatusBar(m_statusBar);
Expand Down Expand Up @@ -1760,6 +1761,12 @@ void MainWindow::on_actionDonateMoney_triggered()
QDesktopServices::openUrl(QUrl(u"https://www.qbittorrent.org/donate"_s));
}

void MainWindow::showExternalAddressesInLog()
{
displayExecutionLogTab();
on_actionInformationMessages_triggered(true);
}

void MainWindow::showConnectionSettings()
{
on_actionOptions_triggered();
Expand Down
1 change: 1 addition & 0 deletions src/gui/mainwindow.h
Expand Up @@ -118,6 +118,7 @@ private slots:
bool unlockUI();
void notifyOfUpdate(const QString &);
void showConnectionSettings();
void showExternalAddressesInLog();
void minimizeWindow();
// Keyboard shortcuts
void createKeyboardShortcuts();
Expand Down
44 changes: 41 additions & 3 deletions src/gui/statusbar.cpp
Expand Up @@ -86,6 +86,15 @@ StatusBar::StatusBar(QWidget *parent)
m_upSpeedLbl->setStyleSheet(u"text-align:left;"_s);
m_upSpeedLbl->setMinimumWidth(200);

m_lastExternalAddressesLbl = new QPushButton(this);
m_lastExternalAddressesLbl->setText(tr("External Address(es): Detecting"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about changing "Detecting" to "N/A"?
Not all users have such large monitors as you, and among those who do, not all have the desire to stretch the qBittorrent window to the full screen and shake their heads left and right to view it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course, the IP address will still be longer. But in any case, all we can say about this is that the information about external address is currently "not available". IMO, "Detecting" looks speculative.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know how that would differentiate between "Not available...yet" and other states such as failed, but I do agree about 'Detecting' sounding speculative. Perhaps more information should be communicated to the frontend from the means that qBittorrent uses to detect. "Detecting/Detection failed" etc? As for how much space is used...at this rate it's looking like you want just external addresses printed and nothing else which, quite frankly, leaves me baffled as to what the information would be.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then again, some people use torrent clients on closed networks (so local IP address(es)), so maybe it can make sense.

m_lastExternalAddressesLbl->setIcon(UIThemeManager::instance()->getIcon(u"help-about"_s));
m_lastExternalAddressesLbl->setFlat(true);
m_lastExternalAddressesLbl->setFocusPolicy(Qt::NoFocus);
m_lastExternalAddressesLbl->setCursor(Qt::PointingHandCursor);
m_lastExternalAddressesLbl->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
connect(m_lastExternalAddressesLbl, &QAbstractButton::clicked, this, &StatusBar::showExternalAddressesButtonClicked);

m_DHTLbl = new QLabel(tr("DHT: %1 nodes").arg(0), this);
m_DHTLbl->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);

Expand Down Expand Up @@ -129,14 +138,21 @@ StatusBar::StatusBar(QWidget *parent)
#ifndef Q_OS_MACOS
statusSep4->setFrameShadow(QFrame::Raised);
#endif
layout->addWidget(m_DHTLbl);
QFrame *statusSep5 = new QFrame(this);
statusSep5->setFrameStyle(QFrame::VLine);
#ifndef Q_OS_MACOS
statusSep5->setFrameShadow(QFrame::Raised);
#endif
layout->addWidget(m_lastExternalAddressesLbl);
layout->addWidget(statusSep1);
layout->addWidget(m_connecStatusLblIcon);
layout->addWidget(m_DHTLbl);
layout->addWidget(statusSep2);
layout->addWidget(m_connecStatusLblIcon);
layout->addWidget(statusSep3);
layout->addWidget(m_altSpeedsBtn);
layout->addWidget(statusSep4);
layout->addWidget(m_dlSpeedLbl);
layout->addWidget(statusSep3);
layout->addWidget(statusSep5);
layout->addWidget(m_upSpeedLbl);

addPermanentWidget(container);
Expand Down Expand Up @@ -212,6 +228,27 @@ void StatusBar::updateDHTNodesNumber()
}
}

void StatusBar::updateExternalAddressesLabel()
{
QString lastExternalIPv4Address = BitTorrent::Session::instance()->getLastExternalIPv4Address();
QString lastExternalIPv6Address = BitTorrent::Session::instance()->getLastExternalIPv6Address();
OdinVex marked this conversation as resolved.
Show resolved Hide resolved
QString addressText = tr("External Address(es): Detecting");

if (!lastExternalIPv4Address.isEmpty() || !lastExternalIPv6Address.isEmpty())
{
if (!lastExternalIPv4Address.isEmpty() && !lastExternalIPv6Address.isEmpty())
addressText = tr("External Addresses: %1, %2").
arg(BitTorrent::Session::instance()->getLastExternalIPv4Address()).
arg(BitTorrent::Session::instance()->getLastExternalIPv6Address());
else
addressText = tr("External Address: %1%2").
arg(BitTorrent::Session::instance()->getLastExternalIPv4Address()).
arg(BitTorrent::Session::instance()->getLastExternalIPv6Address());
OdinVex marked this conversation as resolved.
Show resolved Hide resolved
}

m_lastExternalAddressesLbl->setText(addressText);
}

void StatusBar::updateSpeedLabels()
{
const BitTorrent::SessionStatus &sessionStatus = BitTorrent::Session::instance()->status();
Expand All @@ -235,6 +272,7 @@ void StatusBar::refresh()
{
updateConnectionStatus();
updateDHTNodesNumber();
updateExternalAddressesLabel();
updateSpeedLabels();
}

Expand Down
3 changes: 3 additions & 0 deletions src/gui/statusbar.h
Expand Up @@ -50,6 +50,7 @@ class StatusBar final : public QStatusBar
signals:
void alternativeSpeedsButtonClicked();
void connectionButtonClicked();
void showExternalAddressesButtonClicked();

public slots:
void showRestartRequired();
Expand All @@ -62,10 +63,12 @@ private slots:
private:
void updateConnectionStatus();
void updateDHTNodesNumber();
void updateExternalAddressesLabel();
void updateSpeedLabels();

QPushButton *m_dlSpeedLbl = nullptr;
QPushButton *m_upSpeedLbl = nullptr;
QPushButton *m_lastExternalAddressesLbl = nullptr;
QLabel *m_DHTLbl = nullptr;
QPushButton *m_connecStatusLblIcon = nullptr;
QPushButton *m_altSpeedsBtn = nullptr;
Expand Down
6 changes: 6 additions & 0 deletions src/webui/api/synccontroller.cpp
Expand Up @@ -82,6 +82,8 @@ namespace

// TransferInfo keys
const QString KEY_TRANSFER_CONNECTION_STATUS = u"connection_status"_s;
const QString KEY_TRANSFER_LAST_EXTERNAL_ADDRESS_V6 = u"last_external_address_v6"_s;
const QString KEY_TRANSFER_LAST_EXTERNAL_ADDRESS_V4 = u"last_external_address_v4"_s;
Comment on lines +85 to +86
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong order, keys are sorted alphabetically here.

Copy link
Author

@OdinVex OdinVex Dec 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... I didn't see anything that required it.

const QString KEY_TRANSFER_DHT_NODES = u"dht_nodes"_s;
const QString KEY_TRANSFER_DLDATA = u"dl_info_data"_s;
const QString KEY_TRANSFER_DLRATELIMIT = u"dl_rate_limit"_s;
Expand Down Expand Up @@ -161,6 +163,8 @@ namespace
map[KEY_TRANSFER_AVERAGE_TIME_QUEUE] = cacheStatus.averageJobTime;
map[KEY_TRANSFER_TOTAL_QUEUED_SIZE] = cacheStatus.queuedBytes;

map[KEY_TRANSFER_LAST_EXTERNAL_ADDRESS_V6] = session->getLastExternalIPv6Address();
map[KEY_TRANSFER_LAST_EXTERNAL_ADDRESS_V4] = session->getLastExternalIPv4Address();
map[KEY_TRANSFER_DHT_NODES] = sessionStatus.dhtNodes;
map[KEY_TRANSFER_CONNECTION_STATUS] = session->isListening()
? (sessionStatus.hasIncomingConnections ? u"connected"_s : u"firewalled"_s)
Expand Down Expand Up @@ -445,6 +449,8 @@ void SyncController::updateFreeDiskSpace(const qint64 freeDiskSpace)
// - "total_size": Size including unwanted data
// Server state map may contain the following keys:
// - "connection_status": connection status
// - "last_external_address_v6": last external address v6
// - "last_external_address_v4": last external address v4
// - "dht_nodes": DHT nodes count
// - "dl_info_data": bytes downloaded
// - "dl_info_speed": download speed
Expand Down
5 changes: 5 additions & 0 deletions src/webui/api/transfercontroller.cpp
Expand Up @@ -45,6 +45,8 @@ const QString KEY_TRANSFER_DLRATELIMIT = u"dl_rate_limit"_s;
const QString KEY_TRANSFER_UPSPEED = u"up_info_speed"_s;
const QString KEY_TRANSFER_UPDATA = u"up_info_data"_s;
const QString KEY_TRANSFER_UPRATELIMIT = u"up_rate_limit"_s;
const QString KEY_TRANSFER_LAST_EXTERNAL_ADDRESS_V6 = u"last_external_address_v6"_s;
const QString KEY_TRANSFER_LAST_EXTERNAL_ADDRESS_V4 = u"last_external_address_v4"_s;
const QString KEY_TRANSFER_DHT_NODES = u"dht_nodes"_s;
const QString KEY_TRANSFER_CONNECTION_STATUS = u"connection_status"_s;

Expand All @@ -57,6 +59,7 @@ const QString KEY_TRANSFER_CONNECTION_STATUS = u"connection_status"_s;
// - "up_info_data": Data uploaded this session
// - "dl_rate_limit": Download rate limit
// - "up_rate_limit": Upload rate limit
// - "external_address": external address
// - "dht_nodes": DHT nodes connected to
// - "connection_status": Connection status
void TransferController::infoAction()
Expand All @@ -71,6 +74,8 @@ void TransferController::infoAction()
dict[KEY_TRANSFER_UPDATA] = static_cast<qint64>(sessionStatus.totalPayloadUpload);
dict[KEY_TRANSFER_DLRATELIMIT] = BitTorrent::Session::instance()->downloadSpeedLimit();
dict[KEY_TRANSFER_UPRATELIMIT] = BitTorrent::Session::instance()->uploadSpeedLimit();
dict[KEY_TRANSFER_LAST_EXTERNAL_ADDRESS_V6] = BitTorrent::Session::instance()->getLastExternalIPv6Address();
dict[KEY_TRANSFER_LAST_EXTERNAL_ADDRESS_V4] = BitTorrent::Session::instance()->getLastExternalIPv4Address();
dict[KEY_TRANSFER_DHT_NODES] = static_cast<qint64>(sessionStatus.dhtNodes);
if (!BitTorrent::Session::instance()->isListening())
dict[KEY_TRANSFER_CONNECTION_STATUS] = u"disconnected"_s;
Expand Down
2 changes: 2 additions & 0 deletions src/webui/www/private/index.html
Expand Up @@ -243,6 +243,8 @@ <h1 class="applicationTitle">qBittorrent Web User Interface <span class="version
<tr>
<td id="freeSpaceOnDisk"></td>
<td class="statusBarSeparator"></td>
<td id="showExternalAddressesInLogViewerLink" style="cursor:pointer;"><img alt="QBT_TR(Show external addresses in log viewer)QBT_TR[CONTEXT=MainWindow]" title="QBT_TR(Show external addresses in log viewer)QBT_TR[CONTEXT=MainWindow]" src="images/help-about.svg" style="height: 1.5em; padding-right: 5px; margin-bottom: -4px;" /><span id="externalAddresses"></span></td>
<td class="statusBarSeparator"></td>
<td id="DHTNodes"></td>
<td class="statusBarSeparator"></td>
<td><img id="connectionStatus" alt="QBT_TR(Connection status: Firewalled)QBT_TR[CONTEXT=MainWindow]" title="QBT_TR(Connection status: Firewalled)QBT_TR[CONTEXT=MainWindow]" src="images/firewalled.svg" style="height: 1.5em;" /></td>
Expand Down
26 changes: 26 additions & 0 deletions src/webui/www/private/scripts/client.js
Expand Up @@ -843,6 +843,21 @@ window.addEvent('load', function() {
else
document.title = ("qBittorrent " + qbtVersion() + " QBT_TR(Web UI)QBT_TR[CONTEXT=OptionsDialog]");
$('freeSpaceOnDisk').set('html', 'QBT_TR(Free space: %1)QBT_TR[CONTEXT=HttpServer]'.replace("%1", window.qBittorrent.Misc.friendlyUnit(serverState.free_space_on_disk)));

let last_external_address_v4 = serverState.last_external_address_v4;
let last_external_address_v6 = serverState.last_external_address_v6;
Comment on lines +847 to +848
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let last_external_address_v4 = serverState.last_external_address_v4;
let last_external_address_v6 = serverState.last_external_address_v6;
const last_external_address_v4 = serverState.last_external_address_v4;
const last_external_address_v6 = serverState.last_external_address_v6;

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I followed the previous conventions used by qBittorrent for other variables used similarly.

let last_external_addresses = 'QBT_TR(External Address(es): Detecting)QBT_TR[CONTEXT=HttpServer]';

if (last_external_address_v4 !== "" || last_external_address_v6 !== "")
{
if (last_external_address_v4 !== "" && last_external_address_v6 !== "")
Comment on lines +851 to +853
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (last_external_address_v4 !== "" || last_external_address_v6 !== "")
{
if (last_external_address_v4 !== "" && last_external_address_v6 !== "")
if ((last_external_address_v4 !== "") || (last_external_address_v6 !== ""))
{
if ((last_external_address_v4 !== "") && (last_external_address_v6 !== ""))

last_external_addresses = 'QBT_TR(External Addresses: %1, %2)QBT_TR[CONTEXT=HttpServer]';
Copy link
Member

@Chocobo1 Chocobo1 Dec 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although unlikely, I would still suggest using other character for replacement specifier. Maybe $1, $2
See: https://en.wikipedia.org/wiki/IPv6_address#Scoped_literal_IPv6_addresses_(with_zone_index)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't think any device was allowed to start with a number, so I didn't think there any chance of running into %[0-9] with %[0-9] being some interface. I could be wrong but I thought no device could start with [0-9].

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, according to the linked article, Windows will use %[0-9] format:

The latter (using an interface number) is the standard syntax on Microsoft Windows ...

Copy link
Author

@OdinVex OdinVex Dec 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the WebUI, I believe it should work to do this in reverse-order. Ex:

$('externalAddresses').set('html', last_external_addresses.replace("%2", last_external_address_v6).replace("%1", last_external_address_v4));

Similarly I think the GUI should do the same (reverse order) and always specifically replace the first occurrence only. Edit: I'm away from rig for the day.

Copy link
Author

@OdinVex OdinVex Feb 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot to ask, does qB supply those interfacings or does qB just supply the IP address? If it's IP address then we don't need to account for which interface (unless interface is added to IP addresses). My only test case for this info has been Linux.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must've been thinking about another client then. Still, there isn't any way for a peer or tracker to know which interface the client is using, so the entire point seems moot.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still, there isn't any way for a peer or tracker to know which interface the client is using,

Sorry, I don't know much about IPv6. What exactly are you talking about when you mention the interface? About the zone identifier, e.g. %eth0?

Copy link
Author

@OdinVex OdinVex Feb 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Somewhere on this long thread someone mentioned something about not using % in Qt API calls because the IPv6 address might have the zone identifier reported and it'd break it but they're assuming that qBittorrent includes that information...when it gets that address from a remote server (peer/tracker/site). The remote endpoint wouldn't have a clue about which interface qBittorrent is using and won't report that. Edit: There was also suggestion around modifying the JavaScript implementation of that string, I can't remember what it was. I've got too much to do and qBittorrent isn't a high priority. The initial src offering was fine but there's no way to please everyone, so I've stuck to my ViolentMonkey script which does exactly what I want.

Edit: Too long a thread, unable to search and follow it anymore hardly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the IPv6 address might have the zone identifier reported

IIRC, Zone ID is "locally significant" (enables us to define out which interface we want to send some traffic) and there is no point to send it to remote host as part if its "external address". But we still can't be sure that it isn't sent in such a way (with Zone ID) so the question is how is it handled by libtorrent, i.e. can it provide we "external address" that mistakenly contains such Zone ID.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Someone familiar with libtorrent's API should weigh in. I resorted to a VM script, so I'm fine and qBittorrent can do with this PR as they want.

else
last_external_addresses = 'QBT_TR(External Address: %1%2)QBT_TR[CONTEXT=HttpServer]';
}

$('freeSpaceOnDisk').set('html', 'QBT_TR(Free space: %1)QBT_TR[CONTEXT=HttpServer]'.replace("%1", window.qBittorrent.Misc.friendlyUnit(serverState.free_space_on_disk)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

copy paste error?

Copy link
Author

@OdinVex OdinVex Dec 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. -_-; Too tired to address right now, will do later.

$('externalAddresses').set('html', last_external_addresses.replace("%1", last_external_address_v4).replace("%2", last_external_address_v6));
$('DHTNodes').set('html', 'QBT_TR(DHT: %1 nodes)QBT_TR[CONTEXT=StatusBar]'.replace("%1", serverState.dht_nodes));

// Statistics dialog
Expand Down Expand Up @@ -1024,6 +1039,17 @@ window.addEvent('load', function() {
updateTabDisplay();
});

$('showExternalAddressesInLogViewerLink').addEvent('click', function(e) {
showLogViewer = true;
LocalPreferences.set('show_log_viewer', showLogViewer.toString());
updateTabDisplay();
$("logTabLink").click();
$("logLevelSelect").options[2].selected = true;
window.qBittorrent.Log.logLevelChanged();
$("filterTextInput").value = 'QBT_TR(Detected external IP.)QBT_TR[CONTEXT=MainWindow]';
window.qBittorrent.Log.filterTextChanged();
});

const updateTabDisplay = function() {
if (showRssReader) {
$('showRssReaderLink').firstChild.style.opacity = '1';
Expand Down