Compare commits

...

6 Commits

Author SHA1 Message Date
Chocobo1
5c0010ac6c WebUI: prefer for loop over Array.forEach method
These were missed in 6ac0c5a8b8.
Also refactor the code a bit.

PR #23231.
2025-09-07 16:16:31 +08:00
Chocobo1
0a9316382a WebUI: fix invalid method
The FileList type has no `entries()` method. Use the generic function from `Array` instead.
Addresses https://github.com/qbittorrent/qBittorrent/pull/23182#discussion_r2319408410

Closes #23224.
2025-09-07 16:14:40 +08:00
dependabot[bot]
463ac253fd GHA CI: Bump actions version
PR #23208.

---
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-07 16:11:02 +08:00
Thomas (Tom) Piccirello
4ad93bafb2 Update Piccirello's copyright email
PR #23197.
2025-09-07 16:10:07 +08:00
Thomas (Tom) Piccirello
f651a311a4 WebUI: Fix add torrent spinner in Firefox
Firefox seems to have an issue where svgs loaded via background-url are not animated. Loading the svg directly as an img fixes this.

Related: #23074.
PR #23195.
2025-09-07 16:02:32 +08:00
Userdocs
3146a3c2f9 Fix compilation in C++23 mode
This adds c++23 support. In my testing it works for nox and desktop.

PR #23193.
2025-09-07 15:49:50 +08:00
27 changed files with 70 additions and 63 deletions

View File

@@ -16,7 +16,7 @@ jobs:
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
persist-credentials: false

View File

@@ -28,7 +28,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
persist-credentials: false

View File

@@ -15,7 +15,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
persist-credentials: false

View File

@@ -30,7 +30,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
persist-credentials: false

View File

@@ -21,7 +21,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
persist-credentials: false

View File

@@ -27,7 +27,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
persist-credentials: false

View File

@@ -25,7 +25,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
persist-credentials: false

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2018 Thomas Piccirello <thomas.piccirello@gmail.com>
* Copyright (C) 2018 Thomas Piccirello <thomas@piccirello.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2018 Thomas Piccirello <thomas.piccirello@gmail.com>
* Copyright (C) 2018 Thomas Piccirello <thomas@piccirello.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -132,7 +132,7 @@ try
const lt::entry torrentEntry = lt::write_torrent_file(m_ltAddTorrentParams);
const nonstd::expected<void, QString> result = Utils::IO::saveToFile(path, torrentEntry);
if (!result)
return result.get_unexpected();
return nonstd::make_unexpected(result.error());
return {};
}

View File

@@ -2780,7 +2780,7 @@ nonstd::expected<QByteArray, QString> TorrentImpl::exportToBuffer() const
{
const nonstd::expected<lt::entry, QString> preparationResult = exportTorrent();
if (!preparationResult)
return preparationResult.get_unexpected();
return nonstd::make_unexpected(preparationResult.error());
// usually torrent size should be smaller than 1 MB,
// however there are >100 MB v2/hybrid torrent files out in the wild
@@ -2794,11 +2794,11 @@ nonstd::expected<void, QString> TorrentImpl::exportToFile(const Path &path) cons
{
const nonstd::expected<lt::entry, QString> preparationResult = exportTorrent();
if (!preparationResult)
return preparationResult.get_unexpected();
return nonstd::make_unexpected(preparationResult.error());
const nonstd::expected<void, QString> saveResult = Utils::IO::saveToFile(path, preparationResult.value());
if (!saveResult)
return saveResult.get_unexpected();
return nonstd::make_unexpected(saveResult.error());
return {};
}

View File

@@ -1,7 +1,7 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2023-2025 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2018 Thomas Piccirello <thomas.piccirello@gmail.com>
* Copyright (C) 2018 Thomas Piccirello <thomas@piccirello.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -1,7 +1,7 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2023-2025 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2018 Thomas Piccirello <thomas.piccirello@gmail.com>
* Copyright (C) 2018 Thomas Piccirello <thomas@piccirello.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -141,7 +141,7 @@ nonstd::expected<Folder *, QString> Session::addFolder(const QString &path)
{
const nonstd::expected<Folder *, QString> result = prepareItemDest(path);
if (!result)
return result.get_unexpected();
return nonstd::make_unexpected(result.error());
auto *destFolder = result.value();
auto *folder = new Folder(path);
@@ -157,7 +157,7 @@ nonstd::expected<Feed *, QString> Session::addFeed(const QString &url, const QSt
const nonstd::expected<Folder *, QString> result = prepareItemDest(path);
if (!result)
return result.get_unexpected();
return nonstd::make_unexpected(result.error());
auto *destFolder = result.value();
auto *feed = new Feed(this, generateUID(), url, path, refreshInterval);
@@ -225,7 +225,7 @@ nonstd::expected<void, QString> Session::moveItem(Item *item, const QString &des
const nonstd::expected<Folder *, QString> result = prepareItemDest(destPath);
if (!result)
return result.get_unexpected();
return nonstd::make_unexpected(result.error());
auto *destFolder = result.value();
auto *srcFolder = static_cast<Folder *>(m_itemsByPath.value(Item::parentPath(item->path())));

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2017 Thomas Piccirello <thomas.piccirello@gmail.com>
* Copyright (C) 2017 Thomas Piccirello <thomas@piccirello.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2017 Thomas Piccirello <thomas.piccirello@gmail.com>
* Copyright (C) 2017 Thomas Piccirello <thomas@piccirello.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -1,7 +1,7 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2024 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2018 Thomas Piccirello <thomas.piccirello@gmail.com>
* Copyright (C) 2018 Thomas Piccirello <thomas@piccirello.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -1,7 +1,7 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2024 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2018 Thomas Piccirello <thomas.piccirello@gmail.com>
* Copyright (C) 2018 Thomas Piccirello <thomas@piccirello.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -131,6 +131,15 @@
background-color: initial;
}
#loadingSpinner {
position: absolute;
left: 6px;
bottom: 2px;
width: 16px;
height: 16px;
display: block;
}
</style>
</head>
@@ -396,7 +405,7 @@
</div>
</div>
<div id="submitbutton" style="display: flex; margin-top: 10px; align-items: center; position: relative;">
<div id="loadingSpinner" class="mochaSpinner" style="display: block; bottom: 2px;"></div>
<img id="loadingSpinner" src="images/spinner.svg" alt="" aria-hidden="true">
<div id="errorIcon" class="mochaErrorIcon invisible" style="bottom: 2px;"></div>
<span id="metadataStatus" style="padding-left: 28px;">Retrieving metadata</span>
<button id="saveTorrent" type="button" class="invisible" style="font-size: 1em;">QBT_TR(Save as .torrent file)QBT_TR[CONTEXT=AddNewTorrentDialog]</button>

View File

@@ -176,7 +176,7 @@ window.qBittorrent.Client ??= (() => {
const uploadTorrentFiles = (files) => {
const fileNames = [];
const formData = new FormData();
for (const [i, file] of files.entries()) {
for (const [i, file] of Array.prototype.entries.call(files)) {
fileNames.push(file.name);
// send dummy file name as file name won't be used and may not be encoded properly
formData.append("file", file, i);

View File

@@ -3138,7 +3138,7 @@ window.qBittorrent.DynamicTable ??= (() => {
img_path = "images/task-reject.svg";
break;
case "isLoading":
img_path = "images/spinner.gif";
img_path = "images/spinner.svg";
break;
case "unread":
img_path = "images/mail-inbox.svg";

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2019 Thomas Piccirello <thomas.piccirello@gmail.com>
* Copyright (C) 2019 Thomas Piccirello <thomas@piccirello.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2019 Thomas Piccirello <thomas.piccirello@gmail.com>
* Copyright (C) 2019 Thomas Piccirello <thomas@piccirello.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -1,7 +1,7 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2025 Mike Tzou (Chocobo1)
* Copyright (C) 2019 Thomas Piccirello <thomas.piccirello@gmail.com>
* Copyright (C) 2019 Thomas Piccirello <thomas@piccirello.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

@@ -1,6 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2018 Thomas Piccirello <thomas.piccirello@gmail.com>
* Copyright (C) 2018 Thomas Piccirello <thomas@piccirello.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View File

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

View File

@@ -33,40 +33,40 @@
"use strict";
(() => {
// Tabs
MochaUI.initializeTabs("preferencesTabs");
const showTab = (element) => {
for (const tab of document.querySelectorAll(".PrefTab")) {
if (tab === element)
tab.classList.remove("invisible");
else
tab.classList.add("invisible");
}
};
document.getElementById("PrefBehaviorLink").addEventListener("click", (e) => {
Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible")));
document.getElementById("BehaviorTab").classList.remove("invisible");
showTab(document.getElementById("BehaviorTab"));
});
document.getElementById("PrefDownloadsLink").addEventListener("click", (e) => {
Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible")));
document.getElementById("DownloadsTab").classList.remove("invisible");
showTab(document.getElementById("DownloadsTab"));
});
document.getElementById("PrefConnectionLink").addEventListener("click", (e) => {
Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible")));
document.getElementById("ConnectionTab").classList.remove("invisible");
showTab(document.getElementById("ConnectionTab"));
});
document.getElementById("PrefSpeedLink").addEventListener("click", (e) => {
Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible")));
document.getElementById("SpeedTab").classList.remove("invisible");
showTab(document.getElementById("SpeedTab"));
});
document.getElementById("PrefBittorrentLink").addEventListener("click", (e) => {
Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible")));
document.getElementById("BittorrentTab").classList.remove("invisible");
showTab(document.getElementById("BittorrentTab"));
});
document.getElementById("PrefRSSLink").addEventListener("click", (e) => {
Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible")));
document.getElementById("RSSTab").classList.remove("invisible");
showTab(document.getElementById("RSSTab"));
});
document.getElementById("PrefWebUILink").addEventListener("click", (e) => {
Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible")));
document.getElementById("WebUITab").classList.remove("invisible");
showTab(document.getElementById("WebUITab"));
});
document.getElementById("PrefAdvancedLink").addEventListener("click", (e) => {
Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible")));
document.getElementById("AdvancedTab").classList.remove("invisible");
showTab(document.getElementById("AdvancedTab"));
});
})();
</script>