From 7b3aa51bb16e242c6bf79f84fbe83f74e2029c38 Mon Sep 17 00:00:00 2001 From: skomerko <168652295+skomerko@users.noreply.github.com> Date: Sat, 12 Apr 2025 11:53:52 +0200 Subject: [PATCH 01/45] WebUI: Eliminate redundant DOM element queries --- src/webui/www/private/scripts/contextmenu.js | 4 ++-- src/webui/www/private/scripts/download.js | 2 +- src/webui/www/private/views/preferences.html | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/webui/www/private/scripts/contextmenu.js b/src/webui/www/private/scripts/contextmenu.js index 7831461bf..094fba5b3 100644 --- a/src/webui/www/private/scripts/contextmenu.js +++ b/src/webui/www/private/scripts/contextmenu.js @@ -190,7 +190,7 @@ window.qBittorrent.ContextMenu ??= (() => { e.stopPropagation(); } // record this as the trigger - this.options.element = $(el); + this.options.element = el; this.adjustMenuPosition(e); // show the menu this.show(); @@ -219,7 +219,7 @@ window.qBittorrent.ContextMenu ??= (() => { }); // hide on body click - $(document.body).addEventListener("click", () => { + document.body.addEventListener("click", () => { this.hide(); this.options.element = null; }); diff --git a/src/webui/www/private/scripts/download.js b/src/webui/www/private/scripts/download.js index e79d97978..38a4ce81e 100644 --- a/src/webui/www/private/scripts/download.js +++ b/src/webui/www/private/scripts/download.js @@ -131,7 +131,7 @@ window.qBittorrent.Download ??= (() => { } }; - $(window).addEventListener("load", async () => { + window.addEventListener("load", async () => { // user might load this page directly (via browser magnet handler) // so wait for crucial initialization to complete await window.parent.qBittorrent.Client.initializeCaches(); diff --git a/src/webui/www/private/views/preferences.html b/src/webui/www/private/views/preferences.html index 07109e68e..883efdbaa 100644 --- a/src/webui/www/private/views/preferences.html +++ b/src/webui/www/private/views/preferences.html @@ -3168,7 +3168,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD $("rowMarkOfTheWeb").style.display = "none"; $("networkInterface").addEventListener("change", function() { - updateInterfaceAddresses($(this).value, ""); + updateInterfaceAddresses(this.value, ""); }); loadPreferences(); From 411ca0f6684e3a1354b6c97ac4fc797e447f849b Mon Sep 17 00:00:00 2001 From: skomerko <168652295+skomerko@users.noreply.github.com> Date: Sat, 12 Apr 2025 11:57:27 +0200 Subject: [PATCH 02/45] WebUI: Use native function for selecting elements by ID --- src/webui/www/private/addpeers.html | 6 +- src/webui/www/private/addtrackers.html | 6 +- src/webui/www/private/addwebseeds.html | 6 +- .../www/private/confirmfeeddeletion.html | 6 +- src/webui/www/private/confirmruleclear.html | 6 +- .../www/private/confirmruledeletion.html | 6 +- .../www/private/confirmtrackerdeletion.html | 8 +- src/webui/www/private/download.html | 14 +- src/webui/www/private/downloadlimit.html | 6 +- src/webui/www/private/editfeedurl.html | 16 +- src/webui/www/private/edittracker.html | 10 +- src/webui/www/private/editwebseed.html | 10 +- src/webui/www/private/newcategory.html | 22 +- src/webui/www/private/newfeed.html | 12 +- src/webui/www/private/newfolder.html | 12 +- src/webui/www/private/newrule.html | 10 +- src/webui/www/private/newtag.html | 10 +- src/webui/www/private/rename.html | 10 +- src/webui/www/private/rename_feed.html | 16 +- src/webui/www/private/rename_file.html | 16 +- src/webui/www/private/rename_files.html | 112 +- src/webui/www/private/rename_rule.html | 14 +- src/webui/www/private/scripts/client.js | 280 ++-- src/webui/www/private/scripts/contextmenu.js | 12 +- src/webui/www/private/scripts/download.js | 44 +- src/webui/www/private/scripts/dynamicTable.js | 14 +- src/webui/www/private/scripts/mocha-init.js | 6 +- src/webui/www/private/scripts/piecesbar.js | 2 +- src/webui/www/private/scripts/progressbar.js | 2 +- src/webui/www/private/scripts/prop-files.js | 14 +- src/webui/www/private/scripts/prop-general.js | 122 +- src/webui/www/private/scripts/prop-peers.js | 6 +- .../www/private/scripts/prop-trackers.js | 4 +- .../www/private/scripts/prop-webseeds.js | 4 +- src/webui/www/private/scripts/search.js | 134 +- src/webui/www/private/scripts/speedslider.js | 76 +- src/webui/www/private/setlocation.html | 14 +- src/webui/www/private/shareratio.html | 44 +- src/webui/www/private/upload.html | 14 +- src/webui/www/private/uploadlimit.html | 6 +- src/webui/www/private/views/about.html | 14 +- src/webui/www/private/views/aboutToolbar.html | 24 +- .../private/views/installsearchplugin.html | 4 +- src/webui/www/private/views/log.html | 22 +- src/webui/www/private/views/preferences.html | 1186 ++++++++--------- .../www/private/views/preferencesToolbar.html | 32 +- src/webui/www/private/views/rss.html | 8 +- .../www/private/views/rssDownloader.html | 184 +-- 48 files changed, 1303 insertions(+), 1303 deletions(-) diff --git a/src/webui/www/private/addpeers.html b/src/webui/www/private/addpeers.html index ad645b3d9..cfca9c026 100644 --- a/src/webui/www/private/addpeers.html +++ b/src/webui/www/private/addpeers.html @@ -26,13 +26,13 @@ if (hash === null) return; - $("peers").focus(); + document.getElementById("peers").focus(); - $("addPeersOk").addEventListener("click", (e) => { + document.getElementById("addPeersOk").addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); - const peers = $("peers").value.trim().split(/[\r\n]+/); + const peers = document.getElementById("peers").value.trim().split(/[\r\n]+/); if (peers.length === 0) return; diff --git a/src/webui/www/private/addtrackers.html b/src/webui/www/private/addtrackers.html index 818f20f09..b11adf195 100644 --- a/src/webui/www/private/addtrackers.html +++ b/src/webui/www/private/addtrackers.html @@ -22,8 +22,8 @@ } }); - $("trackersUrls").focus(); - $("addTrackersButton").addEventListener("click", (e) => { + document.getElementById("trackersUrls").focus(); + document.getElementById("addTrackersButton").addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); @@ -31,7 +31,7 @@ method: "POST", body: new URLSearchParams({ hash: new URLSearchParams(window.location.search).get("hash"), - urls: $("trackersUrls").value + urls: document.getElementById("trackersUrls").value }) }) .then((response) => { diff --git a/src/webui/www/private/addwebseeds.html b/src/webui/www/private/addwebseeds.html index c87c17146..e43b10fb3 100644 --- a/src/webui/www/private/addwebseeds.html +++ b/src/webui/www/private/addwebseeds.html @@ -22,15 +22,15 @@ } }); - $("urls").focus(); - $("addWebSeedsButton").addEventListener("click", (e) => { + document.getElementById("urls").focus(); + document.getElementById("addWebSeedsButton").addEventListener("click", (e) => { e.stopPropagation(); fetch("api/v2/torrents/addWebSeeds", { method: "POST", body: new URLSearchParams({ hash: new URLSearchParams(window.location.search).get("hash"), - urls: $("urls").value.split("\n").map(w => encodeURIComponent(w.trim())).filter(w => (w.length > 0)).join("|") + urls: document.getElementById("urls").value.split("\n").map(w => encodeURIComponent(w.trim())).filter(w => (w.length > 0)).join("|") }) }) .then((response) => { diff --git a/src/webui/www/private/confirmfeeddeletion.html b/src/webui/www/private/confirmfeeddeletion.html index b0f2abe5c..b4f209b36 100644 --- a/src/webui/www/private/confirmfeeddeletion.html +++ b/src/webui/www/private/confirmfeeddeletion.html @@ -13,13 +13,13 @@ "use strict"; window.addEventListener("DOMContentLoaded", () => { - $("cancelBtn").focus(); - $("cancelBtn").addEventListener("click", (e) => { + document.getElementById("cancelBtn").focus(); + document.getElementById("cancelBtn").addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); window.parent.qBittorrent.Client.closeFrameWindow(window); }); - $("confirmBtn").addEventListener("click", (e) => { + document.getElementById("confirmBtn").addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); diff --git a/src/webui/www/private/confirmruleclear.html b/src/webui/www/private/confirmruleclear.html index 9817d3c1d..57c3deb6b 100644 --- a/src/webui/www/private/confirmruleclear.html +++ b/src/webui/www/private/confirmruleclear.html @@ -13,13 +13,13 @@ "use strict"; window.addEventListener("DOMContentLoaded", () => { - $("cancelBtn").focus(); - $("cancelBtn").addEventListener("click", (e) => { + document.getElementById("cancelBtn").focus(); + document.getElementById("cancelBtn").addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); window.parent.qBittorrent.Client.closeFrameWindow(window); }); - $("confirmBtn").addEventListener("click", (e) => { + document.getElementById("confirmBtn").addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); diff --git a/src/webui/www/private/confirmruledeletion.html b/src/webui/www/private/confirmruledeletion.html index cf9f7d874..728c7defc 100644 --- a/src/webui/www/private/confirmruledeletion.html +++ b/src/webui/www/private/confirmruledeletion.html @@ -13,13 +13,13 @@ "use strict"; window.addEventListener("DOMContentLoaded", () => { - $("cancelBtn").focus(); - $("cancelBtn").addEventListener("click", (e) => { + document.getElementById("cancelBtn").focus(); + document.getElementById("cancelBtn").addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); window.parent.qBittorrent.Client.closeFrameWindow(window); }); - $("confirmBtn").addEventListener("click", (e) => { + document.getElementById("confirmBtn").addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); diff --git a/src/webui/www/private/confirmtrackerdeletion.html b/src/webui/www/private/confirmtrackerdeletion.html index 4324f528f..46ea918e8 100644 --- a/src/webui/www/private/confirmtrackerdeletion.html +++ b/src/webui/www/private/confirmtrackerdeletion.html @@ -16,14 +16,14 @@ const searchParams = new URLSearchParams(window.location.search); const host = searchParams.get("host"); - $("confirmDeleteTrackerText").textContent = "QBT_TR(Are you sure you want to remove tracker %1 from all torrents?)QBT_TR[CONTEXT=TrackersFilterWidget]".replace("%1", host); + document.getElementById("confirmDeleteTrackerText").textContent = "QBT_TR(Are you sure you want to remove tracker %1 from all torrents?)QBT_TR[CONTEXT=TrackersFilterWidget]".replace("%1", host); - $("cancelBtn").focus(); - $("cancelBtn").addEventListener("click", (e) => { + document.getElementById("cancelBtn").focus(); + document.getElementById("cancelBtn").addEventListener("click", (e) => { e.stopPropagation(); window.parent.qBittorrent.Client.closeFrameWindow(window); }); - $("confirmBtn").addEventListener("click", (e) => { + document.getElementById("confirmBtn").addEventListener("click", (e) => { e.stopPropagation(); fetch("api/v2/torrents/removeTrackers", { diff --git a/src/webui/www/private/download.html b/src/webui/www/private/download.html index ecd1bb6bb..ca9a63b79 100644 --- a/src/webui/www/private/download.html +++ b/src/webui/www/private/download.html @@ -167,22 +167,22 @@ if (encodedUrls !== null) { const urls = encodedUrls.split("|").map(decodeURIComponent); if (urls.length > 0) - $("urls").value = urls.join("\n"); + document.getElementById("urls").value = urls.join("\n"); } let submitted = false; - $("downloadForm").addEventListener("submit", () => { - $("startTorrentHidden").value = $("startTorrent").checked ? "false" : "true"; + document.getElementById("downloadForm").addEventListener("submit", () => { + document.getElementById("startTorrentHidden").value = document.getElementById("startTorrent").checked ? "false" : "true"; - $("dlLimitHidden").value = Number($("dlLimitText").value) * 1024; - $("upLimitHidden").value = Number($("upLimitText").value) * 1024; + document.getElementById("dlLimitHidden").value = Number(document.getElementById("dlLimitText").value) * 1024; + document.getElementById("upLimitHidden").value = Number(document.getElementById("upLimitText").value) * 1024; - $("download_spinner").style.display = "block"; + document.getElementById("download_spinner").style.display = "block"; submitted = true; }); - $("download_frame").addEventListener("load", () => { + document.getElementById("download_frame").addEventListener("load", () => { if (submitted) window.parent.qBittorrent.Client.closeFrameWindow(window); }); diff --git a/src/webui/www/private/downloadlimit.html b/src/webui/www/private/downloadlimit.html index d703cf79e..3cc02ebfa 100644 --- a/src/webui/www/private/downloadlimit.html +++ b/src/webui/www/private/downloadlimit.html @@ -37,7 +37,7 @@ switch (event.key) { case "Enter": event.preventDefault(); - $("applyButton").click(); + document.getElementById("applyButton").click(); break; case "Escape": event.preventDefault(); @@ -48,7 +48,7 @@ const hashes = new URLSearchParams(window.location.search).get("hashes").split("|"); const setDlLimit = () => { - const limit = Number($("dllimitUpdatevalue").value) * 1024; + const limit = Number(document.getElementById("dllimitUpdatevalue").value) * 1024; if (hashes[0] === "global") { fetch("api/v2/transfer/setDownloadLimit", { method: "POST", @@ -81,7 +81,7 @@ } }; - $("dllimitUpdatevalue").focus(); + document.getElementById("dllimitUpdatevalue").focus(); MochaUI.addDlLimitSlider(hashes); diff --git a/src/webui/www/private/editfeedurl.html b/src/webui/www/private/editfeedurl.html index 83618a0b5..c92a0b48f 100644 --- a/src/webui/www/private/editfeedurl.html +++ b/src/webui/www/private/editfeedurl.html @@ -18,7 +18,7 @@ switch (event.key) { case "Enter": event.preventDefault(); - $("submitButton").click(); + document.getElementById("submitButton").click(); break; case "Escape": event.preventDefault(); @@ -30,16 +30,16 @@ const searchParams = new URLSearchParams(window.location.search); const currentUrl = searchParams.get("url"); - $("url").value = currentUrl; - $("url").focus(); - $("url").setSelectionRange(0, currentUrl.length); + document.getElementById("url").value = currentUrl; + document.getElementById("url").focus(); + document.getElementById("url").setSelectionRange(0, currentUrl.length); - $("submitButton").addEventListener("click", (e) => { + document.getElementById("submitButton").addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); // check field - const newUrl = $("url").value.trim(); + const newUrl = document.getElementById("url").value.trim(); if (newUrl === "") { alert("QBT_TR(URL cannot be empty)QBT_TR[CONTEXT=RSSWidget]"); return; @@ -50,7 +50,7 @@ return; } - $("submitButton").disabled = true; + document.getElementById("submitButton").disabled = true; fetch("api/v2/rss/setFeedURL", { method: "POST", @@ -64,7 +64,7 @@ alert((response.status === 409) ? await response.text() : "QBT_TR(Unable to update URL)QBT_TR[CONTEXT=RSSWidget]"); - $("submitButton").disabled = false; + document.getElementById("submitButton").disabled = false; return; } diff --git a/src/webui/www/private/edittracker.html b/src/webui/www/private/edittracker.html index 2b4ff2553..fd14c8217 100644 --- a/src/webui/www/private/edittracker.html +++ b/src/webui/www/private/edittracker.html @@ -17,7 +17,7 @@ switch (event.key) { case "Enter": event.preventDefault(); - $("editTrackerButton").click(); + document.getElementById("editTrackerButton").click(); break; case "Escape": event.preventDefault(); @@ -31,10 +31,10 @@ if (currentUrl === null) return; - $("trackerUrl").value = currentUrl; - $("trackerUrl").focus(); + document.getElementById("trackerUrl").value = currentUrl; + document.getElementById("trackerUrl").focus(); - $("editTrackerButton").addEventListener("click", (e) => { + document.getElementById("editTrackerButton").addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); @@ -43,7 +43,7 @@ body: new URLSearchParams({ hash: searchParams.get("hash"), origUrl: currentUrl, - newUrl: $("trackerUrl").value + newUrl: document.getElementById("trackerUrl").value }) }) .then((response) => { diff --git a/src/webui/www/private/editwebseed.html b/src/webui/www/private/editwebseed.html index ef6b70998..3b4ef53e5 100644 --- a/src/webui/www/private/editwebseed.html +++ b/src/webui/www/private/editwebseed.html @@ -17,7 +17,7 @@ switch (event.key) { case "Enter": event.preventDefault(); - $("editWebSeedButton").click(); + document.getElementById("editWebSeedButton").click(); break; case "Escape": event.preventDefault(); @@ -28,10 +28,10 @@ const searchParams = new URLSearchParams(window.location.search); const origUrl = searchParams.get("url"); - $("url").value = decodeURIComponent(origUrl); - $("url").focus(); + document.getElementById("url").value = decodeURIComponent(origUrl); + document.getElementById("url").focus(); - $("editWebSeedButton").addEventListener("click", (e) => { + document.getElementById("editWebSeedButton").addEventListener("click", (e) => { e.stopPropagation(); fetch("api/v2/torrents/editWebSeed", { @@ -39,7 +39,7 @@ body: new URLSearchParams({ hash: searchParams.get("hash"), origUrl: origUrl, - newUrl: encodeURIComponent($("url").value.trim()) + newUrl: encodeURIComponent(document.getElementById("url").value.trim()) }) }) .then((response) => { diff --git a/src/webui/www/private/newcategory.html b/src/webui/www/private/newcategory.html index b2ec949fa..ceda85359 100644 --- a/src/webui/www/private/newcategory.html +++ b/src/webui/www/private/newcategory.html @@ -19,7 +19,7 @@ switch (event.key) { case "Enter": event.preventDefault(); - $("categoryNameButton").click(); + document.getElementById("categoryNameButton").click(); break; case "Escape": event.preventDefault(); @@ -38,25 +38,25 @@ if (!uriCategoryName) return; - $("categoryName").disabled = true; - $("categoryName").value = window.qBittorrent.Misc.escapeHtml(uriCategoryName); - $("savePath").value = window.qBittorrent.Misc.escapeHtml(uriSavePath); - $("savePath").focus(); + document.getElementById("categoryName").disabled = true; + document.getElementById("categoryName").value = window.qBittorrent.Misc.escapeHtml(uriCategoryName); + document.getElementById("savePath").value = window.qBittorrent.Misc.escapeHtml(uriSavePath); + document.getElementById("savePath").focus(); } else if (uriAction === "createSubcategory") { - $("categoryName").value = window.qBittorrent.Misc.escapeHtml(uriCategoryName); - $("categoryName").focus(); + document.getElementById("categoryName").value = window.qBittorrent.Misc.escapeHtml(uriCategoryName); + document.getElementById("categoryName").focus(); } else { - $("categoryName").focus(); + document.getElementById("categoryName").focus(); } - $("categoryNameButton").addEventListener("click", (e) => { + document.getElementById("categoryNameButton").addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); - const savePath = $("savePath").value.trim(); - const categoryName = $("categoryName").value.trim(); + const savePath = document.getElementById("savePath").value.trim(); + const categoryName = document.getElementById("categoryName").value.trim(); const verifyCategoryName = (name) => { if ((name === null) || (name === "")) diff --git a/src/webui/www/private/newfeed.html b/src/webui/www/private/newfeed.html index b3815a63e..c126ca068 100644 --- a/src/webui/www/private/newfeed.html +++ b/src/webui/www/private/newfeed.html @@ -18,7 +18,7 @@ switch (event.key) { case "Enter": event.preventDefault(); - $("submitButton").click(); + document.getElementById("submitButton").click(); break; case "Escape": event.preventDefault(); @@ -27,19 +27,19 @@ } }); - $("feedURL").focus(); - $("submitButton").addEventListener("click", (e) => { + document.getElementById("feedURL").focus(); + document.getElementById("submitButton").addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); // check field - const feedURL = $("feedURL").value.trim(); + const feedURL = document.getElementById("feedURL").value.trim(); if (feedURL === "") { alert("QBT_TR(Name cannot be empty)QBT_TR[CONTEXT=HttpServer]"); return; } - $("submitButton").disabled = true; + document.getElementById("submitButton").disabled = true; const path = new URLSearchParams(window.location.search).get("path"); fetch("api/v2/rss/addFeed", { @@ -53,7 +53,7 @@ if (!response.ok) { if (response.status === 409) alert(await response.text()); - $("submitButton").disabled = false; + document.getElementById("submitButton").disabled = false; return; } diff --git a/src/webui/www/private/newfolder.html b/src/webui/www/private/newfolder.html index 30db4c450..c567a7c55 100644 --- a/src/webui/www/private/newfolder.html +++ b/src/webui/www/private/newfolder.html @@ -19,7 +19,7 @@ switch (event.key) { case "Enter": event.preventDefault(); - $("submitButton").click(); + document.getElementById("submitButton").click(); break; case "Escape": event.preventDefault(); @@ -28,19 +28,19 @@ } }); - $("folderName").focus(); - $("submitButton").addEventListener("click", (e) => { + document.getElementById("folderName").focus(); + document.getElementById("submitButton").addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); // check field - const folderName = $("folderName").value.trim(); + const folderName = document.getElementById("folderName").value.trim(); if (folderName === "") { alert("QBT_TR(Name cannot be empty)QBT_TR[CONTEXT=HttpServer]"); return; } - $("submitButton").disabled = true; + document.getElementById("submitButton").disabled = true; const path = new URLSearchParams(window.location.search).get("path"); fetch("api/v2/rss/addFolder", { @@ -53,7 +53,7 @@ if (!response.ok) { if (response.status === 409) alert(await response.text()); - $("submitButton").disabled = false; + document.getElementById("submitButton").disabled = false; return; } diff --git a/src/webui/www/private/newrule.html b/src/webui/www/private/newrule.html index 18f03a154..dc419e112 100644 --- a/src/webui/www/private/newrule.html +++ b/src/webui/www/private/newrule.html @@ -18,7 +18,7 @@ switch (event.key) { case "Enter": event.preventDefault(); - $("submitButton").click(); + document.getElementById("submitButton").click(); break; case "Escape": event.preventDefault(); @@ -27,18 +27,18 @@ } }); - $("name").focus(); - $("submitButton").addEventListener("click", (e) => { + document.getElementById("name").focus(); + document.getElementById("submitButton").addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); // check field - const name = $("name").value.trim(); + const name = document.getElementById("name").value.trim(); if (name === "") { alert("QBT_TR(Name cannot be empty)QBT_TR[CONTEXT=HttpServer]"); return; } - $("submitButton").disabled = true; + document.getElementById("submitButton").disabled = true; fetch("api/v2/rss/setRule", { method: "POST", diff --git a/src/webui/www/private/newtag.html b/src/webui/www/private/newtag.html index a8067fecc..cab3b26cf 100644 --- a/src/webui/www/private/newtag.html +++ b/src/webui/www/private/newtag.html @@ -18,7 +18,7 @@ switch (event.key) { case "Enter": event.preventDefault(); - $("tagNameButton").click(); + document.getElementById("tagNameButton").click(); break; case "Escape": event.preventDefault(); @@ -31,15 +31,15 @@ const uriAction = window.qBittorrent.Misc.safeTrim(searchParams.get("action")); if (uriAction === "create") - $("legendText").textContent = "QBT_TR(Tag:)QBT_TR[CONTEXT=TagFilterWidget]"; + document.getElementById("legendText").textContent = "QBT_TR(Tag:)QBT_TR[CONTEXT=TagFilterWidget]"; - $("tagName").focus(); + document.getElementById("tagName").focus(); - $("tagNameButton").addEventListener("click", (e) => { + document.getElementById("tagNameButton").addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); - const tagName = $("tagName").value.trim(); + const tagName = document.getElementById("tagName").value.trim(); const verifyTagName = (name) => { if ((name === null) || (name === "")) diff --git a/src/webui/www/private/rename.html b/src/webui/www/private/rename.html index f3f1d119f..e4debb24b 100644 --- a/src/webui/www/private/rename.html +++ b/src/webui/www/private/rename.html @@ -18,7 +18,7 @@ switch (event.key) { case "Enter": event.preventDefault(); - $("renameButton").click(); + document.getElementById("renameButton").click(); break; case "Escape": event.preventDefault(); @@ -31,15 +31,15 @@ const name = searchParams.get("name"); // set text field to current value if (name !== null) - $("rename").value = name; + document.getElementById("rename").value = name; - $("rename").focus(); - $("renameButton").addEventListener("click", (e) => { + document.getElementById("rename").focus(); + document.getElementById("renameButton").addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); // check field - const name = $("rename").value.trim(); + const name = document.getElementById("rename").value.trim(); if ((name === null) || (name === "")) return; diff --git a/src/webui/www/private/rename_feed.html b/src/webui/www/private/rename_feed.html index d11f41935..356ca9dd1 100644 --- a/src/webui/www/private/rename_feed.html +++ b/src/webui/www/private/rename_feed.html @@ -18,7 +18,7 @@ switch (event.key) { case "Enter": event.preventDefault(); - $("renameButton").click(); + document.getElementById("renameButton").click(); break; case "Escape": event.preventDefault(); @@ -29,16 +29,16 @@ const oldPath = new URLSearchParams(window.location.search).get("oldPath"); - $("rename").value = oldPath; - $("rename").focus(); - $("rename").setSelectionRange(0, oldPath.length); + document.getElementById("rename").value = oldPath; + document.getElementById("rename").focus(); + document.getElementById("rename").setSelectionRange(0, oldPath.length); - $("renameButton").addEventListener("click", (e) => { + document.getElementById("renameButton").addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); // check field - const newPath = $("rename").value.trim(); + const newPath = document.getElementById("rename").value.trim(); if (newPath === "") { alert("QBT_TR(Name cannot be empty)QBT_TR[CONTEXT=HttpServer]"); return; @@ -49,7 +49,7 @@ return; } - $("renameButton").disabled = true; + document.getElementById("renameButton").disabled = true; fetch("api/v2/rss/moveItem", { method: "POST", @@ -62,7 +62,7 @@ if (!response.ok) { if (response.status === 409) alert(await response.text()); - $("renameButton").disabled = false; + document.getElementById("renameButton").disabled = false; return; } diff --git a/src/webui/www/private/rename_file.html b/src/webui/www/private/rename_file.html index 8cddc935b..dfe5d0cdb 100644 --- a/src/webui/www/private/rename_file.html +++ b/src/webui/www/private/rename_file.html @@ -19,7 +19,7 @@ switch (event.key) { case "Enter": event.preventDefault(); - $("renameButton").click(); + document.getElementById("renameButton").click(); break; case "Escape": event.preventDefault(); @@ -34,17 +34,17 @@ const isFolder = ((searchParams.get("isFolder")) === "true"); const oldName = window.qBittorrent.Filesystem.fileName(oldPath); - $("rename").value = oldName; - $("rename").focus(); + document.getElementById("rename").value = oldName; + document.getElementById("rename").focus(); if (!isFolder) - $("rename").setSelectionRange(0, oldName.lastIndexOf(".")); + document.getElementById("rename").setSelectionRange(0, oldName.lastIndexOf(".")); - $("renameButton").addEventListener("click", (e) => { + document.getElementById("renameButton").addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); // check field - const newName = $("rename").value.trim(); + const newName = document.getElementById("rename").value.trim(); if (newName === "") { alert("QBT_TR(Name cannot be empty)QBT_TR[CONTEXT=HttpServer]"); return; @@ -55,7 +55,7 @@ return; } - $("renameButton").disabled = true; + document.getElementById("renameButton").disabled = true; const parentPath = window.qBittorrent.Filesystem.folderName(oldPath); const newPath = parentPath @@ -72,7 +72,7 @@ .then((response) => { if (!response.ok) { alert("QBT_TR(Failed to update name)QBT_TR[CONTEXT=HttpServer]"); - $("renameButton").disabled = false; + document.getElementById("renameButton").disabled = false; return; } diff --git a/src/webui/www/private/rename_files.html b/src/webui/www/private/rename_files.html index 37a15b3a7..55f461b6f 100644 --- a/src/webui/www/private/rename_files.html +++ b/src/webui/www/private/rename_files.html @@ -80,50 +80,50 @@ // Load Multi Rename Preferences const multiRenamePrefChecked = LocalPreferences.get("multirename_rememberPreferences", "true") === "true"; - $("multirename_rememberprefs_checkbox").checked = multiRenamePrefChecked; + document.getElementById("multirename_rememberprefs_checkbox").checked = multiRenamePrefChecked; if (multiRenamePrefChecked) { const multirename_search = LocalPreferences.get("multirename_search", ""); fileRenamer.setSearch(multirename_search); - $("multiRenameSearch").value = multirename_search; + document.getElementById("multiRenameSearch").value = multirename_search; const multirename_useRegex = LocalPreferences.get("multirename_useRegex", false); fileRenamer.useRegex = multirename_useRegex === "true"; - $("use_regex_search").checked = fileRenamer.useRegex; + document.getElementById("use_regex_search").checked = fileRenamer.useRegex; const multirename_matchAllOccurrences = LocalPreferences.get("multirename_matchAllOccurrences", false); fileRenamer.matchAllOccurrences = multirename_matchAllOccurrences === "true"; - $("match_all_occurrences").checked = fileRenamer.matchAllOccurrences; + document.getElementById("match_all_occurrences").checked = fileRenamer.matchAllOccurrences; const multirename_caseSensitive = LocalPreferences.get("multirename_caseSensitive", false); fileRenamer.caseSensitive = multirename_caseSensitive === "true"; - $("case_sensitive").checked = fileRenamer.caseSensitive; + document.getElementById("case_sensitive").checked = fileRenamer.caseSensitive; const multirename_replace = LocalPreferences.get("multirename_replace", ""); fileRenamer.setReplacement(multirename_replace); - $("multiRenameReplace").value = multirename_replace; + document.getElementById("multiRenameReplace").value = multirename_replace; const multirename_appliesTo = LocalPreferences.get("multirename_appliesTo", window.qBittorrent.MultiRename.AppliesTo.FilenameExtension); fileRenamer.appliesTo = window.qBittorrent.MultiRename.AppliesTo[multirename_appliesTo]; - $("applies_to_option").value = fileRenamer.appliesTo; + document.getElementById("applies_to_option").value = fileRenamer.appliesTo; const multirename_includeFiles = LocalPreferences.get("multirename_includeFiles", true); fileRenamer.includeFiles = multirename_includeFiles === "true"; - $("include_files").checked = fileRenamer.includeFiles; + document.getElementById("include_files").checked = fileRenamer.includeFiles; const multirename_includeFolders = LocalPreferences.get("multirename_includeFolders", false); fileRenamer.includeFolders = multirename_includeFolders === "true"; - $("include_folders").checked = fileRenamer.includeFolders; + document.getElementById("include_folders").checked = fileRenamer.includeFolders; const multirename_fileEnumerationStart = LocalPreferences.get("multirename_fileEnumerationStart", 0); fileRenamer.fileEnumerationStart = Number(multirename_fileEnumerationStart); - $("file_counter").value = fileRenamer.fileEnumerationStart; + document.getElementById("file_counter").value = fileRenamer.fileEnumerationStart; const multirename_replaceAll = LocalPreferences.get("multirename_replaceAll", false); fileRenamer.replaceAll = multirename_replaceAll === "true"; const renameButtonValue = fileRenamer.replaceAll ? "Replace All" : "Replace"; - $("renameOptions").value = renameButtonValue; - $("renameButton").value = renameButtonValue; + document.getElementById("renameOptions").value = renameButtonValue; + document.getElementById("renameButton").value = renameButtonValue; } // Fires every time a row's selection changes @@ -133,26 +133,26 @@ }; // Setup Search Events that control renaming - $("multiRenameSearch").addEventListener("input", (e) => { + document.getElementById("multiRenameSearch").addEventListener("input", (e) => { const sanitized = e.target.value.replace(/\n/g, ""); - $("multiRenameSearch").value = sanitized; + document.getElementById("multiRenameSearch").value = sanitized; // Search input has changed - $("multiRenameSearch").style["border-color"] = ""; + document.getElementById("multiRenameSearch").style["border-color"] = ""; LocalPreferences.set("multirename_search", sanitized); fileRenamer.setSearch(sanitized); }); - $("use_regex_search").addEventListener("change", (e) => { + document.getElementById("use_regex_search").addEventListener("change", (e) => { fileRenamer.useRegex = e.target.checked; LocalPreferences.set("multirename_useRegex", e.target.checked); fileRenamer.update(); }); - $("match_all_occurrences").addEventListener("change", (e) => { + document.getElementById("match_all_occurrences").addEventListener("change", (e) => { fileRenamer.matchAllOccurrences = e.target.checked; LocalPreferences.set("multirename_matchAllOccurrences", e.target.checked); fileRenamer.update(); }); - $("case_sensitive").addEventListener("change", (e) => { + document.getElementById("case_sensitive").addEventListener("change", (e) => { fileRenamer.caseSensitive = e.target.checked; LocalPreferences.set("multirename_caseSensitive", e.target.checked); fileRenamer.update(); @@ -179,35 +179,35 @@ } }; fileRenamer.onInvalidRegex = (err) => { - $("multiRenameSearch").style["border-color"] = "#CC0033"; + document.getElementById("multiRenameSearch").style["border-color"] = "#CC0033"; }; // Setup Replace Events that control renaming - $("multiRenameReplace").addEventListener("input", (e) => { + document.getElementById("multiRenameReplace").addEventListener("input", (e) => { const sanitized = e.target.value.replace(/\n/g, ""); - $("multiRenameReplace").value = sanitized; + document.getElementById("multiRenameReplace").value = sanitized; // Replace input has changed - $("multiRenameReplace").style["border-color"] = ""; + document.getElementById("multiRenameReplace").style["border-color"] = ""; LocalPreferences.set("multirename_replace", sanitized); fileRenamer.setReplacement(sanitized); }); - $("applies_to_option").addEventListener("change", (e) => { + document.getElementById("applies_to_option").addEventListener("change", (e) => { fileRenamer.appliesTo = e.target.value; LocalPreferences.set("multirename_appliesTo", e.target.value); fileRenamer.update(); }); - $("include_files").addEventListener("change", (e) => { + document.getElementById("include_files").addEventListener("change", (e) => { fileRenamer.includeFiles = e.target.checked; LocalPreferences.set("multirename_includeFiles", e.target.checked); fileRenamer.update(); }); - $("include_folders").addEventListener("change", (e) => { + document.getElementById("include_folders").addEventListener("change", (e) => { fileRenamer.includeFolders = e.target.checked; LocalPreferences.set("multirename_includeFolders", e.target.checked); fileRenamer.update(); }); - $("file_counter").addEventListener("input", (e) => { + document.getElementById("file_counter").addEventListener("input", (e) => { let value = e.target.valueAsNumber; if (!value) value = 0; @@ -216,46 +216,46 @@ if (value > 99999999) value = 99999999; fileRenamer.fileEnumerationStart = value; - $("file_counter").value = value; + document.getElementById("file_counter").value = value; LocalPreferences.set("multirename_fileEnumerationStart", value); fileRenamer.update(); }); // Setup Rename Operation Events - $("renameButton").addEventListener("click", (e) => { + document.getElementById("renameButton").addEventListener("click", (e) => { // Disable Search Options - $("multiRenameSearch").disabled = true; - $("use_regex_search").disabled = true; - $("match_all_occurrences").disabled = true; - $("case_sensitive").disabled = true; + document.getElementById("multiRenameSearch").disabled = true; + document.getElementById("use_regex_search").disabled = true; + document.getElementById("match_all_occurrences").disabled = true; + document.getElementById("case_sensitive").disabled = true; // Disable Replace Options - $("multiRenameReplace").disabled = true; - $("applies_to_option").disabled = true; - $("include_files").disabled = true; - $("include_folders").disabled = true; - $("file_counter").disabled = true; + document.getElementById("multiRenameReplace").disabled = true; + document.getElementById("applies_to_option").disabled = true; + document.getElementById("include_files").disabled = true; + document.getElementById("include_folders").disabled = true; + document.getElementById("file_counter").disabled = true; // Disable Rename Buttons - $("renameButton").disabled = true; - $("renameOptions").disabled = true; + document.getElementById("renameButton").disabled = true; + document.getElementById("renameOptions").disabled = true; // Clear error text - $("rename_error").textContent = ""; + document.getElementById("rename_error").textContent = ""; fileRenamer.rename(); }); fileRenamer.onRenamed = (rows) => { // Disable Search Options - $("multiRenameSearch").disabled = false; - $("use_regex_search").disabled = false; - $("match_all_occurrences").disabled = false; - $("case_sensitive").disabled = false; + document.getElementById("multiRenameSearch").disabled = false; + document.getElementById("use_regex_search").disabled = false; + document.getElementById("match_all_occurrences").disabled = false; + document.getElementById("case_sensitive").disabled = false; // Disable Replace Options - $("multiRenameReplace").disabled = false; - $("applies_to_option").disabled = false; - $("include_files").disabled = false; - $("include_folders").disabled = false; - $("file_counter").disabled = false; + document.getElementById("multiRenameReplace").disabled = false; + document.getElementById("applies_to_option").disabled = false; + document.getElementById("include_files").disabled = false; + document.getElementById("include_folders").disabled = false; + document.getElementById("file_counter").disabled = false; // Disable Rename Buttons - $("renameButton").disabled = false; - $("renameOptions").disabled = false; + document.getElementById("renameButton").disabled = false; + document.getElementById("renameOptions").disabled = false; // Recreate table let selectedRows = bulkRenameFilesTable.getSelectedRows().map(row => row.rowId.toString()); @@ -266,15 +266,15 @@ // Adjust file enumeration count by 1 when replacing single files to prevent naming conflicts if (!fileRenamer.replaceAll) { fileRenamer.fileEnumerationStart++; - $("file_counter").value = fileRenamer.fileEnumerationStart; + document.getElementById("file_counter").value = fileRenamer.fileEnumerationStart; } setupTable(selectedRows); }; fileRenamer.onRenameError = (response, row) => { if (response.status === 409) - $("rename_error").textContent = `QBT_TR(Rename failed: file or folder already exists)QBT_TR[CONTEXT=PropertiesWidget] \`${row.renamed}\``; + document.getElementById("rename_error").textContent = `QBT_TR(Rename failed: file or folder already exists)QBT_TR[CONTEXT=PropertiesWidget] \`${row.renamed}\``; }; - $("renameOptions").addEventListener("change", (e) => { + document.getElementById("renameOptions").addEventListener("change", (e) => { const combobox = e.target; const replaceOperation = combobox.value; if (replaceOperation === "Replace") @@ -284,9 +284,9 @@ else fileRenamer.replaceAll = false; LocalPreferences.set("multirename_replaceAll", fileRenamer.replaceAll); - $("renameButton").value = replaceOperation; + document.getElementById("renameButton").value = replaceOperation; }); - $("closeButton").addEventListener("click", (event) => { + document.getElementById("closeButton").addEventListener("click", (event) => { event.preventDefault(); window.qBittorrent.Client.closeWindow(windowEl); }); diff --git a/src/webui/www/private/rename_rule.html b/src/webui/www/private/rename_rule.html index dc0c39b75..c67d81026 100644 --- a/src/webui/www/private/rename_rule.html +++ b/src/webui/www/private/rename_rule.html @@ -18,7 +18,7 @@ switch (event.key) { case "Enter": event.preventDefault(); - $("renameButton").click(); + document.getElementById("renameButton").click(); break; case "Escape": event.preventDefault(); @@ -29,16 +29,16 @@ const oldName = new URLSearchParams(window.location.search).get("rule"); - $("rename").value = oldName; - $("rename").focus(); - $("rename").setSelectionRange(0, oldName.length); + document.getElementById("rename").value = oldName; + document.getElementById("rename").focus(); + document.getElementById("rename").setSelectionRange(0, oldName.length); - $("renameButton").addEventListener("click", (e) => { + document.getElementById("renameButton").addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); // check field - const newName = $("rename").value.trim(); + const newName = document.getElementById("rename").value.trim(); if (newName === "") { alert("QBT_TR(Name cannot be empty)QBT_TR[CONTEXT=HttpServer]"); return; @@ -49,7 +49,7 @@ return; } - $("renameButton").disabled = true; + document.getElementById("renameButton").disabled = true; fetch("api/v2/rss/renameRule", { method: "POST", diff --git a/src/webui/www/private/scripts/client.js b/src/webui/www/private/scripts/client.js index 15e7af365..382b09a26 100644 --- a/src/webui/www/private/scripts/client.js +++ b/src/webui/www/private/scripts/client.js @@ -180,15 +180,15 @@ window.addEventListener("DOMContentLoaded", () => { let isRssPanelLoaded = false; const saveColumnSizes = () => { - const filters_width = $("Filters").getSize().x; + const filters_width = document.getElementById("Filters").getSize().x; LocalPreferences.set("filters_width", filters_width); - const properties_height_rel = $("propertiesPanel").getSize().y / Window.getSize().y; + const properties_height_rel = document.getElementById("propertiesPanel").getSize().y / Window.getSize().y; LocalPreferences.set("properties_height_rel", properties_height_rel); }; window.addEventListener("resize", window.qBittorrent.Misc.createDebounceHandler(500, (e) => { // only save sizes if the columns are visible - if (!$("mainColumn").classList.contains("invisible")) + if (!document.getElementById("mainColumn").classList.contains("invisible")) saveColumnSizes(); })); @@ -221,7 +221,7 @@ window.addEventListener("DOMContentLoaded", () => { }); // start off hidden - $("searchTabColumn").classList.add("invisible"); + document.getElementById("searchTabColumn").classList.add("invisible"); }; const buildRssTab = () => { @@ -232,7 +232,7 @@ window.addEventListener("DOMContentLoaded", () => { }); // start off hidden - $("rssTabColumn").classList.add("invisible"); + document.getElementById("rssTabColumn").classList.add("invisible"); }; const buildLogTab = () => { @@ -243,7 +243,7 @@ window.addEventListener("DOMContentLoaded", () => { }); // start off hidden - $("logTabColumn").classList.add("invisible"); + document.getElementById("logTabColumn").classList.add("invisible"); }; buildTransfersTab(); @@ -342,28 +342,28 @@ window.addEventListener("DOMContentLoaded", () => { // Show Top Toolbar is enabled by default let showTopToolbar = LocalPreferences.get("show_top_toolbar", "true") === "true"; if (!showTopToolbar) { - $("showTopToolbarLink").firstElementChild.style.opacity = "0"; - $("mochaToolbar").classList.add("invisible"); + document.getElementById("showTopToolbarLink").firstElementChild.style.opacity = "0"; + document.getElementById("mochaToolbar").classList.add("invisible"); } // Show Status Bar is enabled by default let showStatusBar = LocalPreferences.get("show_status_bar", "true") === "true"; if (!showStatusBar) { - $("showStatusBarLink").firstElementChild.style.opacity = "0"; - $("desktopFooterWrapper").classList.add("invisible"); + document.getElementById("showStatusBarLink").firstElementChild.style.opacity = "0"; + document.getElementById("desktopFooterWrapper").classList.add("invisible"); } // Show Filters Sidebar is enabled by default let showFiltersSidebar = LocalPreferences.get("show_filters_sidebar", "true") === "true"; if (!showFiltersSidebar) { - $("showFiltersSidebarLink").firstElementChild.style.opacity = "0"; - $("filtersColumn").classList.add("invisible"); - $("filtersColumn_handle").classList.add("invisible"); + document.getElementById("showFiltersSidebarLink").firstElementChild.style.opacity = "0"; + document.getElementById("filtersColumn").classList.add("invisible"); + document.getElementById("filtersColumn_handle").classList.add("invisible"); } let speedInTitle = LocalPreferences.get("speed_in_browser_title_bar") === "true"; if (!speedInTitle) - $("speedInBrowserTitleBarLink").firstElementChild.style.opacity = "0"; + document.getElementById("speedInBrowserTitleBarLink").firstElementChild.style.opacity = "0"; // After showing/hiding the toolbar + status bar window.qBittorrent.Client.showSearchEngine(LocalPreferences.get("show_search_engine") !== "false"); @@ -614,7 +614,7 @@ window.addEventListener("DOMContentLoaded", () => { }; const updateTagList = () => { - const tagFilterList = $("tagFilterList"); + const tagFilterList = document.getElementById("tagFilterList"); if (tagFilterList === null) return; @@ -667,7 +667,7 @@ window.addEventListener("DOMContentLoaded", () => { }; const updateTrackerList = () => { - const trackerFilterList = $("trackerFilterList"); + const trackerFilterList = document.getElementById("trackerFilterList"); if (trackerFilterList === null) return; @@ -763,7 +763,7 @@ window.addEventListener("DOMContentLoaded", () => { }) .then(async (response) => { if (response.ok) { - $("error_div").textContent = ""; + document.getElementById("error_div").textContent = ""; const responseJSON = await response.json(); @@ -933,7 +933,7 @@ window.addEventListener("DOMContentLoaded", () => { syncData(window.qBittorrent.Client.getSyncMainDataInterval()); }, (error) => { - const errorDiv = $("error_div"); + const errorDiv = document.getElementById("error_div"); if (errorDiv) errorDiv.textContent = "QBT_TR(qBittorrent client is not reachable)QBT_TR[CONTEXT=HttpServer]"; syncRequestInProgress = false; @@ -964,12 +964,12 @@ window.addEventListener("DOMContentLoaded", () => { if (serverState.dl_rate_limit > 0) transfer_info += ` [${window.qBittorrent.Misc.friendlyUnit(serverState.dl_rate_limit, true)}]`; transfer_info += ` (${window.qBittorrent.Misc.friendlyUnit(serverState.dl_info_data, false)})`; - $("DlInfos").textContent = transfer_info; + document.getElementById("DlInfos").textContent = transfer_info; transfer_info = window.qBittorrent.Misc.friendlyUnit(serverState.up_info_speed, true); if (serverState.up_rate_limit > 0) transfer_info += ` [${window.qBittorrent.Misc.friendlyUnit(serverState.up_rate_limit, true)}]`; transfer_info += ` (${window.qBittorrent.Misc.friendlyUnit(serverState.up_info_data, false)})`; - $("UpInfos").textContent = transfer_info; + document.getElementById("UpInfos").textContent = transfer_info; document.title = (speedInTitle ? (`QBT_TR([D: %1, U: %2])QBT_TR[CONTEXT=MainWindow] ` @@ -978,7 +978,7 @@ window.addEventListener("DOMContentLoaded", () => { : "") + window.qBittorrent.Client.mainTitle(); - $("freeSpaceOnDisk").textContent = "QBT_TR(Free space: %1)QBT_TR[CONTEXT=HttpServer]".replace("%1", window.qBittorrent.Misc.friendlyUnit(serverState.free_space_on_disk)); + document.getElementById("freeSpaceOnDisk").textContent = "QBT_TR(Free space: %1)QBT_TR[CONTEXT=HttpServer]".replace("%1", window.qBittorrent.Misc.friendlyUnit(serverState.free_space_on_disk)); const externalIPsElement = document.getElementById("externalIPs"); if (window.qBittorrent.Cache.preferences.get().status_bar_external_ip) { @@ -1015,35 +1015,35 @@ window.addEventListener("DOMContentLoaded", () => { // Statistics dialog if (document.getElementById("statisticsContent")) { - $("AlltimeDL").textContent = window.qBittorrent.Misc.friendlyUnit(serverState.alltime_dl, false); - $("AlltimeUL").textContent = window.qBittorrent.Misc.friendlyUnit(serverState.alltime_ul, false); - $("TotalWastedSession").textContent = window.qBittorrent.Misc.friendlyUnit(serverState.total_wasted_session, false); - $("GlobalRatio").textContent = serverState.global_ratio; - $("TotalPeerConnections").textContent = serverState.total_peer_connections; - $("ReadCacheHits").textContent = `${serverState.read_cache_hits}%`; - $("TotalBuffersSize").textContent = window.qBittorrent.Misc.friendlyUnit(serverState.total_buffers_size, false); - $("WriteCacheOverload").textContent = `${serverState.write_cache_overload}%`; - $("ReadCacheOverload").textContent = `${serverState.read_cache_overload}%`; - $("QueuedIOJobs").textContent = serverState.queued_io_jobs; - $("AverageTimeInQueue").textContent = `${serverState.average_time_queue} ms`; - $("TotalQueuedSize").textContent = window.qBittorrent.Misc.friendlyUnit(serverState.total_queued_size, false); + document.getElementById("AlltimeDL").textContent = window.qBittorrent.Misc.friendlyUnit(serverState.alltime_dl, false); + document.getElementById("AlltimeUL").textContent = window.qBittorrent.Misc.friendlyUnit(serverState.alltime_ul, false); + document.getElementById("TotalWastedSession").textContent = window.qBittorrent.Misc.friendlyUnit(serverState.total_wasted_session, false); + document.getElementById("GlobalRatio").textContent = serverState.global_ratio; + document.getElementById("TotalPeerConnections").textContent = serverState.total_peer_connections; + document.getElementById("ReadCacheHits").textContent = `${serverState.read_cache_hits}%`; + document.getElementById("TotalBuffersSize").textContent = window.qBittorrent.Misc.friendlyUnit(serverState.total_buffers_size, false); + document.getElementById("WriteCacheOverload").textContent = `${serverState.write_cache_overload}%`; + document.getElementById("ReadCacheOverload").textContent = `${serverState.read_cache_overload}%`; + document.getElementById("QueuedIOJobs").textContent = serverState.queued_io_jobs; + document.getElementById("AverageTimeInQueue").textContent = `${serverState.average_time_queue} ms`; + document.getElementById("TotalQueuedSize").textContent = window.qBittorrent.Misc.friendlyUnit(serverState.total_queued_size, false); } switch (serverState.connection_status) { case "connected": - $("connectionStatus").src = "images/connected.svg"; - $("connectionStatus").alt = "QBT_TR(Connection status: Connected)QBT_TR[CONTEXT=MainWindow]"; - $("connectionStatus").title = "QBT_TR(Connection status: Connected)QBT_TR[CONTEXT=MainWindow]"; + document.getElementById("connectionStatus").src = "images/connected.svg"; + document.getElementById("connectionStatus").alt = "QBT_TR(Connection status: Connected)QBT_TR[CONTEXT=MainWindow]"; + document.getElementById("connectionStatus").title = "QBT_TR(Connection status: Connected)QBT_TR[CONTEXT=MainWindow]"; break; case "firewalled": - $("connectionStatus").src = "images/firewalled.svg"; - $("connectionStatus").alt = "QBT_TR(Connection status: Firewalled)QBT_TR[CONTEXT=MainWindow]"; - $("connectionStatus").title = "QBT_TR(Connection status: Firewalled)QBT_TR[CONTEXT=MainWindow]"; + document.getElementById("connectionStatus").src = "images/firewalled.svg"; + document.getElementById("connectionStatus").alt = "QBT_TR(Connection status: Firewalled)QBT_TR[CONTEXT=MainWindow]"; + document.getElementById("connectionStatus").title = "QBT_TR(Connection status: Firewalled)QBT_TR[CONTEXT=MainWindow]"; break; default: - $("connectionStatus").src = "images/disconnected.svg"; - $("connectionStatus").alt = "QBT_TR(Connection status: Disconnected)QBT_TR[CONTEXT=MainWindow]"; - $("connectionStatus").title = "QBT_TR(Connection status: Disconnected)QBT_TR[CONTEXT=MainWindow]"; + document.getElementById("connectionStatus").src = "images/disconnected.svg"; + document.getElementById("connectionStatus").alt = "QBT_TR(Connection status: Disconnected)QBT_TR[CONTEXT=MainWindow]"; + document.getElementById("connectionStatus").title = "QBT_TR(Connection status: Disconnected)QBT_TR[CONTEXT=MainWindow]"; break; } @@ -1052,20 +1052,20 @@ window.addEventListener("DOMContentLoaded", () => { torrentsTable.columns["priority"].force_hide = !queueing_enabled; torrentsTable.updateColumn("priority"); if (queueing_enabled) { - $("topQueuePosItem").classList.remove("invisible"); - $("increaseQueuePosItem").classList.remove("invisible"); - $("decreaseQueuePosItem").classList.remove("invisible"); - $("bottomQueuePosItem").classList.remove("invisible"); - $("queueingButtons").classList.remove("invisible"); - $("queueingMenuItems").classList.remove("invisible"); + document.getElementById("topQueuePosItem").classList.remove("invisible"); + document.getElementById("increaseQueuePosItem").classList.remove("invisible"); + document.getElementById("decreaseQueuePosItem").classList.remove("invisible"); + document.getElementById("bottomQueuePosItem").classList.remove("invisible"); + document.getElementById("queueingButtons").classList.remove("invisible"); + document.getElementById("queueingMenuItems").classList.remove("invisible"); } else { - $("topQueuePosItem").classList.add("invisible"); - $("increaseQueuePosItem").classList.add("invisible"); - $("decreaseQueuePosItem").classList.add("invisible"); - $("bottomQueuePosItem").classList.add("invisible"); - $("queueingButtons").classList.add("invisible"); - $("queueingMenuItems").classList.add("invisible"); + document.getElementById("topQueuePosItem").classList.add("invisible"); + document.getElementById("increaseQueuePosItem").classList.add("invisible"); + document.getElementById("decreaseQueuePosItem").classList.add("invisible"); + document.getElementById("bottomQueuePosItem").classList.add("invisible"); + document.getElementById("queueingButtons").classList.add("invisible"); + document.getElementById("queueingMenuItems").classList.add("invisible"); } } @@ -1084,18 +1084,18 @@ window.addEventListener("DOMContentLoaded", () => { const updateAltSpeedIcon = (enabled) => { if (enabled) { - $("alternativeSpeedLimits").src = "images/slow.svg"; - $("alternativeSpeedLimits").alt = "QBT_TR(Alternative speed limits: On)QBT_TR[CONTEXT=MainWindow]"; - $("alternativeSpeedLimits").title = "QBT_TR(Alternative speed limits: On)QBT_TR[CONTEXT=MainWindow]"; + document.getElementById("alternativeSpeedLimits").src = "images/slow.svg"; + document.getElementById("alternativeSpeedLimits").alt = "QBT_TR(Alternative speed limits: On)QBT_TR[CONTEXT=MainWindow]"; + document.getElementById("alternativeSpeedLimits").title = "QBT_TR(Alternative speed limits: On)QBT_TR[CONTEXT=MainWindow]"; } else { - $("alternativeSpeedLimits").src = "images/slow_off.svg"; - $("alternativeSpeedLimits").alt = "QBT_TR(Alternative speed limits: Off)QBT_TR[CONTEXT=MainWindow]"; - $("alternativeSpeedLimits").title = "QBT_TR(Alternative speed limits: Off)QBT_TR[CONTEXT=MainWindow]"; + document.getElementById("alternativeSpeedLimits").src = "images/slow_off.svg"; + document.getElementById("alternativeSpeedLimits").alt = "QBT_TR(Alternative speed limits: Off)QBT_TR[CONTEXT=MainWindow]"; + document.getElementById("alternativeSpeedLimits").title = "QBT_TR(Alternative speed limits: Off)QBT_TR[CONTEXT=MainWindow]"; } }; - $("alternativeSpeedLimits").addEventListener("click", () => { + document.getElementById("alternativeSpeedLimits").addEventListener("click", () => { // Change icon immediately to give some feedback updateAltSpeedIcon(!alternativeSpeedLimits); @@ -1114,33 +1114,33 @@ window.addEventListener("DOMContentLoaded", () => { }); }); - $("DlInfos").addEventListener("click", () => { globalDownloadLimitFN(); }); - $("UpInfos").addEventListener("click", () => { globalUploadLimitFN(); }); + document.getElementById("DlInfos").addEventListener("click", () => { globalDownloadLimitFN(); }); + document.getElementById("UpInfos").addEventListener("click", () => { globalUploadLimitFN(); }); - $("showTopToolbarLink").addEventListener("click", (e) => { + document.getElementById("showTopToolbarLink").addEventListener("click", (e) => { showTopToolbar = !showTopToolbar; LocalPreferences.set("show_top_toolbar", showTopToolbar.toString()); if (showTopToolbar) { - $("showTopToolbarLink").firstElementChild.style.opacity = "1"; - $("mochaToolbar").classList.remove("invisible"); + document.getElementById("showTopToolbarLink").firstElementChild.style.opacity = "1"; + document.getElementById("mochaToolbar").classList.remove("invisible"); } else { - $("showTopToolbarLink").firstElementChild.style.opacity = "0"; - $("mochaToolbar").classList.add("invisible"); + document.getElementById("showTopToolbarLink").firstElementChild.style.opacity = "0"; + document.getElementById("mochaToolbar").classList.add("invisible"); } MochaUI.Desktop.setDesktopSize(); }); - $("showStatusBarLink").addEventListener("click", (e) => { + document.getElementById("showStatusBarLink").addEventListener("click", (e) => { showStatusBar = !showStatusBar; LocalPreferences.set("show_status_bar", showStatusBar.toString()); if (showStatusBar) { - $("showStatusBarLink").firstElementChild.style.opacity = "1"; - $("desktopFooterWrapper").classList.remove("invisible"); + document.getElementById("showStatusBarLink").firstElementChild.style.opacity = "1"; + document.getElementById("desktopFooterWrapper").classList.remove("invisible"); } else { - $("showStatusBarLink").firstElementChild.style.opacity = "0"; - $("desktopFooterWrapper").classList.add("invisible"); + document.getElementById("showStatusBarLink").firstElementChild.style.opacity = "0"; + document.getElementById("desktopFooterWrapper").classList.add("invisible"); } MochaUI.Desktop.setDesktopSize(); }); @@ -1164,49 +1164,49 @@ window.addEventListener("DOMContentLoaded", () => { navigator.registerProtocolHandler("magnet", templateUrl, "qBittorrent WebUI magnet handler"); }; - $("registerMagnetHandlerLink").addEventListener("click", (e) => { + document.getElementById("registerMagnetHandlerLink").addEventListener("click", (e) => { registerMagnetHandler(); }); - $("showFiltersSidebarLink").addEventListener("click", (e) => { + document.getElementById("showFiltersSidebarLink").addEventListener("click", (e) => { showFiltersSidebar = !showFiltersSidebar; LocalPreferences.set("show_filters_sidebar", showFiltersSidebar.toString()); if (showFiltersSidebar) { - $("showFiltersSidebarLink").firstElementChild.style.opacity = "1"; - $("filtersColumn").classList.remove("invisible"); - $("filtersColumn_handle").classList.remove("invisible"); + document.getElementById("showFiltersSidebarLink").firstElementChild.style.opacity = "1"; + document.getElementById("filtersColumn").classList.remove("invisible"); + document.getElementById("filtersColumn_handle").classList.remove("invisible"); } else { - $("showFiltersSidebarLink").firstElementChild.style.opacity = "0"; - $("filtersColumn").classList.add("invisible"); - $("filtersColumn_handle").classList.add("invisible"); + document.getElementById("showFiltersSidebarLink").firstElementChild.style.opacity = "0"; + document.getElementById("filtersColumn").classList.add("invisible"); + document.getElementById("filtersColumn_handle").classList.add("invisible"); } MochaUI.Desktop.setDesktopSize(); }); - $("speedInBrowserTitleBarLink").addEventListener("click", (e) => { + document.getElementById("speedInBrowserTitleBarLink").addEventListener("click", (e) => { speedInTitle = !speedInTitle; LocalPreferences.set("speed_in_browser_title_bar", speedInTitle.toString()); if (speedInTitle) - $("speedInBrowserTitleBarLink").firstElementChild.style.opacity = "1"; + document.getElementById("speedInBrowserTitleBarLink").firstElementChild.style.opacity = "1"; else - $("speedInBrowserTitleBarLink").firstElementChild.style.opacity = "0"; + document.getElementById("speedInBrowserTitleBarLink").firstElementChild.style.opacity = "0"; processServerState(); }); - $("showSearchEngineLink").addEventListener("click", (e) => { + document.getElementById("showSearchEngineLink").addEventListener("click", (e) => { window.qBittorrent.Client.showSearchEngine(!window.qBittorrent.Client.isShowSearchEngine()); LocalPreferences.set("show_search_engine", window.qBittorrent.Client.isShowSearchEngine().toString()); updateTabDisplay(); }); - $("showRssReaderLink").addEventListener("click", (e) => { + document.getElementById("showRssReaderLink").addEventListener("click", (e) => { window.qBittorrent.Client.showRssReader(!window.qBittorrent.Client.isShowRssReader()); LocalPreferences.set("show_rss_reader", window.qBittorrent.Client.isShowRssReader().toString()); updateTabDisplay(); }); - $("showLogViewerLink").addEventListener("click", (e) => { + document.getElementById("showLogViewerLink").addEventListener("click", (e) => { window.qBittorrent.Client.showLogViewer(!window.qBittorrent.Client.isShowLogViewer()); LocalPreferences.set("show_log_viewer", window.qBittorrent.Client.isShowLogViewer().toString()); updateTabDisplay(); @@ -1214,64 +1214,64 @@ window.addEventListener("DOMContentLoaded", () => { const updateTabDisplay = () => { if (window.qBittorrent.Client.isShowRssReader()) { - $("showRssReaderLink").firstElementChild.style.opacity = "1"; - $("mainWindowTabs").classList.remove("invisible"); - $("rssTabLink").classList.remove("invisible"); + document.getElementById("showRssReaderLink").firstElementChild.style.opacity = "1"; + document.getElementById("mainWindowTabs").classList.remove("invisible"); + document.getElementById("rssTabLink").classList.remove("invisible"); if (!MochaUI.Panels.instances.RssPanel) addRssPanel(); } else { - $("showRssReaderLink").firstElementChild.style.opacity = "0"; - $("rssTabLink").classList.add("invisible"); - if ($("rssTabLink").classList.contains("selected")) - $("transfersTabLink").click(); + document.getElementById("showRssReaderLink").firstElementChild.style.opacity = "0"; + document.getElementById("rssTabLink").classList.add("invisible"); + if (document.getElementById("rssTabLink").classList.contains("selected")) + document.getElementById("transfersTabLink").click(); } if (window.qBittorrent.Client.isShowSearchEngine()) { - $("showSearchEngineLink").firstElementChild.style.opacity = "1"; - $("mainWindowTabs").classList.remove("invisible"); - $("searchTabLink").classList.remove("invisible"); + document.getElementById("showSearchEngineLink").firstElementChild.style.opacity = "1"; + document.getElementById("mainWindowTabs").classList.remove("invisible"); + document.getElementById("searchTabLink").classList.remove("invisible"); if (!MochaUI.Panels.instances.SearchPanel) addSearchPanel(); } else { - $("showSearchEngineLink").firstElementChild.style.opacity = "0"; - $("searchTabLink").classList.add("invisible"); - if ($("searchTabLink").classList.contains("selected")) - $("transfersTabLink").click(); + document.getElementById("showSearchEngineLink").firstElementChild.style.opacity = "0"; + document.getElementById("searchTabLink").classList.add("invisible"); + if (document.getElementById("searchTabLink").classList.contains("selected")) + document.getElementById("transfersTabLink").click(); } if (window.qBittorrent.Client.isShowLogViewer()) { - $("showLogViewerLink").firstElementChild.style.opacity = "1"; - $("mainWindowTabs").classList.remove("invisible"); - $("logTabLink").classList.remove("invisible"); + document.getElementById("showLogViewerLink").firstElementChild.style.opacity = "1"; + document.getElementById("mainWindowTabs").classList.remove("invisible"); + document.getElementById("logTabLink").classList.remove("invisible"); if (!MochaUI.Panels.instances.LogPanel) addLogPanel(); } else { - $("showLogViewerLink").firstElementChild.style.opacity = "0"; - $("logTabLink").classList.add("invisible"); - if ($("logTabLink").classList.contains("selected")) - $("transfersTabLink").click(); + document.getElementById("showLogViewerLink").firstElementChild.style.opacity = "0"; + document.getElementById("logTabLink").classList.add("invisible"); + if (document.getElementById("logTabLink").classList.contains("selected")) + document.getElementById("transfersTabLink").click(); } // display no tabs if (!window.qBittorrent.Client.isShowRssReader() && !window.qBittorrent.Client.isShowSearchEngine() && !window.qBittorrent.Client.isShowLogViewer()) - $("mainWindowTabs").classList.add("invisible"); + document.getElementById("mainWindowTabs").classList.add("invisible"); }; - $("StatisticsLink").addEventListener("click", () => { StatisticsLinkFN(); }); + document.getElementById("StatisticsLink").addEventListener("click", () => { StatisticsLinkFN(); }); // main window tabs const showTransfersTab = () => { const showFiltersSidebar = LocalPreferences.get("show_filters_sidebar", "true") === "true"; if (showFiltersSidebar) { - $("filtersColumn").classList.remove("invisible"); - $("filtersColumn_handle").classList.remove("invisible"); + document.getElementById("filtersColumn").classList.remove("invisible"); + document.getElementById("filtersColumn_handle").classList.remove("invisible"); } - $("mainColumn").classList.remove("invisible"); - $("torrentsFilterToolbar").classList.remove("invisible"); + document.getElementById("mainColumn").classList.remove("invisible"); + document.getElementById("torrentsFilterToolbar").classList.remove("invisible"); customSyncMainDataInterval = null; syncData(100); @@ -1284,10 +1284,10 @@ window.addEventListener("DOMContentLoaded", () => { }; const hideTransfersTab = () => { - $("filtersColumn").classList.add("invisible"); - $("filtersColumn_handle").classList.add("invisible"); - $("mainColumn").classList.add("invisible"); - $("torrentsFilterToolbar").classList.add("invisible"); + document.getElementById("filtersColumn").classList.add("invisible"); + document.getElementById("filtersColumn_handle").classList.add("invisible"); + document.getElementById("mainColumn").classList.add("invisible"); + document.getElementById("torrentsFilterToolbar").classList.add("invisible"); MochaUI.Desktop.resizePanels(); }; @@ -1310,7 +1310,7 @@ window.addEventListener("DOMContentLoaded", () => { searchTabInitialized = true; } - $("searchTabColumn").classList.remove("invisible"); + document.getElementById("searchTabColumn").classList.remove("invisible"); customSyncMainDataInterval = 30000; hideTransfersTab(); hideRssTab(); @@ -1321,7 +1321,7 @@ window.addEventListener("DOMContentLoaded", () => { })(); const hideSearchTab = () => { - $("searchTabColumn").classList.add("invisible"); + document.getElementById("searchTabColumn").classList.add("invisible"); MochaUI.Desktop.resizePanels(); }; @@ -1347,7 +1347,7 @@ window.addEventListener("DOMContentLoaded", () => { window.qBittorrent.Rss.load(); } - $("rssTabColumn").classList.remove("invisible"); + document.getElementById("rssTabColumn").classList.remove("invisible"); customSyncMainDataInterval = 30000; hideTransfersTab(); hideSearchTab(); @@ -1358,7 +1358,7 @@ window.addEventListener("DOMContentLoaded", () => { })(); const hideRssTab = () => { - $("rssTabColumn").classList.add("invisible"); + document.getElementById("rssTabColumn").classList.add("invisible"); window.qBittorrent.Rss && window.qBittorrent.Rss.unload(); MochaUI.Desktop.resizePanels(); }; @@ -1385,7 +1385,7 @@ window.addEventListener("DOMContentLoaded", () => { window.qBittorrent.Log.load(); } - $("logTabColumn").classList.remove("invisible"); + document.getElementById("logTabColumn").classList.remove("invisible"); customSyncMainDataInterval = 30000; hideTransfersTab(); hideSearchTab(); @@ -1396,7 +1396,7 @@ window.addEventListener("DOMContentLoaded", () => { })(); const hideLogTab = () => { - $("logTabColumn").classList.add("invisible"); + document.getElementById("logTabColumn").classList.add("invisible"); MochaUI.Desktop.resizePanels(); window.qBittorrent.Log && window.qBittorrent.Log.unload(); }; @@ -1472,11 +1472,11 @@ window.addEventListener("DOMContentLoaded", () => { tabsOnload: () => { MochaUI.initializeTabs("panelTabs"); - $("logMessageLink").addEventListener("click", (e) => { + document.getElementById("logMessageLink").addEventListener("click", (e) => { window.qBittorrent.Log.setCurrentTab("main"); }); - $("logPeerLink").addEventListener("click", (e) => { + document.getElementById("logPeerLink").addEventListener("click", (e) => { window.qBittorrent.Log.setCurrentTab("peer"); }); }, @@ -1618,7 +1618,7 @@ window.addEventListener("DOMContentLoaded", () => { // listen for changes to torrentsFilterInput let torrentsFilterInputTimer = -1; - $("torrentsFilterInput").addEventListener("input", () => { + document.getElementById("torrentsFilterInput").addEventListener("input", () => { clearTimeout(torrentsFilterInputTimer); torrentsFilterInputTimer = setTimeout(() => { torrentsFilterInputTimer = -1; @@ -1628,24 +1628,24 @@ window.addEventListener("DOMContentLoaded", () => { document.getElementById("torrentsFilterToolbar").addEventListener("change", (e) => { torrentsTable.updateTable(); }); - $("transfersTabLink").addEventListener("click", () => { showTransfersTab(); }); - $("searchTabLink").addEventListener("click", () => { showSearchTab(); }); - $("rssTabLink").addEventListener("click", () => { showRssTab(); }); - $("logTabLink").addEventListener("click", () => { showLogTab(); }); + document.getElementById("transfersTabLink").addEventListener("click", () => { showTransfersTab(); }); + document.getElementById("searchTabLink").addEventListener("click", () => { showSearchTab(); }); + document.getElementById("rssTabLink").addEventListener("click", () => { showRssTab(); }); + document.getElementById("logTabLink").addEventListener("click", () => { showLogTab(); }); updateTabDisplay(); const registerDragAndDrop = () => { - $("desktop").addEventListener("dragover", (ev) => { + document.getElementById("desktop").addEventListener("dragover", (ev) => { if (ev.preventDefault) ev.preventDefault(); }); - $("desktop").addEventListener("dragenter", (ev) => { + document.getElementById("desktop").addEventListener("dragenter", (ev) => { if (ev.preventDefault) ev.preventDefault(); }); - $("desktop").addEventListener("drop", (ev) => { + document.getElementById("desktop").addEventListener("drop", (ev) => { if (ev.preventDefault) ev.preventDefault(); @@ -1679,7 +1679,7 @@ window.addEventListener("DOMContentLoaded", () => { saveWindowSize(id); }), onContentLoaded: () => { - const fileInput = $(`${id}_iframe`).contentDocument.getElementById("fileselect"); + const fileInput = document.getElementById(`${id}_iframe`).contentDocument.getElementById("fileselect"); fileInput.files = droppedFiles; } }); @@ -1801,22 +1801,22 @@ window.addEventListener("load", async () => { switch (previouslyUsedTab) { case "search": if (window.qBittorrent.Client.isShowSearchEngine()) - $("searchTabLink").click(); + document.getElementById("searchTabLink").click(); break; case "rss": if (window.qBittorrent.Client.isShowRssReader()) - $("rssTabLink").click(); + document.getElementById("rssTabLink").click(); break; case "log": if (window.qBittorrent.Client.isShowLogViewer()) - $("logTabLink").click(); + document.getElementById("logTabLink").click(); break; case "transfers": - $("transfersTabLink").click(); + document.getElementById("transfersTabLink").click(); break; default: console.error(`Unexpected 'selected_window_tab' value: ${previouslyUsedTab}`); - $("transfersTabLink").click(); + document.getElementById("transfersTabLink").click(); break; }; }); diff --git a/src/webui/www/private/scripts/contextmenu.js b/src/webui/www/private/scripts/contextmenu.js index 094fba5b3..c56f1712f 100644 --- a/src/webui/www/private/scripts/contextmenu.js +++ b/src/webui/www/private/scripts/contextmenu.js @@ -66,7 +66,7 @@ window.qBittorrent.ContextMenu ??= (() => { }; // option diffs menu - this.menu = $(this.options.menu); + this.menu = document.getElementById(this.options.menu); // fx this.fx = new Fx.Tween(this.menu, { @@ -457,7 +457,7 @@ window.qBittorrent.ContextMenu ??= (() => { this.setEnabled("copyInfohash1", thereAreV1Hashes); this.setEnabled("copyInfohash2", thereAreV2Hashes); - const contextTagList = $("contextTagList"); + const contextTagList = document.getElementById("contextTagList"); for (const tag of tagMap.keys()) { const checkbox = contextTagList.querySelector(`a[href="#Tag/${tag}"] input[type="checkbox"]`); const count = tagCount.get(tag); @@ -477,7 +477,7 @@ window.qBittorrent.ContextMenu ??= (() => { } updateCategoriesSubMenu(categories) { - const contextCategoryList = $("contextCategoryList"); + const contextCategoryList = document.getElementById("contextCategoryList"); [...contextCategoryList.children].forEach((el) => { el.destroy(); }); const createMenuItem = (text, imgURL, clickFn) => { @@ -527,7 +527,7 @@ window.qBittorrent.ContextMenu ??= (() => { } updateTagsSubMenu(tags) { - const contextTagList = $("contextTagList"); + const contextTagList = document.getElementById("contextTagList"); contextTagList.replaceChildren(); const createMenuItem = (text, imgURL, clickFn) => { @@ -727,8 +727,8 @@ window.qBittorrent.ContextMenu ??= (() => { this.menu.style.left = "-999em"; this.menu.style.top = "-999em"; // position the menu - let xPosMenu = e.pageX + this.options.offsets.x - $("rssdownloaderpage").offsetLeft; - let yPosMenu = e.pageY + this.options.offsets.y - $("rssdownloaderpage").offsetTop; + let xPosMenu = e.pageX + this.options.offsets.x - document.getElementById("rssdownloaderpage").offsetLeft; + let yPosMenu = e.pageY + this.options.offsets.y - document.getElementById("rssdownloaderpage").offsetTop; if ((xPosMenu + this.menu.offsetWidth) > document.documentElement.clientWidth) xPosMenu -= this.menu.offsetWidth; if ((yPosMenu + this.menu.offsetHeight) > document.documentElement.clientHeight) diff --git a/src/webui/www/private/scripts/download.js b/src/webui/www/private/scripts/download.js index 38a4ce81e..2b6df21ad 100644 --- a/src/webui/www/private/scripts/download.js +++ b/src/webui/www/private/scripts/download.js @@ -55,7 +55,7 @@ window.qBittorrent.Download ??= (() => { const option = document.createElement("option"); option.value = category.name; option.textContent = category.name; - $("categorySelect").appendChild(option); + document.getElementById("categorySelect").appendChild(option); } }); }; @@ -64,31 +64,31 @@ window.qBittorrent.Download ??= (() => { const pref = window.parent.qBittorrent.Cache.preferences.get(); defaultSavePath = pref.save_path; - $("savepath").value = defaultSavePath; - $("startTorrent").checked = !pref.add_stopped_enabled; - $("addToTopOfQueue").checked = pref.add_to_top_of_queue; + document.getElementById("savepath").value = defaultSavePath; + document.getElementById("startTorrent").checked = !pref.add_stopped_enabled; + document.getElementById("addToTopOfQueue").checked = pref.add_to_top_of_queue; if (pref.auto_tmm_enabled) { - $("autoTMM").selectedIndex = 1; - $("savepath").disabled = true; + document.getElementById("autoTMM").selectedIndex = 1; + document.getElementById("savepath").disabled = true; } else { - $("autoTMM").selectedIndex = 0; + document.getElementById("autoTMM").selectedIndex = 0; } if (pref.torrent_stop_condition === "MetadataReceived") - $("stopCondition").selectedIndex = 1; + document.getElementById("stopCondition").selectedIndex = 1; else if (pref.torrent_stop_condition === "FilesChecked") - $("stopCondition").selectedIndex = 2; + document.getElementById("stopCondition").selectedIndex = 2; else - $("stopCondition").selectedIndex = 0; + document.getElementById("stopCondition").selectedIndex = 0; if (pref.torrent_content_layout === "Subfolder") - $("contentLayout").selectedIndex = 1; + document.getElementById("contentLayout").selectedIndex = 1; else if (pref.torrent_content_layout === "NoSubfolder") - $("contentLayout").selectedIndex = 2; + document.getElementById("contentLayout").selectedIndex = 2; else - $("contentLayout").selectedIndex = 0; + document.getElementById("contentLayout").selectedIndex = 0; }; const changeCategorySelect = (item) => { @@ -97,37 +97,37 @@ window.qBittorrent.Download ??= (() => { item.nextElementSibling.value = ""; item.nextElementSibling.select(); - if ($("autoTMM").selectedIndex === 1) - $("savepath").value = defaultSavePath; + if (document.getElementById("autoTMM").selectedIndex === 1) + document.getElementById("savepath").value = defaultSavePath; } else { item.nextElementSibling.hidden = true; const text = item.options[item.selectedIndex].textContent; item.nextElementSibling.value = text; - if ($("autoTMM").selectedIndex === 1) { + if (document.getElementById("autoTMM").selectedIndex === 1) { const categoryName = item.value; const category = categories[categoryName]; let savePath = defaultSavePath; if (category !== undefined) savePath = (category["savePath"] !== "") ? category["savePath"] : `${defaultSavePath}/${categoryName}`; - $("savepath").value = savePath; + document.getElementById("savepath").value = savePath; } } }; const changeTMM = (item) => { if (item.selectedIndex === 1) { - $("savepath").disabled = true; + document.getElementById("savepath").disabled = true; - const categorySelect = $("categorySelect"); + const categorySelect = document.getElementById("categorySelect"); const categoryName = categorySelect.options[categorySelect.selectedIndex].value; const category = categories[categoryName]; - $("savepath").value = (category === undefined) ? "" : category["savePath"]; + document.getElementById("savepath").value = (category === undefined) ? "" : category["savePath"]; } else { - $("savepath").disabled = false; - $("savepath").value = defaultSavePath; + document.getElementById("savepath").disabled = false; + document.getElementById("savepath").value = defaultSavePath; } }; diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index d05cd8c53..ea9d46d41 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -1762,8 +1762,8 @@ window.qBittorrent.DynamicTable ??= (() => { getFilteredAndSortedRows: function() { const filteredRows = []; - const useRegex = $("torrentsFilterRegexBox").checked; - const filterText = $("torrentsFilterInput").value.trim().toLowerCase(); + const useRegex = document.getElementById("torrentsFilterRegexBox").checked; + const filterText = document.getElementById("torrentsFilterInput").value.trim().toLowerCase(); let filterTerms; try { filterTerms = (filterText.length > 0) @@ -2021,7 +2021,7 @@ window.qBittorrent.DynamicTable ??= (() => { const filterTerms = window.qBittorrent.Search.searchText.filterPattern.toLowerCase().split(" "); const sizeFilters = getSizeFilters(); const seedsFilters = getSeedsFilters(); - const searchInTorrentName = $("searchInTorrentName").value === "names"; + const searchInTorrentName = document.getElementById("searchInTorrentName").value === "names"; if (searchInTorrentName || (filterTerms.length > 0) || (window.qBittorrent.Search.searchSizeFilter.min > 0.00) || (window.qBittorrent.Search.searchSizeFilter.max > 0.00)) { for (const row of this.getRowValues()) { @@ -3263,7 +3263,7 @@ window.qBittorrent.DynamicTable ??= (() => { this.newColumn("name", "", "", -1, true); this.columns["checked"].updateTd = function(td, row) { - if ($(`cbRssDlRule${row.rowId}`) === null) { + if (document.getElementById(`cbRssDlRule${row.rowId}`) === null) { const checkbox = document.createElement("input"); checkbox.type = "checkbox"; checkbox.id = `cbRssDlRule${row.rowId}`; @@ -3281,7 +3281,7 @@ window.qBittorrent.DynamicTable ??= (() => { td.append(checkbox); } else { - $(`cbRssDlRule${row.rowId}`).checked = row.full_data.checked; + document.getElementById(`cbRssDlRule${row.rowId}`).checked = row.full_data.checked; } }; this.columns["checked"].staticWidth = 50; @@ -3361,7 +3361,7 @@ window.qBittorrent.DynamicTable ??= (() => { this.newColumn("name", "", "", -1, true); this.columns["checked"].updateTd = function(td, row) { - if ($(`cbRssDlFeed${row.rowId}`) === null) { + if (document.getElementById(`cbRssDlFeed${row.rowId}`) === null) { const checkbox = document.createElement("input"); checkbox.type = "checkbox"; checkbox.id = `cbRssDlFeed${row.rowId}`; @@ -3378,7 +3378,7 @@ window.qBittorrent.DynamicTable ??= (() => { td.append(checkbox); } else { - $(`cbRssDlFeed${row.rowId}`).checked = row.full_data.checked; + document.getElementById(`cbRssDlFeed${row.rowId}`).checked = row.full_data.checked; } }; this.columns["checked"].staticWidth = 50; diff --git a/src/webui/www/private/scripts/mocha-init.js b/src/webui/www/private/scripts/mocha-init.js index 52bba2d4d..314d84d22 100644 --- a/src/webui/www/private/scripts/mocha-init.js +++ b/src/webui/www/private/scripts/mocha-init.js @@ -151,7 +151,7 @@ let exportTorrentFN = () => {}; const initializeWindows = () => { saveWindowSize = (windowId) => { - const size = $(windowId).getSize(); + const size = document.getElementById(windowId).getSize(); LocalPreferences.set(`window_${windowId}_width`, size.x); LocalPreferences.set(`window_${windowId}_height`, size.y); }; @@ -166,8 +166,8 @@ const initializeWindows = () => { const addClickEvent = (el, fn) => { ["Link", "Button"].each((item) => { - if ($(el + item)) - $(el + item).addEventListener("click", fn); + if (document.getElementById(el + item)) + document.getElementById(el + item).addEventListener("click", fn); }); }; diff --git a/src/webui/www/private/scripts/piecesbar.js b/src/webui/www/private/scripts/piecesbar.js index 49d159cb1..803087f24 100644 --- a/src/webui/www/private/scripts/piecesbar.js +++ b/src/webui/www/private/scripts/piecesbar.js @@ -251,7 +251,7 @@ window.qBittorrent.PiecesBar ??= (() => { } const checkForParent = (id) => { - const obj = $(id); + const obj = document.getElementById(id); if (!obj) return; if (!obj.parentNode) diff --git a/src/webui/www/private/scripts/progressbar.js b/src/webui/www/private/scripts/progressbar.js index 5489b8877..0812024cf 100644 --- a/src/webui/www/private/scripts/progressbar.js +++ b/src/webui/www/private/scripts/progressbar.js @@ -142,7 +142,7 @@ window.qBittorrent.ProgressBar ??= (() => { } const ProgressBar_checkForParent = (id) => { - const obj = $(id); + const obj = document.getElementById(id); if (!obj) return; if (!obj.parentNode) diff --git a/src/webui/www/private/scripts/prop-files.js b/src/webui/www/private/scripts/prop-files.js index 1aa2665b9..0d9ce76b9 100644 --- a/src/webui/www/private/scripts/prop-files.js +++ b/src/webui/www/private/scripts/prop-files.js @@ -208,7 +208,7 @@ window.qBittorrent.PropFiles ??= (() => { const rowIds = []; const fileIds = []; let priority = FilePriority.Ignored; - const checkbox = $("tristate_cb"); + const checkbox = document.getElementById("tristate_cb"); if (checkbox.state === "checked") { setCheckboxUnchecked(checkbox); @@ -245,7 +245,7 @@ window.qBittorrent.PropFiles ??= (() => { }; const updateGlobalCheckbox = () => { - const checkbox = $("tristate_cb"); + const checkbox = document.getElementById("tristate_cb"); if (torrentFilesTable.isAllCheckboxesChecked()) setCheckboxChecked(checkbox); else if (torrentFilesTable.isAllCheckboxesUnchecked()) @@ -297,7 +297,7 @@ window.qBittorrent.PropFiles ??= (() => { ids.forEach((id) => { torrentFilesTable.setIgnored(id, ignore); - const combobox = $(`comboPrio${id}`); + const combobox = document.getElementById(`comboPrio${id}`); if (combobox !== null) selectComboboxPriority(combobox, priority); }); @@ -307,8 +307,8 @@ window.qBittorrent.PropFiles ??= (() => { const loadTorrentFilesData = () => { if (document.hidden) return; - if ($("propFiles").classList.contains("invisible") - || $("propertiesPanel_collapseToggle").classList.contains("panel-expand")) { + if (document.getElementById("propFiles").classList.contains("invisible") + || document.getElementById("propertiesPanel_collapseToggle").classList.contains("panel-expand")) { // Tab changed, don't do anything return; } @@ -586,10 +586,10 @@ window.qBittorrent.PropFiles ??= (() => { // listen for changes to torrentFilesFilterInput let torrentFilesFilterInputTimer = -1; - $("torrentFilesFilterInput").addEventListener("input", () => { + document.getElementById("torrentFilesFilterInput").addEventListener("input", () => { clearTimeout(torrentFilesFilterInputTimer); - const value = $("torrentFilesFilterInput").value; + const value = document.getElementById("torrentFilesFilterInput").value; torrentFilesTable.setFilter(value); torrentFilesFilterInputTimer = setTimeout(() => { diff --git a/src/webui/www/private/scripts/prop-general.js b/src/webui/www/private/scripts/prop-general.js index d93c9b746..fce3c84a6 100644 --- a/src/webui/www/private/scripts/prop-general.js +++ b/src/webui/www/private/scripts/prop-general.js @@ -40,37 +40,37 @@ window.qBittorrent.PropGeneral ??= (() => { const piecesBar = new window.qBittorrent.PiecesBar.PiecesBar([], { height: 18 }); - $("progress").appendChild(piecesBar); + document.getElementById("progress").appendChild(piecesBar); const clearData = () => { document.getElementById("progressPercentage").textContent = ""; - $("time_elapsed").textContent = ""; - $("eta").textContent = ""; - $("nb_connections").textContent = ""; - $("total_downloaded").textContent = ""; - $("total_uploaded").textContent = ""; - $("dl_speed").textContent = ""; - $("up_speed").textContent = ""; - $("dl_limit").textContent = ""; - $("up_limit").textContent = ""; - $("total_wasted").textContent = ""; - $("seeds").textContent = ""; - $("peers").textContent = ""; - $("share_ratio").textContent = ""; - $("popularity").textContent = ""; - $("reannounce").textContent = ""; - $("last_seen").textContent = ""; - $("total_size").textContent = ""; - $("pieces").textContent = ""; - $("created_by").textContent = ""; - $("addition_date").textContent = ""; - $("completion_date").textContent = ""; - $("creation_date").textContent = ""; - $("torrent_hash_v1").textContent = ""; - $("torrent_hash_v2").textContent = ""; - $("save_path").textContent = ""; - $("comment").textContent = ""; - $("private").textContent = ""; + document.getElementById("time_elapsed").textContent = ""; + document.getElementById("eta").textContent = ""; + document.getElementById("nb_connections").textContent = ""; + document.getElementById("total_downloaded").textContent = ""; + document.getElementById("total_uploaded").textContent = ""; + document.getElementById("dl_speed").textContent = ""; + document.getElementById("up_speed").textContent = ""; + document.getElementById("dl_limit").textContent = ""; + document.getElementById("up_limit").textContent = ""; + document.getElementById("total_wasted").textContent = ""; + document.getElementById("seeds").textContent = ""; + document.getElementById("peers").textContent = ""; + document.getElementById("share_ratio").textContent = ""; + document.getElementById("popularity").textContent = ""; + document.getElementById("reannounce").textContent = ""; + document.getElementById("last_seen").textContent = ""; + document.getElementById("total_size").textContent = ""; + document.getElementById("pieces").textContent = ""; + document.getElementById("created_by").textContent = ""; + document.getElementById("addition_date").textContent = ""; + document.getElementById("completion_date").textContent = ""; + document.getElementById("creation_date").textContent = ""; + document.getElementById("torrent_hash_v1").textContent = ""; + document.getElementById("torrent_hash_v2").textContent = ""; + document.getElementById("save_path").textContent = ""; + document.getElementById("comment").textContent = ""; + document.getElementById("private").textContent = ""; piecesBar.clear(); }; @@ -78,8 +78,8 @@ window.qBittorrent.PropGeneral ??= (() => { const loadTorrentData = () => { if (document.hidden) return; - if ($("propGeneral").classList.contains("invisible") - || $("propertiesPanel_collapseToggle").classList.contains("panel-expand")) { + if (document.getElementById("propGeneral").classList.contains("invisible") + || document.getElementById("propertiesPanel_collapseToggle").classList.contains("panel-expand")) { // Tab changed, don't do anything return; } @@ -100,13 +100,13 @@ window.qBittorrent.PropGeneral ??= (() => { }) .then(async (response) => { if (!response.ok) { - $("error_div").textContent = "QBT_TR(qBittorrent client is not reachable)QBT_TR[CONTEXT=HttpServer]"; + document.getElementById("error_div").textContent = "QBT_TR(qBittorrent client is not reachable)QBT_TR[CONTEXT=HttpServer]"; clearTimeout(loadTorrentDataTimer); loadTorrentDataTimer = loadTorrentData.delay(10000); return; } - $("error_div").textContent = ""; + document.getElementById("error_div").textContent = ""; const data = await response.json(); if (data) { @@ -119,70 +119,70 @@ window.qBittorrent.PropGeneral ??= (() => { .replace("%1", window.qBittorrent.Misc.friendlyDuration(data.time_elapsed)) .replace("%2", window.qBittorrent.Misc.friendlyDuration(data.seeding_time)) : window.qBittorrent.Misc.friendlyDuration(data.time_elapsed); - $("time_elapsed").textContent = timeElapsed; + document.getElementById("time_elapsed").textContent = timeElapsed; - $("eta").textContent = window.qBittorrent.Misc.friendlyDuration(data.eta, window.qBittorrent.Misc.MAX_ETA); + document.getElementById("eta").textContent = window.qBittorrent.Misc.friendlyDuration(data.eta, window.qBittorrent.Misc.MAX_ETA); const nbConnections = "QBT_TR(%1 (%2 max))QBT_TR[CONTEXT=PropertiesWidget]" .replace("%1", data.nb_connections) .replace("%2", ((data.nb_connections_limit < 0) ? "∞" : data.nb_connections_limit)); - $("nb_connections").textContent = nbConnections; + document.getElementById("nb_connections").textContent = nbConnections; const totalDownloaded = "QBT_TR(%1 (%2 this session))QBT_TR[CONTEXT=PropertiesWidget]" .replace("%1", window.qBittorrent.Misc.friendlyUnit(data.total_downloaded)) .replace("%2", window.qBittorrent.Misc.friendlyUnit(data.total_downloaded_session)); - $("total_downloaded").textContent = totalDownloaded; + document.getElementById("total_downloaded").textContent = totalDownloaded; const totalUploaded = "QBT_TR(%1 (%2 this session))QBT_TR[CONTEXT=PropertiesWidget]" .replace("%1", window.qBittorrent.Misc.friendlyUnit(data.total_uploaded)) .replace("%2", window.qBittorrent.Misc.friendlyUnit(data.total_uploaded_session)); - $("total_uploaded").textContent = totalUploaded; + document.getElementById("total_uploaded").textContent = totalUploaded; const dlSpeed = "QBT_TR(%1 (%2 avg.))QBT_TR[CONTEXT=PropertiesWidget]" .replace("%1", window.qBittorrent.Misc.friendlyUnit(data.dl_speed, true)) .replace("%2", window.qBittorrent.Misc.friendlyUnit(data.dl_speed_avg, true)); - $("dl_speed").textContent = dlSpeed; + document.getElementById("dl_speed").textContent = dlSpeed; const upSpeed = "QBT_TR(%1 (%2 avg.))QBT_TR[CONTEXT=PropertiesWidget]" .replace("%1", window.qBittorrent.Misc.friendlyUnit(data.up_speed, true)) .replace("%2", window.qBittorrent.Misc.friendlyUnit(data.up_speed_avg, true)); - $("up_speed").textContent = upSpeed; + document.getElementById("up_speed").textContent = upSpeed; const dlLimit = (data.dl_limit === -1) ? "∞" : window.qBittorrent.Misc.friendlyUnit(data.dl_limit, true); - $("dl_limit").textContent = dlLimit; + document.getElementById("dl_limit").textContent = dlLimit; const upLimit = (data.up_limit === -1) ? "∞" : window.qBittorrent.Misc.friendlyUnit(data.up_limit, true); - $("up_limit").textContent = upLimit; + document.getElementById("up_limit").textContent = upLimit; - $("total_wasted").textContent = window.qBittorrent.Misc.friendlyUnit(data.total_wasted); + document.getElementById("total_wasted").textContent = window.qBittorrent.Misc.friendlyUnit(data.total_wasted); const seeds = "QBT_TR(%1 (%2 total))QBT_TR[CONTEXT=PropertiesWidget]" .replace("%1", data.seeds) .replace("%2", data.seeds_total); - $("seeds").textContent = seeds; + document.getElementById("seeds").textContent = seeds; const peers = "QBT_TR(%1 (%2 total))QBT_TR[CONTEXT=PropertiesWidget]" .replace("%1", data.peers) .replace("%2", data.peers_total); - $("peers").textContent = peers; + document.getElementById("peers").textContent = peers; - $("share_ratio").textContent = data.share_ratio.toFixed(2); + document.getElementById("share_ratio").textContent = data.share_ratio.toFixed(2); - $("popularity").textContent = data.popularity.toFixed(2); + document.getElementById("popularity").textContent = data.popularity.toFixed(2); - $("reannounce").textContent = window.qBittorrent.Misc.friendlyDuration(data.reannounce); + document.getElementById("reannounce").textContent = window.qBittorrent.Misc.friendlyDuration(data.reannounce); const lastSeen = (data.last_seen >= 0) ? new Date(data.last_seen * 1000).toLocaleString() : "QBT_TR(Never)QBT_TR[CONTEXT=PropertiesWidget]"; - $("last_seen").textContent = lastSeen; + document.getElementById("last_seen").textContent = lastSeen; const totalSize = (data.total_size >= 0) ? window.qBittorrent.Misc.friendlyUnit(data.total_size) : ""; - $("total_size").textContent = totalSize; + document.getElementById("total_size").textContent = totalSize; const pieces = (data.pieces_num >= 0) ? "QBT_TR(%1 x %2 (have %3))QBT_TR[CONTEXT=PropertiesWidget]" @@ -190,40 +190,40 @@ window.qBittorrent.PropGeneral ??= (() => { .replace("%2", window.qBittorrent.Misc.friendlyUnit(data.piece_size)) .replace("%3", data.pieces_have) : ""; - $("pieces").textContent = pieces; + document.getElementById("pieces").textContent = pieces; - $("created_by").textContent = data.created_by; + document.getElementById("created_by").textContent = data.created_by; const additionDate = (data.addition_date >= 0) ? new Date(data.addition_date * 1000).toLocaleString() : "QBT_TR(Unknown)QBT_TR[CONTEXT=HttpServer]"; - $("addition_date").textContent = additionDate; + document.getElementById("addition_date").textContent = additionDate; const completionDate = (data.completion_date >= 0) ? new Date(data.completion_date * 1000).toLocaleString() : ""; - $("completion_date").textContent = completionDate; + document.getElementById("completion_date").textContent = completionDate; const creationDate = (data.creation_date >= 0) ? new Date(data.creation_date * 1000).toLocaleString() : ""; - $("creation_date").textContent = creationDate; + document.getElementById("creation_date").textContent = creationDate; const torrentHashV1 = (data.infohash_v1 !== "") ? data.infohash_v1 : "QBT_TR(N/A)QBT_TR[CONTEXT=PropertiesWidget]"; - $("torrent_hash_v1").textContent = torrentHashV1; + document.getElementById("torrent_hash_v1").textContent = torrentHashV1; const torrentHashV2 = (data.infohash_v2 !== "") ? data.infohash_v2 : "QBT_TR(N/A)QBT_TR[CONTEXT=PropertiesWidget]"; - $("torrent_hash_v2").textContent = torrentHashV2; + document.getElementById("torrent_hash_v2").textContent = torrentHashV2; - $("save_path").textContent = data.save_path; + document.getElementById("save_path").textContent = data.save_path; - $("comment").innerHTML = window.qBittorrent.Misc.parseHtmlLinks(window.qBittorrent.Misc.escapeHtml(data.comment)); + document.getElementById("comment").innerHTML = window.qBittorrent.Misc.parseHtmlLinks(window.qBittorrent.Misc.escapeHtml(data.comment)); - $("private").textContent = (data.has_metadata + document.getElementById("private").textContent = (data.has_metadata ? (data.private ? "QBT_TR(Yes)QBT_TR[CONTEXT=PropertiesWidget]" : "QBT_TR(No)QBT_TR[CONTEXT=PropertiesWidget]") @@ -246,13 +246,13 @@ window.qBittorrent.PropGeneral ??= (() => { }) .then(async (response) => { if (!response.ok) { - $("error_div").textContent = "QBT_TR(qBittorrent client is not reachable)QBT_TR[CONTEXT=HttpServer]"; + document.getElementById("error_div").textContent = "QBT_TR(qBittorrent client is not reachable)QBT_TR[CONTEXT=HttpServer]"; clearTimeout(loadTorrentDataTimer); loadTorrentDataTimer = loadTorrentData.delay(10000); return; } - $("error_div").textContent = ""; + document.getElementById("error_div").textContent = ""; const data = await response.json(); if (data) diff --git a/src/webui/www/private/scripts/prop-peers.js b/src/webui/www/private/scripts/prop-peers.js index 8ccb2cbd1..f718d04e6 100644 --- a/src/webui/www/private/scripts/prop-peers.js +++ b/src/webui/www/private/scripts/prop-peers.js @@ -45,8 +45,8 @@ window.qBittorrent.PropPeers ??= (() => { const loadTorrentPeersData = () => { if (document.hidden) return; - if ($("propPeers").classList.contains("invisible") - || $("propertiesPanel_collapseToggle").classList.contains("panel-expand")) { + if (document.getElementById("propPeers").classList.contains("invisible") + || document.getElementById("propertiesPanel_collapseToggle").classList.contains("panel-expand")) { syncTorrentPeersLastResponseId = 0; torrentPeersTable.clear(); return; @@ -73,7 +73,7 @@ window.qBittorrent.PropPeers ??= (() => { const responseJSON = await response.json(); - $("error_div").textContent = ""; + document.getElementById("error_div").textContent = ""; if (responseJSON) { const full_update = (responseJSON["full_update"] === true); if (full_update) diff --git a/src/webui/www/private/scripts/prop-trackers.js b/src/webui/www/private/scripts/prop-trackers.js index e75709724..05a5de700 100644 --- a/src/webui/www/private/scripts/prop-trackers.js +++ b/src/webui/www/private/scripts/prop-trackers.js @@ -45,8 +45,8 @@ window.qBittorrent.PropTrackers ??= (() => { const loadTrackersData = () => { if (document.hidden) return; - if ($("propTrackers").classList.contains("invisible") - || $("propertiesPanel_collapseToggle").classList.contains("panel-expand")) { + if (document.getElementById("propTrackers").classList.contains("invisible") + || document.getElementById("propertiesPanel_collapseToggle").classList.contains("panel-expand")) { // Tab changed, don't do anything return; } diff --git a/src/webui/www/private/scripts/prop-webseeds.js b/src/webui/www/private/scripts/prop-webseeds.js index 7fd517597..737642f69 100644 --- a/src/webui/www/private/scripts/prop-webseeds.js +++ b/src/webui/www/private/scripts/prop-webseeds.js @@ -45,8 +45,8 @@ window.qBittorrent.PropWebseeds ??= (() => { const loadWebSeedsData = () => { if (document.hidden) return; - if ($("propWebSeeds").classList.contains("invisible") - || $("propertiesPanel_collapseToggle").classList.contains("panel-expand")) { + if (document.getElementById("propWebSeeds").classList.contains("invisible") + || document.getElementById("propertiesPanel_collapseToggle").classList.contains("panel-expand")) { // Tab changed, don't do anything return; } diff --git a/src/webui/www/private/scripts/search.js b/src/webui/www/private/scripts/search.js index 3dc0b454b..5d9d8c946 100644 --- a/src/webui/www/private/scripts/search.js +++ b/src/webui/www/private/scripts/search.js @@ -107,7 +107,7 @@ window.qBittorrent.Search ??= (() => { const init = () => { // load "Search in" preference from local storage - $("searchInTorrentName").value = (LocalPreferences.get("search_in_filter") === "names") ? "names" : "everywhere"; + document.getElementById("searchInTorrentName").value = (LocalPreferences.get("search_in_filter") === "names") ? "names" : "everywhere"; const searchResultsTableContextMenu = new window.qBittorrent.ContextMenu.ContextMenu({ targets: "#searchResultsTableDiv tbody tr", menu: "searchResultsTableMenu", @@ -128,12 +128,12 @@ window.qBittorrent.Search ??= (() => { // listen for changes to searchInNameFilter let searchInNameFilterTimer = -1; - $("searchInNameFilter").addEventListener("input", () => { + document.getElementById("searchInNameFilter").addEventListener("input", () => { clearTimeout(searchInNameFilterTimer); searchInNameFilterTimer = setTimeout(() => { searchInNameFilterTimer = -1; - const value = $("searchInNameFilter").value; + const value = document.getElementById("searchInNameFilter").value; searchText.filterPattern = value; searchFilterChanged(); }, window.qBittorrent.Misc.FILTER_INPUT_DELAY); @@ -200,15 +200,15 @@ window.qBittorrent.Search ??= (() => { document.getElementById("startSearchButton").lastChild.textContent = "QBT_TR(Search)QBT_TR[CONTEXT=SearchEngineWidget]"; }); listItem.appendChild(tabElem); - $("searchTabs").appendChild(listItem); + document.getElementById("searchTabs").appendChild(listItem); searchResultsTabsContextMenu.addTarget(listItem); // unhide the results elements if (numSearchTabs() >= 1) { - $("searchResultsNoSearches").classList.add("invisible"); - $("searchResultsFilters").classList.remove("invisible"); - $("searchResultsTableContainer").classList.remove("invisible"); - $("searchTabsToolbar").classList.remove("invisible"); + document.getElementById("searchResultsNoSearches").classList.add("invisible"); + document.getElementById("searchResultsFilters").classList.remove("invisible"); + document.getElementById("searchResultsTableContainer").classList.remove("invisible"); + document.getElementById("searchTabsToolbar").classList.remove("invisible"); } // select new tab @@ -268,12 +268,12 @@ window.qBittorrent.Search ??= (() => { resetSearchState(); resetFilters(); - $("numSearchResultsVisible").textContent = 0; - $("numSearchResultsTotal").textContent = 0; - $("searchResultsNoSearches").classList.remove("invisible"); - $("searchResultsFilters").classList.add("invisible"); - $("searchResultsTableContainer").classList.add("invisible"); - $("searchTabsToolbar").classList.add("invisible"); + document.getElementById("numSearchResultsVisible").textContent = 0; + document.getElementById("numSearchResultsTotal").textContent = 0; + document.getElementById("searchResultsNoSearches").classList.remove("invisible"); + document.getElementById("searchResultsFilters").classList.add("invisible"); + document.getElementById("searchResultsTableContainer").classList.add("invisible"); + document.getElementById("searchTabsToolbar").classList.add("invisible"); } else if (isTabSelected && newTabToSelect) { setActiveTab(newTabToSelect); @@ -335,23 +335,23 @@ window.qBittorrent.Search ??= (() => { // restore filters searchText.pattern = state.searchPattern; searchText.filterPattern = state.filterPattern; - $("searchInNameFilter").value = state.filterPattern; + document.getElementById("searchInNameFilter").value = state.filterPattern; searchSeedsFilter.min = state.seedsFilter.min; searchSeedsFilter.max = state.seedsFilter.max; - $("searchMinSeedsFilter").value = state.seedsFilter.min; - $("searchMaxSeedsFilter").value = state.seedsFilter.max; + document.getElementById("searchMinSeedsFilter").value = state.seedsFilter.min; + document.getElementById("searchMaxSeedsFilter").value = state.seedsFilter.max; searchSizeFilter.min = state.sizeFilter.min; searchSizeFilter.minUnit = state.sizeFilter.minUnit; searchSizeFilter.max = state.sizeFilter.max; searchSizeFilter.maxUnit = state.sizeFilter.maxUnit; - $("searchMinSizeFilter").value = state.sizeFilter.min; - $("searchMinSizePrefix").value = state.sizeFilter.minUnit; - $("searchMaxSizeFilter").value = state.sizeFilter.max; - $("searchMaxSizePrefix").value = state.sizeFilter.maxUnit; + document.getElementById("searchMinSizeFilter").value = state.sizeFilter.min; + document.getElementById("searchMinSizePrefix").value = state.sizeFilter.minUnit; + document.getElementById("searchMaxSizeFilter").value = state.sizeFilter.max; + document.getElementById("searchMaxSizePrefix").value = state.sizeFilter.maxUnit; - const currentSearchPattern = $("searchPattern").value.trim(); + const currentSearchPattern = document.getElementById("searchPattern").value.trim(); if (state.running && (state.searchPattern === currentSearchPattern)) { // allow search to be stopped document.getElementById("startSearchButton").lastChild.textContent = "QBT_TR(Stop)QBT_TR[CONTEXT=SearchEngineWidget]"; @@ -360,7 +360,7 @@ window.qBittorrent.Search ??= (() => { searchResultsTable.setSortedColumn(state.sort.column, state.sort.reverse); - $("searchInTorrentName").value = state.searchIn; + document.getElementById("searchInTorrentName").value = state.searchIn; } // must restore all filters before calling updateTable @@ -370,8 +370,8 @@ window.qBittorrent.Search ??= (() => { if (rowsToSelect.length > 0) searchResultsTable.reselectRows(rowsToSelect); - $("numSearchResultsVisible").textContent = searchResultsTable.getFilteredAndSortedRows().length; - $("numSearchResultsTotal").textContent = searchResultsTable.getRowSize(); + document.getElementById("numSearchResultsVisible").textContent = searchResultsTable.getFilteredAndSortedRows().length; + document.getElementById("numSearchResultsTotal").textContent = searchResultsTable.getRowSize(); }; const getStatusIconElement = (text, image) => { @@ -386,7 +386,7 @@ window.qBittorrent.Search ??= (() => { }; const updateStatusIconElement = (searchId, text, image) => { - const searchTab = $(`${searchTabIdPrefix}${searchId}`); + const searchTab = document.getElementById(`${searchTabIdPrefix}${searchId}`); if (searchTab) { const statusIcon = searchTab.querySelector(".statusIcon"); statusIcon.alt = text; @@ -439,7 +439,7 @@ window.qBittorrent.Search ??= (() => { }; const getSelectedSearchId = () => { - const selectedTab = $("searchTabs").querySelector("li.selected"); + const selectedTab = document.getElementById("searchTabs").querySelector("li.selected"); return selectedTab ? getSearchIdFromTab(selectedTab) : null; }; @@ -448,9 +448,9 @@ window.qBittorrent.Search ??= (() => { const state = searchState.get(currentSearchId); const isSearchRunning = state && state.running; if (!isSearchRunning || searchPatternChanged) { - const pattern = $("searchPattern").value.trim(); - const category = $("categorySelect").value; - const plugins = $("pluginsSelect").value; + const pattern = document.getElementById("searchPattern").value.trim(); + const category = document.getElementById("categorySelect").value; + const plugins = document.getElementById("pluginsSelect").value; if (!pattern || !category || !plugins) return; @@ -506,7 +506,7 @@ window.qBittorrent.Search ??= (() => { const manageSearchPlugins = () => { const id = "searchPlugins"; - if (!$(id)) { + if (!document.getElementById(id)) { new MochaUI.Window({ id: id, title: "QBT_TR(Search plugins)QBT_TR[CONTEXT=PluginSelectDlg]", @@ -541,7 +541,7 @@ window.qBittorrent.Search ??= (() => { const onSearchPatternChanged = () => { const currentSearchId = getSelectedSearchId(); const state = searchState.get(currentSearchId); - const currentSearchPattern = $("searchPattern").value.trim(); + const currentSearchPattern = document.getElementById("searchPattern").value.trim(); // start a new search if pattern has changed, otherwise allow the search to be stopped if (state && (state.searchPattern === currentSearchPattern)) { searchPatternChanged = false; @@ -554,11 +554,11 @@ window.qBittorrent.Search ??= (() => { }; const categorySelected = () => { - selectedCategory = $("categorySelect").value; + selectedCategory = document.getElementById("categorySelect").value; }; const pluginSelected = () => { - selectedPlugin = $("pluginsSelect").value; + selectedPlugin = document.getElementById("pluginsSelect").value; if (selectedPlugin !== prevSelectedPlugin) { prevSelectedPlugin = selectedPlugin; @@ -567,18 +567,18 @@ window.qBittorrent.Search ??= (() => { }; const reselectCategory = () => { - for (let i = 0; i < $("categorySelect").options.length; ++i) { - if ($("categorySelect").options[i].get("value") === selectedCategory) - $("categorySelect").options[i].selected = true; + for (let i = 0; i < document.getElementById("categorySelect").options.length; ++i) { + if (document.getElementById("categorySelect").options[i].get("value") === selectedCategory) + document.getElementById("categorySelect").options[i].selected = true; } categorySelected(); }; const reselectPlugin = () => { - for (let i = 0; i < $("pluginsSelect").options.length; ++i) { - if ($("pluginsSelect").options[i].get("value") === selectedPlugin) - $("pluginsSelect").options[i].selected = true; + for (let i = 0; i < document.getElementById("pluginsSelect").options.length; ++i) { + if (document.getElementById("pluginsSelect").options[i].get("value") === selectedPlugin) + document.getElementById("pluginsSelect").options[i].selected = true; } pluginSelected(); @@ -614,10 +614,10 @@ window.qBittorrent.Search ??= (() => { categoryOptions.splice(1, 0, option); } - $("categorySelect").replaceChildren(...categoryOptions); + document.getElementById("categorySelect").replaceChildren(...categoryOptions); }; - const selectedPlugin = $("pluginsSelect").value; + const selectedPlugin = document.getElementById("pluginsSelect").value; if ((selectedPlugin === "all") || (selectedPlugin === "enabled")) { const uniqueCategories = {}; @@ -675,9 +675,9 @@ window.qBittorrent.Search ??= (() => { const searchPluginsEmpty = (searchPlugins.length === 0); if (!searchPluginsEmpty) { - $("searchResultsNoPlugins").classList.add("invisible"); + document.getElementById("searchResultsNoPlugins").classList.add("invisible"); if (numSearchTabs() === 0) - $("searchResultsNoSearches").classList.remove("invisible"); + document.getElementById("searchResultsNoSearches").classList.remove("invisible"); // sort plugins alphabetically const allPlugins = searchPlugins.sort((left, right) => { @@ -695,11 +695,11 @@ window.qBittorrent.Search ??= (() => { pluginOptions.splice(2, 0, createOption("──────────", undefined, true)); } - $("pluginsSelect").replaceChildren(...pluginOptions); + document.getElementById("pluginsSelect").replaceChildren(...pluginOptions); - $("searchPattern").disabled = searchPluginsEmpty; - $("categorySelect").disabled = searchPluginsEmpty; - $("pluginsSelect").disabled = searchPluginsEmpty; + document.getElementById("searchPattern").disabled = searchPluginsEmpty; + document.getElementById("categorySelect").disabled = searchPluginsEmpty; + document.getElementById("pluginsSelect").disabled = searchPluginsEmpty; document.getElementById("startSearchButton").disabled = searchPluginsEmpty; if (window.qBittorrent.SearchPlugins !== undefined) @@ -721,25 +721,25 @@ window.qBittorrent.Search ??= (() => { const resetFilters = () => { searchText.filterPattern = ""; - $("searchInNameFilter").value = ""; + document.getElementById("searchInNameFilter").value = ""; searchSeedsFilter.min = 0; searchSeedsFilter.max = 0; - $("searchMinSeedsFilter").value = searchSeedsFilter.min; - $("searchMaxSeedsFilter").value = searchSeedsFilter.max; + document.getElementById("searchMinSeedsFilter").value = searchSeedsFilter.min; + document.getElementById("searchMaxSeedsFilter").value = searchSeedsFilter.max; searchSizeFilter.min = 0.00; searchSizeFilter.minUnit = 2; // B = 0, KiB = 1, MiB = 2, GiB = 3, TiB = 4, PiB = 5, EiB = 6 searchSizeFilter.max = 0.00; searchSizeFilter.maxUnit = 3; - $("searchMinSizeFilter").value = searchSizeFilter.min; - $("searchMinSizePrefix").value = searchSizeFilter.minUnit; - $("searchMaxSizeFilter").value = searchSizeFilter.max; - $("searchMaxSizePrefix").value = searchSizeFilter.maxUnit; + document.getElementById("searchMinSizeFilter").value = searchSizeFilter.min; + document.getElementById("searchMinSizePrefix").value = searchSizeFilter.minUnit; + document.getElementById("searchMaxSizeFilter").value = searchSizeFilter.max; + document.getElementById("searchMaxSizePrefix").value = searchSizeFilter.maxUnit; }; const getSearchInTorrentName = () => { - return ($("searchInTorrentName").value === "names") ? "names" : "everywhere"; + return (document.getElementById("searchInTorrentName").value === "names") ? "names" : "everywhere"; }; const searchInTorrentName = () => { @@ -748,29 +748,29 @@ window.qBittorrent.Search ??= (() => { }; const searchSeedsFilterChanged = () => { - searchSeedsFilter.min = $("searchMinSeedsFilter").value; - searchSeedsFilter.max = $("searchMaxSeedsFilter").value; + searchSeedsFilter.min = document.getElementById("searchMinSeedsFilter").value; + searchSeedsFilter.max = document.getElementById("searchMaxSeedsFilter").value; searchFilterChanged(); }; const searchSizeFilterChanged = () => { - searchSizeFilter.min = $("searchMinSizeFilter").value; - searchSizeFilter.minUnit = $("searchMinSizePrefix").value; - searchSizeFilter.max = $("searchMaxSizeFilter").value; - searchSizeFilter.maxUnit = $("searchMaxSizePrefix").value; + searchSizeFilter.min = document.getElementById("searchMinSizeFilter").value; + searchSizeFilter.minUnit = document.getElementById("searchMinSizePrefix").value; + searchSizeFilter.max = document.getElementById("searchMaxSizeFilter").value; + searchSizeFilter.maxUnit = document.getElementById("searchMaxSizePrefix").value; searchFilterChanged(); }; const searchSizeFilterPrefixChanged = () => { - if ((Number($("searchMinSizeFilter").value) !== 0) || (Number($("searchMaxSizeFilter").value) !== 0)) + if ((Number(document.getElementById("searchMinSizeFilter").value) !== 0) || (Number(document.getElementById("searchMaxSizeFilter").value) !== 0)) searchSizeFilterChanged(); }; const searchFilterChanged = () => { searchResultsTable.updateTable(); - $("numSearchResultsVisible").textContent = searchResultsTable.getFilteredAndSortedRows().length; + document.getElementById("numSearchResultsVisible").textContent = searchResultsTable.getFilteredAndSortedRows().length; }; const loadSearchResultsData = function(searchId) { @@ -799,7 +799,7 @@ window.qBittorrent.Search ??= (() => { return; } - $("error_div").textContent = ""; + document.getElementById("error_div").textContent = ""; const state = searchState.get(searchId); // check if user stopped the search prior to receiving the response @@ -842,8 +842,8 @@ window.qBittorrent.Search ??= (() => { for (const row of newRows) searchResultsTable.updateRowData(row); - $("numSearchResultsVisible").textContent = searchResultsTable.getFilteredAndSortedRows().length; - $("numSearchResultsTotal").textContent = searchResultsTable.getRowSize(); + document.getElementById("numSearchResultsVisible").textContent = searchResultsTable.getFilteredAndSortedRows().length; + document.getElementById("numSearchResultsTotal").textContent = searchResultsTable.getRowSize(); searchResultsTable.updateTable(); } diff --git a/src/webui/www/private/scripts/speedslider.js b/src/webui/www/private/scripts/speedslider.js index 24544a8d1..f2c96f66a 100644 --- a/src/webui/www/private/scripts/speedslider.js +++ b/src/webui/www/private/scripts/speedslider.js @@ -30,7 +30,7 @@ MochaUI.extend({ addUpLimitSlider: (hashes) => { - if ($("uplimitSliderarea")) { + if (document.getElementById("uplimitSliderarea")) { // Get global upload limit fetch("api/v2/transfer/uploadLimit", { method: "GET", @@ -61,29 +61,29 @@ MochaUI.extend({ if (up_limit < 0) up_limit = 0; maximum = 10000; - new Slider($("uplimitSliderarea"), $("uplimitSliderknob"), { + new Slider(document.getElementById("uplimitSliderarea"), document.getElementById("uplimitSliderknob"), { steps: maximum, offset: 0, initialStep: Math.round(up_limit), onChange: (pos) => { if (pos > 0) { - $("uplimitUpdatevalue").value = pos; - $("upLimitUnit").style.visibility = "visible"; + document.getElementById("uplimitUpdatevalue").value = pos; + document.getElementById("upLimitUnit").style.visibility = "visible"; } else { - $("uplimitUpdatevalue").value = "∞"; - $("upLimitUnit").style.visibility = "hidden"; + document.getElementById("uplimitUpdatevalue").value = "∞"; + document.getElementById("upLimitUnit").style.visibility = "hidden"; } } }); // Set default value if (up_limit === 0) { - $("uplimitUpdatevalue").value = "∞"; - $("upLimitUnit").style.visibility = "hidden"; + document.getElementById("uplimitUpdatevalue").value = "∞"; + document.getElementById("upLimitUnit").style.visibility = "hidden"; } else { - $("uplimitUpdatevalue").value = Math.round(up_limit); - $("upLimitUnit").style.visibility = "visible"; + document.getElementById("uplimitUpdatevalue").value = Math.round(up_limit); + document.getElementById("upLimitUnit").style.visibility = "visible"; } } else { @@ -108,29 +108,29 @@ MochaUI.extend({ } if (up_limit < 0) up_limit = 0; - new Slider($("uplimitSliderarea"), $("uplimitSliderknob"), { + new Slider(document.getElementById("uplimitSliderarea"), document.getElementById("uplimitSliderknob"), { steps: maximum, offset: 0, initialStep: Math.round(up_limit / 1024), onChange: (pos) => { if (pos > 0) { - $("uplimitUpdatevalue").value = pos; - $("upLimitUnit").style.visibility = "visible"; + document.getElementById("uplimitUpdatevalue").value = pos; + document.getElementById("upLimitUnit").style.visibility = "visible"; } else { - $("uplimitUpdatevalue").value = "∞"; - $("upLimitUnit").style.visibility = "hidden"; + document.getElementById("uplimitUpdatevalue").value = "∞"; + document.getElementById("upLimitUnit").style.visibility = "hidden"; } } }); // Set default value if (up_limit === 0) { - $("uplimitUpdatevalue").value = "∞"; - $("upLimitUnit").style.visibility = "hidden"; + document.getElementById("uplimitUpdatevalue").value = "∞"; + document.getElementById("upLimitUnit").style.visibility = "hidden"; } else { - $("uplimitUpdatevalue").value = Math.round(up_limit / 1024); - $("upLimitUnit").style.visibility = "visible"; + document.getElementById("uplimitUpdatevalue").value = Math.round(up_limit / 1024); + document.getElementById("upLimitUnit").style.visibility = "visible"; } }); } @@ -139,7 +139,7 @@ MochaUI.extend({ }, addDlLimitSlider: (hashes) => { - if ($("dllimitSliderarea")) { + if (document.getElementById("dllimitSliderarea")) { // Get global upload limit fetch("api/v2/transfer/downloadLimit", { method: "GET", @@ -170,29 +170,29 @@ MochaUI.extend({ if (dl_limit < 0) dl_limit = 0; maximum = 10000; - new Slider($("dllimitSliderarea"), $("dllimitSliderknob"), { + new Slider(document.getElementById("dllimitSliderarea"), document.getElementById("dllimitSliderknob"), { steps: maximum, offset: 0, initialStep: Math.round(dl_limit), onChange: (pos) => { if (pos > 0) { - $("dllimitUpdatevalue").value = pos; - $("dlLimitUnit").style.visibility = "visible"; + document.getElementById("dllimitUpdatevalue").value = pos; + document.getElementById("dlLimitUnit").style.visibility = "visible"; } else { - $("dllimitUpdatevalue").value = "∞"; - $("dlLimitUnit").style.visibility = "hidden"; + document.getElementById("dllimitUpdatevalue").value = "∞"; + document.getElementById("dlLimitUnit").style.visibility = "hidden"; } } }); // Set default value if (dl_limit === 0) { - $("dllimitUpdatevalue").value = "∞"; - $("dlLimitUnit").style.visibility = "hidden"; + document.getElementById("dllimitUpdatevalue").value = "∞"; + document.getElementById("dlLimitUnit").style.visibility = "hidden"; } else { - $("dllimitUpdatevalue").value = Math.round(dl_limit); - $("dlLimitUnit").style.visibility = "visible"; + document.getElementById("dllimitUpdatevalue").value = Math.round(dl_limit); + document.getElementById("dlLimitUnit").style.visibility = "visible"; } } else { @@ -217,29 +217,29 @@ MochaUI.extend({ } if (dl_limit < 0) dl_limit = 0; - new Slider($("dllimitSliderarea"), $("dllimitSliderknob"), { + new Slider(document.getElementById("dllimitSliderarea"), document.getElementById("dllimitSliderknob"), { steps: maximum, offset: 0, initialStep: Math.round(dl_limit / 1024), onChange: (pos) => { if (pos > 0) { - $("dllimitUpdatevalue").value = pos; - $("dlLimitUnit").style.visibility = "visible"; + document.getElementById("dllimitUpdatevalue").value = pos; + document.getElementById("dlLimitUnit").style.visibility = "visible"; } else { - $("dllimitUpdatevalue").value = "∞"; - $("dlLimitUnit").style.visibility = "hidden"; + document.getElementById("dllimitUpdatevalue").value = "∞"; + document.getElementById("dlLimitUnit").style.visibility = "hidden"; } } }); // Set default value if (dl_limit === 0) { - $("dllimitUpdatevalue").value = "∞"; - $("dlLimitUnit").style.visibility = "hidden"; + document.getElementById("dllimitUpdatevalue").value = "∞"; + document.getElementById("dlLimitUnit").style.visibility = "hidden"; } else { - $("dllimitUpdatevalue").value = Math.round(dl_limit / 1024); - $("dlLimitUnit").style.visibility = "visible"; + document.getElementById("dllimitUpdatevalue").value = Math.round(dl_limit / 1024); + document.getElementById("dlLimitUnit").style.visibility = "visible"; } }); } diff --git a/src/webui/www/private/setlocation.html b/src/webui/www/private/setlocation.html index 1455340df..e9095fc83 100644 --- a/src/webui/www/private/setlocation.html +++ b/src/webui/www/private/setlocation.html @@ -18,7 +18,7 @@ switch (event.key) { case "Enter": event.preventDefault(); - $("setLocationButton").click(); + document.getElementById("setLocationButton").click(); break; case "Escape": event.preventDefault(); @@ -32,17 +32,17 @@ // set text field to current value if (path !== null) - $("setLocation").value = decodeURIComponent(path); + document.getElementById("setLocation").value = decodeURIComponent(path); - $("setLocation").focus(); - $("setLocationButton").addEventListener("click", (e) => { + document.getElementById("setLocation").focus(); + document.getElementById("setLocationButton").addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); // check field - const location = $("setLocation").value.trim(); + const location = document.getElementById("setLocation").value.trim(); if ((location === null) || (location === "")) { - $("error_div").textContent = "QBT_TR(Save path is empty)QBT_TR[CONTEXT=TorrentsController]"; + document.getElementById("error_div").textContent = "QBT_TR(Save path is empty)QBT_TR[CONTEXT=TorrentsController]"; return; } @@ -55,7 +55,7 @@ }) .then(async (response) => { if (!response.ok) { - $("error_div").textContent = await response.text(); + document.getElementById("error_div").textContent = await response.text(); return; } diff --git a/src/webui/www/private/shareratio.html b/src/webui/www/private/shareratio.html index b106e72b8..cf2993675 100644 --- a/src/webui/www/private/shareratio.html +++ b/src/webui/www/private/shareratio.html @@ -20,7 +20,7 @@ switch (event.key) { case "Enter": event.preventDefault(); - $("save").click(); + document.getElementById("save").click(); break; case "Escape": event.preventDefault(); @@ -56,23 +56,23 @@ else { setSelectedRadioValue("shareLimit", "custom"); if (values.ratioLimit >= 0) { - $("setRatio").checked = true; - $("ratio").value = values.ratioLimit.toFixed(2); + document.getElementById("setRatio").checked = true; + document.getElementById("ratio").value = values.ratioLimit.toFixed(2); } if (values.seedingTimeLimit >= 0) { - $("setTotalMinutes").checked = true; - $("totalMinutes").value = values.seedingTimeLimit; + document.getElementById("setTotalMinutes").checked = true; + document.getElementById("totalMinutes").value = values.seedingTimeLimit; } if (values.inactiveSeedingTimeLimit >= 0) { - $("setInactiveMinutes").checked = true; - $("inactiveMinutes").value = values.inactiveSeedingTimeLimit; + document.getElementById("setInactiveMinutes").checked = true; + document.getElementById("inactiveMinutes").value = values.inactiveSeedingTimeLimit; } } shareLimitChanged(); - $("default").focus(); - $("save").addEventListener("click", (e) => { + document.getElementById("default").focus(); + document.getElementById("save").addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); @@ -91,9 +91,9 @@ ratioLimitValue = seedingTimeLimitValue = inactiveSeedingTimeLimitValue = NoLimit; } else if (shareLimit === "custom") { - ratioLimitValue = $("setRatio").checked ? $("ratio").value : -1; - seedingTimeLimitValue = $("setTotalMinutes").checked ? $("totalMinutes").value : -1; - inactiveSeedingTimeLimitValue = $("setInactiveMinutes").checked ? $("inactiveMinutes").value : -1; + ratioLimitValue = document.getElementById("setRatio").checked ? document.getElementById("ratio").value : -1; + seedingTimeLimitValue = document.getElementById("setTotalMinutes").checked ? document.getElementById("totalMinutes").value : -1; + inactiveSeedingTimeLimitValue = document.getElementById("setInactiveMinutes").checked ? document.getElementById("inactiveMinutes").value : -1; } else { return; @@ -139,26 +139,26 @@ const shareLimitChanged = () => { const customShareLimit = getSelectedRadioValue("shareLimit") === "custom"; - $("setRatio").disabled = !customShareLimit; - $("setTotalMinutes").disabled = !customShareLimit; - $("setInactiveMinutes").disabled = !customShareLimit; + document.getElementById("setRatio").disabled = !customShareLimit; + document.getElementById("setTotalMinutes").disabled = !customShareLimit; + document.getElementById("setInactiveMinutes").disabled = !customShareLimit; enableInputBoxes(); - $("save").disabled = !isFormValid(); + document.getElementById("save").disabled = !isFormValid(); }; const enableInputBoxes = () => { - $("ratio").disabled = $("setRatio").disabled || !$("setRatio").checked; - $("totalMinutes").disabled = $("setTotalMinutes").disabled || !$("setTotalMinutes").checked; - $("inactiveMinutes").disabled = $("setInactiveMinutes").disabled || !$("setInactiveMinutes").checked; + document.getElementById("ratio").disabled = document.getElementById("setRatio").disabled || !document.getElementById("setRatio").checked; + document.getElementById("totalMinutes").disabled = document.getElementById("setTotalMinutes").disabled || !document.getElementById("setTotalMinutes").checked; + document.getElementById("inactiveMinutes").disabled = document.getElementById("setInactiveMinutes").disabled || !document.getElementById("setInactiveMinutes").checked; - $("save").disabled = !isFormValid(); + document.getElementById("save").disabled = !isFormValid(); }; const isFormValid = () => { - return !((getSelectedRadioValue("shareLimit") === "custom") && !$("setRatio").checked - && !$("setTotalMinutes").checked && !$("setInactiveMinutes").checked); + return !((getSelectedRadioValue("shareLimit") === "custom") && !document.getElementById("setRatio").checked + && !document.getElementById("setTotalMinutes").checked && !document.getElementById("setInactiveMinutes").checked); }; diff --git a/src/webui/www/private/upload.html b/src/webui/www/private/upload.html index d7a065a26..74c4c65e0 100644 --- a/src/webui/www/private/upload.html +++ b/src/webui/www/private/upload.html @@ -160,23 +160,23 @@ let submitted = false; - $("uploadForm").addEventListener("submit", () => { - $("startTorrentHidden").value = $("startTorrent").checked ? "false" : "true"; + document.getElementById("uploadForm").addEventListener("submit", () => { + document.getElementById("startTorrentHidden").value = document.getElementById("startTorrent").checked ? "false" : "true"; - $("dlLimitHidden").value = Number($("dlLimitText").value) * 1024; - $("upLimitHidden").value = Number($("upLimitText").value) * 1024; + document.getElementById("dlLimitHidden").value = Number(document.getElementById("dlLimitText").value) * 1024; + document.getElementById("upLimitHidden").value = Number(document.getElementById("upLimitText").value) * 1024; - $("upload_spinner").style.display = "block"; + document.getElementById("upload_spinner").style.display = "block"; submitted = true; }); - $("upload_frame").addEventListener("load", () => { + document.getElementById("upload_frame").addEventListener("load", () => { if (submitted) window.parent.qBittorrent.Client.closeFrameWindow(window); }); if ((Browser.platform === "ios") || ((Browser.platform === "mac") && (navigator.maxTouchPoints > 1))) - $("fileselect").accept = ".torrent"; + document.getElementById("fileselect").accept = ".torrent"; window.qBittorrent.pathAutofill.attachPathAutofill(); diff --git a/src/webui/www/private/uploadlimit.html b/src/webui/www/private/uploadlimit.html index ed672cd47..fb60da531 100644 --- a/src/webui/www/private/uploadlimit.html +++ b/src/webui/www/private/uploadlimit.html @@ -37,7 +37,7 @@ switch (event.key) { case "Enter": event.preventDefault(); - $("applyButton").click(); + document.getElementById("applyButton").click(); break; case "Escape": event.preventDefault(); @@ -48,7 +48,7 @@ const hashes = new URLSearchParams(window.location.search).get("hashes").split("|"); const setUpLimit = () => { - const limit = Number($("uplimitUpdatevalue").value) * 1024; + const limit = Number(document.getElementById("uplimitUpdatevalue").value) * 1024; if (hashes[0] === "global") { fetch("api/v2/transfer/setUploadLimit", { method: "POST", @@ -81,7 +81,7 @@ } }; - $("uplimitUpdatevalue").focus(); + document.getElementById("uplimitUpdatevalue").focus(); MochaUI.addUpLimitSlider(hashes); diff --git a/src/webui/www/private/views/about.html b/src/webui/www/private/views/about.html index cf265f585..c5a67ed83 100644 --- a/src/webui/www/private/views/about.html +++ b/src/webui/www/private/views/about.html @@ -855,12 +855,12 @@ const qbtVersion = window.parent.qBittorrent.Cache.qbtVersion.get(); const buildInfo = window.parent.qBittorrent.Cache.buildInfo.get(); - $("qbittorrentVersion").textContent = `qBittorrent ${qbtVersion} QBT_TR(WebUI)QBT_TR[CONTEXT=OptionsDialog]`; - $("qtVersion").textContent = buildInfo.qt; - $("libtorrentVersion").textContent = buildInfo.libtorrent; - $("boostVersion").textContent = buildInfo.boost; - $("opensslVersion").textContent = buildInfo.openssl; - $("zlibVersion").textContent = buildInfo.zlib; - $("qbittorrentVersion").textContent += ` (${buildInfo.bitness}-bit)`; + document.getElementById("qbittorrentVersion").textContent = `qBittorrent ${qbtVersion} QBT_TR(WebUI)QBT_TR[CONTEXT=OptionsDialog]`; + document.getElementById("qtVersion").textContent = buildInfo.qt; + document.getElementById("libtorrentVersion").textContent = buildInfo.libtorrent; + document.getElementById("boostVersion").textContent = buildInfo.boost; + document.getElementById("opensslVersion").textContent = buildInfo.openssl; + document.getElementById("zlibVersion").textContent = buildInfo.zlib; + document.getElementById("qbittorrentVersion").textContent += ` (${buildInfo.bitness}-bit)`; })(); diff --git a/src/webui/www/private/views/aboutToolbar.html b/src/webui/www/private/views/aboutToolbar.html index 3557a11e5..5e358890b 100644 --- a/src/webui/www/private/views/aboutToolbar.html +++ b/src/webui/www/private/views/aboutToolbar.html @@ -16,34 +16,34 @@ (() => { MochaUI.initializeTabs("aboutTabs"); - $("aboutAboutLink").addEventListener("click", () => { + document.getElementById("aboutAboutLink").addEventListener("click", () => { Array.prototype.forEach.call(document.querySelectorAll(".aboutTabContent"), (tab => tab.classList.add("invisible"))); - $("aboutAboutContent").classList.remove("invisible"); + document.getElementById("aboutAboutContent").classList.remove("invisible"); }); - $("aboutAuthorLink").addEventListener("click", () => { + document.getElementById("aboutAuthorLink").addEventListener("click", () => { Array.prototype.forEach.call(document.querySelectorAll(".aboutTabContent"), (tab => tab.classList.add("invisible"))); - $("aboutAuthorContent").classList.remove("invisible"); + document.getElementById("aboutAuthorContent").classList.remove("invisible"); }); - $("aboutSpecialThanksLink").addEventListener("click", () => { + document.getElementById("aboutSpecialThanksLink").addEventListener("click", () => { Array.prototype.forEach.call(document.querySelectorAll(".aboutTabContent"), (tab => tab.classList.add("invisible"))); - $("aboutSpecialThanksContent").classList.remove("invisible"); + document.getElementById("aboutSpecialThanksContent").classList.remove("invisible"); }); - $("aboutTranslatorsLink").addEventListener("click", () => { + document.getElementById("aboutTranslatorsLink").addEventListener("click", () => { Array.prototype.forEach.call(document.querySelectorAll(".aboutTabContent"), (tab => tab.classList.add("invisible"))); - $("aboutTranslatorsContent").classList.remove("invisible"); + document.getElementById("aboutTranslatorsContent").classList.remove("invisible"); }); - $("aboutLicenseLink").addEventListener("click", () => { + document.getElementById("aboutLicenseLink").addEventListener("click", () => { Array.prototype.forEach.call(document.querySelectorAll(".aboutTabContent"), (tab => tab.classList.add("invisible"))); - $("aboutLicenseContent").classList.remove("invisible"); + document.getElementById("aboutLicenseContent").classList.remove("invisible"); }); - $("aboutSoftwareUsedLink").addEventListener("click", () => { + document.getElementById("aboutSoftwareUsedLink").addEventListener("click", () => { Array.prototype.forEach.call(document.querySelectorAll(".aboutTabContent"), (tab => tab.classList.add("invisible"))); - $("aboutSoftwareUsedContent").classList.remove("invisible"); + document.getElementById("aboutSoftwareUsedContent").classList.remove("invisible"); }); })(); diff --git a/src/webui/www/private/views/installsearchplugin.html b/src/webui/www/private/views/installsearchplugin.html index de77a46e1..74e1b7aaa 100644 --- a/src/webui/www/private/views/installsearchplugin.html +++ b/src/webui/www/private/views/installsearchplugin.html @@ -61,11 +61,11 @@ } }); - $("newPluginPath").select(); + document.getElementById("newPluginPath").select(); }; const newPluginOk = () => { - const path = $("newPluginPath").value.trim(); + const path = document.getElementById("newPluginPath").value.trim(); if (path) { fetch("api/v2/search/installPlugin", { method: "POST", diff --git a/src/webui/www/private/views/log.html b/src/webui/www/private/views/log.html index bbafca8cc..b7944b784 100644 --- a/src/webui/www/private/views/log.html +++ b/src/webui/www/private/views/log.html @@ -188,7 +188,7 @@ let selectedLogLevels = JSON.parse(LocalPreferences.get("qbt_selected_log_levels")) || ["1", "2", "4", "8"]; const init = () => { - for (const option of $("logLevelSelect").options) + for (const option of document.getElementById("logLevelSelect").options) option.toggleAttribute("selected", selectedLogLevels.includes(option.value)); selectBox = new vanillaSelectBox("#logLevelSelect", { @@ -282,7 +282,7 @@ }; const filterTextChanged = () => { - const value = $("filterTextInput").value.trim(); + const value = document.getElementById("filterTextInput").value.trim(); if (inputtedFilterText !== value) { inputtedFilterText = value; logFilterChanged(); @@ -306,14 +306,14 @@ currentSelectedTab = tab; if (currentSelectedTab === "main") { selectBox.enable(); - $("logMessageView").classList.remove("invisible"); - $("logPeerView").classList.add("invisible"); + document.getElementById("logMessageView").classList.remove("invisible"); + document.getElementById("logPeerView").classList.add("invisible"); resetTableTimer("peer"); } else { selectBox.disable(); - $("logMessageView").classList.add("invisible"); - $("logPeerView").classList.remove("invisible"); + document.getElementById("logMessageView").classList.add("invisible"); + document.getElementById("logPeerView").classList.remove("invisible"); resetTableTimer("main"); } @@ -331,8 +331,8 @@ if (curTab === undefined) curTab = currentSelectedTab; - $("numFilteredLogs").textContent = tableInfo[curTab].instance.filteredLength; - $("numTotalLogs").textContent = tableInfo[curTab].instance.getRowSize(); + document.getElementById("numFilteredLogs").textContent = tableInfo[curTab].instance.filteredLength; + document.getElementById("numTotalLogs").textContent = tableInfo[curTab].instance.getRowSize(); }; const syncLogData = (curTab) => { @@ -368,7 +368,7 @@ }) .then(async (response) => { if (!response.ok) { - const errorDiv = $("error_div"); + const errorDiv = document.getElementById("error_div"); if (errorDiv) errorDiv.textContent = "QBT_TR(qBittorrent client is not reachable)QBT_TR[CONTEXT=HttpServer]"; tableInfo[curTab].progress = false; @@ -376,9 +376,9 @@ return; } - $("error_div").textContent = ""; + document.getElementById("error_div").textContent = ""; - if ($("logTabColumn").classList.contains("invisible")) + if (document.getElementById("logTabColumn").classList.contains("invisible")) return; const responseJSON = await response.json(); diff --git a/src/webui/www/private/views/preferences.html b/src/webui/www/private/views/preferences.html index 883efdbaa..60903e70c 100644 --- a/src/webui/www/private/views/preferences.html +++ b/src/webui/www/private/views/preferences.html @@ -1801,32 +1801,32 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD }; const updateFileLogEnabled = () => { - const isFileLogEnabled = $("filelog_checkbox").checked; - $("filelog_save_path_input").disabled = !isFileLogEnabled; - $("filelog_backup_checkbox").disabled = !isFileLogEnabled; - $("filelog_delete_old_checkbox").disabled = !isFileLogEnabled; + const isFileLogEnabled = document.getElementById("filelog_checkbox").checked; + document.getElementById("filelog_save_path_input").disabled = !isFileLogEnabled; + document.getElementById("filelog_backup_checkbox").disabled = !isFileLogEnabled; + document.getElementById("filelog_delete_old_checkbox").disabled = !isFileLogEnabled; updateFileLogBackupEnabled(); updateFileLogDeleteEnabled(); }; const updateFileLogBackupEnabled = () => { - const pros = $("filelog_backup_checkbox").getProperties("disabled", "checked"); - $("filelog_max_size_input").disabled = pros.disabled || !pros.checked; + const pros = document.getElementById("filelog_backup_checkbox").getProperties("disabled", "checked"); + document.getElementById("filelog_max_size_input").disabled = pros.disabled || !pros.checked; }; const updateFileLogDeleteEnabled = () => { - const pros = $("filelog_delete_old_checkbox").getProperties("disabled", "checked"); - $("filelog_age_input").disabled = pros.disabled || !pros.checked; - $("filelog_age_type_select").disabled = pros.disabled || !pros.checked; + const pros = document.getElementById("filelog_delete_old_checkbox").getProperties("disabled", "checked"); + document.getElementById("filelog_age_input").disabled = pros.disabled || !pros.checked; + document.getElementById("filelog_age_type_select").disabled = pros.disabled || !pros.checked; }; // Downloads tab let watchedFoldersTable; const updateTempDirEnabled = () => { - const isTempDirEnabled = $("temppath_checkbox").checked; - $("temppath_text").disabled = !isTempDirEnabled; + const isTempDirEnabled = document.getElementById("temppath_checkbox").checked; + document.getElementById("temppath_text").disabled = !isTempDirEnabled; }; const changeWatchFolderSelect = (item) => { @@ -1843,7 +1843,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD }; const addWatchFolder = (folder = "", sel = "default_folder", other = "") => { - const pos = $("watched_folders_tab").getChildren("tbody")[0].getChildren("tr").length; + const pos = document.getElementById("watched_folders_tab").getChildren("tbody")[0].getChildren("tr").length; const myinput = ``; const disableInput = (sel !== "other"); const mycb = `
` @@ -1857,28 +1857,28 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD + `
`; watchedFoldersTable.push([myinput, mycb]); - $(`cb_watch_${pos}`).value = sel; + document.getElementById(`cb_watch_${pos}`).value = sel; if (disableInput) { - const elt = $(`cb_watch_${pos}`); + const elt = document.getElementById(`cb_watch_${pos}`); other = elt.options[elt.selectedIndex].textContent; } - $(`cb_watch_txt_${pos}`).value = other; + document.getElementById(`cb_watch_txt_${pos}`).value = other; // hide previous img if (pos > 0) - $(`addFolderImg_${pos - 1}`).style.display = "none"; + document.getElementById(`addFolderImg_${pos - 1}`).style.display = "none"; }; const getWatchedFolders = () => { const folders = {}; - const entryCount = $("watched_folders_tab").getChildren("tbody")[0].getChildren("tr").length; + const entryCount = document.getElementById("watched_folders_tab").getChildren("tbody")[0].getChildren("tr").length; for (let i = 0; i < entryCount; ++i) { - const fpath = $(`text_watch_${i}`).value.trim(); + const fpath = document.getElementById(`text_watch_${i}`).value.trim(); if (fpath.length <= 0) continue; - const sel = $(`cb_watch_${i}`).value.trim(); + const sel = document.getElementById(`cb_watch_${i}`).value.trim(); let other; switch (sel) { @@ -1889,7 +1889,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD other = 1; break; case "other": - other = $(`cb_watch_txt_${i}`).value.trim(); + other = document.getElementById(`cb_watch_txt_${i}`).value.trim(); break; }; @@ -1900,39 +1900,39 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD }; const updateExcludedFileNamesEnabled = () => { - const isAExcludedFileNamesEnabled = $("excludedFileNamesCheckbox").checked; - $("excludedFileNamesTextarea").disabled = !isAExcludedFileNamesEnabled; + const isAExcludedFileNamesEnabled = document.getElementById("excludedFileNamesCheckbox").checked; + document.getElementById("excludedFileNamesTextarea").disabled = !isAExcludedFileNamesEnabled; }; const updateExportDirEnabled = () => { - const isExportDirEnabled = $("exportdir_checkbox").checked; - $("exportdir_text").disabled = !isExportDirEnabled; + const isExportDirEnabled = document.getElementById("exportdir_checkbox").checked; + document.getElementById("exportdir_text").disabled = !isExportDirEnabled; }; const updateExportDirFinEnabled = () => { - const isExportDirFinEnabled = $("exportdirfin_checkbox").checked; - $("exportdirfin_text").disabled = !isExportDirFinEnabled; + const isExportDirFinEnabled = document.getElementById("exportdirfin_checkbox").checked; + document.getElementById("exportdirfin_text").disabled = !isExportDirFinEnabled; }; const updateMailNotification = () => { - const isMailNotificationEnabled = $("mail_notification_checkbox").checked; - $("src_email_txt").disabled = !isMailNotificationEnabled; - $("dest_email_txt").disabled = !isMailNotificationEnabled; - $("smtp_server_txt").disabled = !isMailNotificationEnabled; - $("mail_ssl_checkbox").disabled = !isMailNotificationEnabled; - $("mail_auth_checkbox").disabled = !isMailNotificationEnabled; - $("mail_test_button").disabled = !isMailNotificationEnabled; + const isMailNotificationEnabled = document.getElementById("mail_notification_checkbox").checked; + document.getElementById("src_email_txt").disabled = !isMailNotificationEnabled; + document.getElementById("dest_email_txt").disabled = !isMailNotificationEnabled; + document.getElementById("smtp_server_txt").disabled = !isMailNotificationEnabled; + document.getElementById("mail_ssl_checkbox").disabled = !isMailNotificationEnabled; + document.getElementById("mail_auth_checkbox").disabled = !isMailNotificationEnabled; + document.getElementById("mail_test_button").disabled = !isMailNotificationEnabled; if (!isMailNotificationEnabled) { - $("mail_auth_checkbox").checked = !isMailNotificationEnabled; + document.getElementById("mail_auth_checkbox").checked = !isMailNotificationEnabled; updateMailAuthSettings(); } }; const updateMailAuthSettings = () => { - const isMailAuthEnabled = $("mail_auth_checkbox").checked; - $("mail_username_text").disabled = !isMailAuthEnabled; - $("mail_password_text").disabled = !isMailAuthEnabled; + const isMailAuthEnabled = document.getElementById("mail_auth_checkbox").checked; + document.getElementById("mail_username_text").disabled = !isMailAuthEnabled; + document.getElementById("mail_password_text").disabled = !isMailAuthEnabled; }; const sendTestEmail = () => { @@ -1950,167 +1950,167 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD }; const updateAutoRunOnTorrentAdded = () => { - const isAutoRunOnTorrentAddedEnabled = $("autorunOnTorrentAddedCheckbox").checked; - $("autorunOnTorrentAddedProgram").disabled = !isAutoRunOnTorrentAddedEnabled; + const isAutoRunOnTorrentAddedEnabled = document.getElementById("autorunOnTorrentAddedCheckbox").checked; + document.getElementById("autorunOnTorrentAddedProgram").disabled = !isAutoRunOnTorrentAddedEnabled; }; const updateAutoRun = () => { - const isAutoRunEnabled = $("autorun_checkbox").checked; - $("autorunProg_txt").disabled = !isAutoRunEnabled; + const isAutoRunEnabled = document.getElementById("autorun_checkbox").checked; + document.getElementById("autorunProg_txt").disabled = !isAutoRunEnabled; }; // Connection tab const updateMaxConnecEnabled = () => { - const isMaxConnecEnabled = $("maxConnectionsCheckbox").checked; - $("maxConnectionsValue").disabled = !isMaxConnecEnabled; + const isMaxConnecEnabled = document.getElementById("maxConnectionsCheckbox").checked; + document.getElementById("maxConnectionsValue").disabled = !isMaxConnecEnabled; }; const updateMaxConnecPerTorrentEnabled = () => { - const isMaxConnecPerTorrentEnabled = $("maxConnectionsPerTorrentCheckbox").checked; - $("maxConnectionsPerTorrentValue").disabled = !isMaxConnecPerTorrentEnabled; + const isMaxConnecPerTorrentEnabled = document.getElementById("maxConnectionsPerTorrentCheckbox").checked; + document.getElementById("maxConnectionsPerTorrentValue").disabled = !isMaxConnecPerTorrentEnabled; }; const updateMaxUploadsEnabled = () => { - const isMaxUploadsEnabled = $("maxUploadsCheckbox").checked; - $("max_uploads_value").disabled = !isMaxUploadsEnabled; + const isMaxUploadsEnabled = document.getElementById("maxUploadsCheckbox").checked; + document.getElementById("max_uploads_value").disabled = !isMaxUploadsEnabled; }; const updateMaxUploadsPerTorrentEnabled = () => { - const isMaxUploadsPerTorrentEnabled = $("maxUploadsPerTorrentCheckbox").checked; - $("maxUploadsPerTorrentValue").disabled = !isMaxUploadsPerTorrentEnabled; + const isMaxUploadsPerTorrentEnabled = document.getElementById("maxUploadsPerTorrentCheckbox").checked; + document.getElementById("maxUploadsPerTorrentValue").disabled = !isMaxUploadsPerTorrentEnabled; }; const updateI2PSettingsEnabled = () => { - const isI2PEnabled = $("i2pEnabledCheckbox").checked; - $("i2pAddress").disabled = !isI2PEnabled; - $("i2pPort").disabled = !isI2PEnabled; - $("i2pMixedMode").disabled = !isI2PEnabled; + const isI2PEnabled = document.getElementById("i2pEnabledCheckbox").checked; + document.getElementById("i2pAddress").disabled = !isI2PEnabled; + document.getElementById("i2pPort").disabled = !isI2PEnabled; + document.getElementById("i2pMixedMode").disabled = !isI2PEnabled; }; const updatePeerProxySettings = () => { - const proxyType = $("peer_proxy_type_select").value; + const proxyType = document.getElementById("peer_proxy_type_select").value; const isProxyDisabled = (proxyType === "None"); const isProxySocks4 = (proxyType === "SOCKS4"); - $("peer_proxy_host_text").disabled = isProxyDisabled; - $("peer_proxy_port_value").disabled = isProxyDisabled; + document.getElementById("peer_proxy_host_text").disabled = isProxyDisabled; + document.getElementById("peer_proxy_port_value").disabled = isProxyDisabled; - $("peer_proxy_auth_checkbox").disabled = (isProxyDisabled || isProxySocks4); - $("proxy_bittorrent_checkbox").disabled = isProxyDisabled; - $("use_peer_proxy_checkbox").disabled = (isProxyDisabled || !$("proxy_bittorrent_checkbox").checked); - $("proxyHostnameLookupCheckbox").disabled = (isProxyDisabled || isProxySocks4); - $("proxy_rss_checkbox").disabled = (isProxyDisabled || isProxySocks4); - $("proxy_misc_checkbox").disabled = (isProxyDisabled || isProxySocks4); + document.getElementById("peer_proxy_auth_checkbox").disabled = (isProxyDisabled || isProxySocks4); + document.getElementById("proxy_bittorrent_checkbox").disabled = isProxyDisabled; + document.getElementById("use_peer_proxy_checkbox").disabled = (isProxyDisabled || !document.getElementById("proxy_bittorrent_checkbox").checked); + document.getElementById("proxyHostnameLookupCheckbox").disabled = (isProxyDisabled || isProxySocks4); + document.getElementById("proxy_rss_checkbox").disabled = (isProxyDisabled || isProxySocks4); + document.getElementById("proxy_misc_checkbox").disabled = (isProxyDisabled || isProxySocks4); updatePeerProxyAuthSettings(); }; const updatePeerProxyAuthSettings = () => { - const proxyType = $("peer_proxy_type_select").value; + const proxyType = document.getElementById("peer_proxy_type_select").value; const isProxyDisabled = (proxyType === "None"); - const isPeerProxyAuthEnabled = (!$("peer_proxy_auth_checkbox").disabled && $("peer_proxy_auth_checkbox").checked); - $("peer_proxy_username_text").disabled = (isProxyDisabled || !isPeerProxyAuthEnabled); - $("peer_proxy_password_text").disabled = (isProxyDisabled || !isPeerProxyAuthEnabled); + const isPeerProxyAuthEnabled = (!document.getElementById("peer_proxy_auth_checkbox").disabled && document.getElementById("peer_proxy_auth_checkbox").checked); + document.getElementById("peer_proxy_username_text").disabled = (isProxyDisabled || !isPeerProxyAuthEnabled); + document.getElementById("peer_proxy_password_text").disabled = (isProxyDisabled || !isPeerProxyAuthEnabled); }; const updateFilterSettings = () => { - const isIPFilterEnabled = $("ipfilter_text_checkbox").checked; - $("ipfilter_text").disabled = !isIPFilterEnabled; + const isIPFilterEnabled = document.getElementById("ipfilter_text_checkbox").checked; + document.getElementById("ipfilter_text").disabled = !isIPFilterEnabled; }; // Speed tab const updateSchedulingEnabled = () => { - const isLimitSchedulingEnabled = $("limitSchedulingCheckbox").checked; - $("schedule_from_hour").disabled = !isLimitSchedulingEnabled; - $("schedule_from_min").disabled = !isLimitSchedulingEnabled; - $("schedule_to_hour").disabled = !isLimitSchedulingEnabled; - $("schedule_to_min").disabled = !isLimitSchedulingEnabled; - $("schedule_freq_select").disabled = !isLimitSchedulingEnabled; + const isLimitSchedulingEnabled = document.getElementById("limitSchedulingCheckbox").checked; + document.getElementById("schedule_from_hour").disabled = !isLimitSchedulingEnabled; + document.getElementById("schedule_from_min").disabled = !isLimitSchedulingEnabled; + document.getElementById("schedule_to_hour").disabled = !isLimitSchedulingEnabled; + document.getElementById("schedule_to_min").disabled = !isLimitSchedulingEnabled; + document.getElementById("schedule_freq_select").disabled = !isLimitSchedulingEnabled; }; // Bittorrent tab const updateQueueingSystem = () => { - const isQueueingEnabled = $("queueingCheckbox").checked; - $("maxActiveDlValue").disabled = !isQueueingEnabled; - $("maxActiveUpValue").disabled = !isQueueingEnabled; - $("maxActiveToValue").disabled = !isQueueingEnabled; - $("dontCountSlowTorrentsCheckbox").disabled = !isQueueingEnabled; + const isQueueingEnabled = document.getElementById("queueingCheckbox").checked; + document.getElementById("maxActiveDlValue").disabled = !isQueueingEnabled; + document.getElementById("maxActiveUpValue").disabled = !isQueueingEnabled; + document.getElementById("maxActiveToValue").disabled = !isQueueingEnabled; + document.getElementById("dontCountSlowTorrentsCheckbox").disabled = !isQueueingEnabled; updateSlowTorrentsSettings(); }; const updateSlowTorrentsSettings = () => { - const isDontCountSlowTorrentsEnabled = (!$("dontCountSlowTorrentsCheckbox").disabled) && $("dontCountSlowTorrentsCheckbox").checked; - $("dlRateThresholdValue").disabled = !isDontCountSlowTorrentsEnabled; - $("ulRateThresholdValue").disabled = !isDontCountSlowTorrentsEnabled; - $("torrentInactiveTimerValue").disabled = !isDontCountSlowTorrentsEnabled; + const isDontCountSlowTorrentsEnabled = (!document.getElementById("dontCountSlowTorrentsCheckbox").disabled) && document.getElementById("dontCountSlowTorrentsCheckbox").checked; + document.getElementById("dlRateThresholdValue").disabled = !isDontCountSlowTorrentsEnabled; + document.getElementById("ulRateThresholdValue").disabled = !isDontCountSlowTorrentsEnabled; + document.getElementById("torrentInactiveTimerValue").disabled = !isDontCountSlowTorrentsEnabled; }; const updateMaxRatioTimeEnabled = () => { - const isMaxRatioEnabled = $("maxRatioCheckbox").checked; - $("maxRatioValue").disabled = !isMaxRatioEnabled; + const isMaxRatioEnabled = document.getElementById("maxRatioCheckbox").checked; + document.getElementById("maxRatioValue").disabled = !isMaxRatioEnabled; - const isMaxSeedingTimeEnabled = $("maxSeedingTimeCheckbox").checked; - $("maxSeedingTimeValue").disabled = !isMaxSeedingTimeEnabled; + const isMaxSeedingTimeEnabled = document.getElementById("maxSeedingTimeCheckbox").checked; + document.getElementById("maxSeedingTimeValue").disabled = !isMaxSeedingTimeEnabled; - const isMaxInactiveSeedingTimeEnabled = $("maxInactiveSeedingTimeCheckbox").checked; - $("maxInactiveSeedingTimeValue").disabled = !isMaxInactiveSeedingTimeEnabled; + const isMaxInactiveSeedingTimeEnabled = document.getElementById("maxInactiveSeedingTimeCheckbox").checked; + document.getElementById("maxInactiveSeedingTimeValue").disabled = !isMaxInactiveSeedingTimeEnabled; - $("maxRatioSelect").disabled = !(isMaxRatioEnabled || isMaxSeedingTimeEnabled || isMaxInactiveSeedingTimeEnabled); + document.getElementById("maxRatioSelect").disabled = !(isMaxRatioEnabled || isMaxSeedingTimeEnabled || isMaxInactiveSeedingTimeEnabled); }; const updateAddTrackersEnabled = () => { - const isAddTrackersEnabled = $("add_trackers_checkbox").checked; - $("add_trackers_textarea").disabled = !isAddTrackersEnabled; + const isAddTrackersEnabled = document.getElementById("add_trackers_checkbox").checked; + document.getElementById("add_trackers_textarea").disabled = !isAddTrackersEnabled; }; const updateAddTrackersFromURLEnabled = () => { - const isAddTrackersFromURLEnabled = $("addTrackersFromURLCheckbox").checked; - $("addTrackersURL").disabled = !isAddTrackersFromURLEnabled; + const isAddTrackersFromURLEnabled = document.getElementById("addTrackersFromURLCheckbox").checked; + document.getElementById("addTrackersURL").disabled = !isAddTrackersFromURLEnabled; }; // WebUI tab const updateHttpsSettings = () => { - const isUseHttpsEnabled = $("use_https_checkbox").checked; - $("ssl_cert_text").disabled = !isUseHttpsEnabled; - $("ssl_key_text").disabled = !isUseHttpsEnabled; + const isUseHttpsEnabled = document.getElementById("use_https_checkbox").checked; + document.getElementById("ssl_cert_text").disabled = !isUseHttpsEnabled; + document.getElementById("ssl_key_text").disabled = !isUseHttpsEnabled; }; const updateBypasssAuthSettings = () => { - const isBypassAuthSubnetWhitelistEnabled = $("bypass_auth_subnet_whitelist_checkbox").checked; - $("bypass_auth_subnet_whitelist_textarea").disabled = !isBypassAuthSubnetWhitelistEnabled; + const isBypassAuthSubnetWhitelistEnabled = document.getElementById("bypass_auth_subnet_whitelist_checkbox").checked; + document.getElementById("bypass_auth_subnet_whitelist_textarea").disabled = !isBypassAuthSubnetWhitelistEnabled; }; const updateAlternativeWebUISettings = () => { - const isUseAlternativeWebUIEnabled = $("use_alt_webui_checkbox").checked; - $("webui_files_location_textarea").disabled = !isUseAlternativeWebUIEnabled; + const isUseAlternativeWebUIEnabled = document.getElementById("use_alt_webui_checkbox").checked; + document.getElementById("webui_files_location_textarea").disabled = !isUseAlternativeWebUIEnabled; }; const updateHostHeaderValidationSettings = () => { - const isHostHeaderValidationEnabled = $("host_header_validation_checkbox").checked; - $("webuiDomainTextarea").disabled = !isHostHeaderValidationEnabled; + const isHostHeaderValidationEnabled = document.getElementById("host_header_validation_checkbox").checked; + document.getElementById("webuiDomainTextarea").disabled = !isHostHeaderValidationEnabled; }; const updateWebUICustomHTTPHeadersSettings = () => { - const isEnabled = $("webUIUseCustomHTTPHeadersCheckbox").checked; - $("webUICustomHTTPHeadersTextarea").disabled = !isEnabled; + const isEnabled = document.getElementById("webUIUseCustomHTTPHeadersCheckbox").checked; + document.getElementById("webUICustomHTTPHeadersTextarea").disabled = !isEnabled; }; const updateWebUIReverseProxySettings = () => { - const isEnabled = $("webUIReverseProxySupportCheckbox").checked; - $("webUIReverseProxiesListTextarea").disabled = !isEnabled; + const isEnabled = document.getElementById("webUIReverseProxySupportCheckbox").checked; + document.getElementById("webUIReverseProxiesListTextarea").disabled = !isEnabled; }; const updateDynDnsSettings = () => { - const isDynDnsEnabled = $("use_dyndns_checkbox").checked; - $("dyndns_select").disabled = !isDynDnsEnabled; - $("dyndns_domain_text").disabled = !isDynDnsEnabled; - $("dyndns_username_text").disabled = !isDynDnsEnabled; - $("dyndns_password_text").disabled = !isDynDnsEnabled; + const isDynDnsEnabled = document.getElementById("use_dyndns_checkbox").checked; + document.getElementById("dyndns_select").disabled = !isDynDnsEnabled; + document.getElementById("dyndns_domain_text").disabled = !isDynDnsEnabled; + document.getElementById("dyndns_username_text").disabled = !isDynDnsEnabled; + document.getElementById("dyndns_password_text").disabled = !isDynDnsEnabled; }; const registerDynDns = () => { - if (Number($("dyndns_select").value) === 1) + if (Number(document.getElementById("dyndns_select").value) === 1) window.open("http://www.no-ip.com/services/managed_dns/free_dynamic_dns.html", "NO-IP Registration"); else window.open("https://www.dyndns.com/account/services/hosts/add.html", "DynDNS Registration"); @@ -2120,7 +2120,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD const min = 1024; const max = 65535; const port = Math.floor(Math.random() * (max - min + 1) + min); - $("portValue").value = port; + document.getElementById("portValue").value = port; }; const time_padding = (val) => { @@ -2152,11 +2152,11 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD if (default_iface && !ifaces.some((item) => item.value === default_iface)) ifaces.push({ name: default_iface_name || default_iface, value: default_iface }); - $("networkInterface").options.add(new Option("QBT_TR(Any interface)QBT_TR[CONTEXT=OptionsDialog]", "")); + document.getElementById("networkInterface").options.add(new Option("QBT_TR(Any interface)QBT_TR[CONTEXT=OptionsDialog]", "")); ifaces.forEach((item, index) => { - $("networkInterface").options.add(new Option(item.name, item.value)); + document.getElementById("networkInterface").options.add(new Option(item.name, item.value)); }); - $("networkInterface").value = default_iface; + document.getElementById("networkInterface").value = default_iface; }); }; @@ -2181,26 +2181,26 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD if (!addresses) return; - $("optionalIPAddressToBind").options.add(new Option("QBT_TR(All addresses)QBT_TR[CONTEXT=OptionDialog]", "")); - $("optionalIPAddressToBind").options.add(new Option("QBT_TR(All IPv4 addresses)QBT_TR[CONTEXT=OptionDialog]", "0.0.0.0")); - $("optionalIPAddressToBind").options.add(new Option("QBT_TR(All IPv6 addresses)QBT_TR[CONTEXT=OptionDialog]", "::")); + document.getElementById("optionalIPAddressToBind").options.add(new Option("QBT_TR(All addresses)QBT_TR[CONTEXT=OptionDialog]", "")); + document.getElementById("optionalIPAddressToBind").options.add(new Option("QBT_TR(All IPv4 addresses)QBT_TR[CONTEXT=OptionDialog]", "0.0.0.0")); + document.getElementById("optionalIPAddressToBind").options.add(new Option("QBT_TR(All IPv6 addresses)QBT_TR[CONTEXT=OptionDialog]", "::")); addresses.forEach((item, index) => { - $("optionalIPAddressToBind").options.add(new Option(item, item)); + document.getElementById("optionalIPAddressToBind").options.add(new Option(item, item)); }); - $("optionalIPAddressToBind").value = default_addr; + document.getElementById("optionalIPAddressToBind").value = default_addr; }); }; const updateWebuiLocaleSelect = (selected) => { const languages = []; - for (let i = 0; i < $("locale_select").options.length; i++) - languages.push($("locale_select").options[i].value); + for (let i = 0; i < document.getElementById("locale_select").options.length; i++) + languages.push(document.getElementById("locale_select").options[i].value); if (!languages.includes(selected)) { const lang = selected.split("_", 1)[0]; selected = languages.includes(lang) ? lang : "en"; } - $("locale_select").value = selected; + document.getElementById("locale_select").value = selected; }; const updateColoSchemeSelect = () => { @@ -2222,22 +2222,22 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD // Language updateWebuiLocaleSelect(pref.locale); updateColoSchemeSelect(); - $("statusBarExternalIP").checked = pref.status_bar_external_ip; - $("performanceWarning").checked = pref.performance_warning; + document.getElementById("statusBarExternalIP").checked = pref.status_bar_external_ip; + document.getElementById("performanceWarning").checked = pref.performance_warning; document.getElementById("displayFullURLTrackerColumn").checked = (LocalPreferences.get("full_url_tracker_column", "false") === "true"); document.getElementById("useVirtualList").checked = (LocalPreferences.get("use_virtual_list", "false") === "true"); document.getElementById("hideZeroFiltersCheckbox").checked = (LocalPreferences.get("hide_zero_status_filters", "false") === "true"); - $("dblclickDownloadSelect").value = LocalPreferences.get("dblclick_download", "1"); - $("dblclickCompleteSelect").value = LocalPreferences.get("dblclick_complete", "1"); + document.getElementById("dblclickDownloadSelect").value = LocalPreferences.get("dblclick_download", "1"); + document.getElementById("dblclickCompleteSelect").value = LocalPreferences.get("dblclick_complete", "1"); document.getElementById("confirmTorrentDeletion").checked = pref.confirm_torrent_deletion; document.getElementById("useAltRowColorsInput").checked = (LocalPreferences.get("use_alt_row_colors", "true") === "true"); - $("filelog_checkbox").checked = pref.file_log_enabled; - $("filelog_save_path_input").value = pref.file_log_path; - $("filelog_backup_checkbox").checked = pref.file_log_backup_enabled; - $("filelog_max_size_input").value = pref.file_log_max_size; - $("filelog_delete_old_checkbox").checked = pref.file_log_delete_old; - $("filelog_age_input").value = pref.file_log_age; - $("filelog_age_type_select").value = pref.file_log_age_type; + document.getElementById("filelog_checkbox").checked = pref.file_log_enabled; + document.getElementById("filelog_save_path_input").value = pref.file_log_path; + document.getElementById("filelog_backup_checkbox").checked = pref.file_log_backup_enabled; + document.getElementById("filelog_max_size_input").value = pref.file_log_max_size; + document.getElementById("filelog_delete_old_checkbox").checked = pref.file_log_delete_old; + document.getElementById("filelog_age_input").value = pref.file_log_age; + document.getElementById("filelog_age_type_select").value = pref.file_log_age_type; updateFileLogEnabled(); // Downloads tab @@ -2254,9 +2254,9 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD index = 2; break; } - $("contentlayout_select").getChildren("option")[index].selected = true; - $("addToTopOfQueueCheckbox").checked = pref.add_to_top_of_queue; - $("dontstartdownloads_checkbox").checked = pref.add_stopped_enabled; + document.getElementById("contentlayout_select").getChildren("option")[index].selected = true; + document.getElementById("addToTopOfQueueCheckbox").checked = pref.add_to_top_of_queue; + document.getElementById("dontstartdownloads_checkbox").checked = pref.add_stopped_enabled; switch (pref.torrent_stop_condition) { case "None": index = 0; @@ -2268,41 +2268,41 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD index = 2; break; } - $("stopConditionSelect").getChildren("option")[index].selected = true; + document.getElementById("stopConditionSelect").getChildren("option")[index].selected = true; document.getElementById("mergeTrackersInput").checked = pref.merge_trackers; - $("deletetorrentfileafter_checkbox").checked = pref.auto_delete_mode; + document.getElementById("deletetorrentfileafter_checkbox").checked = pref.auto_delete_mode; - $("preallocateall_checkbox").checked = pref.preallocate_all; - $("appendext_checkbox").checked = pref.incomplete_files_ext; - $("unwantedfolder_checkbox").checked = pref.use_unwanted_folder; + document.getElementById("preallocateall_checkbox").checked = pref.preallocate_all; + document.getElementById("appendext_checkbox").checked = pref.incomplete_files_ext; + document.getElementById("unwantedfolder_checkbox").checked = pref.use_unwanted_folder; // Saving Management - $("default_tmm_combobox").value = pref.auto_tmm_enabled; - $("torrent_changed_tmm_combobox").value = pref.torrent_changed_tmm_enabled; - $("save_path_changed_tmm_combobox").value = pref.save_path_changed_tmm_enabled; - $("category_changed_tmm_combobox").value = pref.category_changed_tmm_enabled; - $("use_subcategories_checkbox").checked = pref.use_subcategories; + document.getElementById("default_tmm_combobox").value = pref.auto_tmm_enabled; + document.getElementById("torrent_changed_tmm_combobox").value = pref.torrent_changed_tmm_enabled; + document.getElementById("save_path_changed_tmm_combobox").value = pref.save_path_changed_tmm_enabled; + document.getElementById("category_changed_tmm_combobox").value = pref.category_changed_tmm_enabled; + document.getElementById("use_subcategories_checkbox").checked = pref.use_subcategories; document.getElementById("categoryPathsManualModeCheckbox").checked = pref.use_category_paths_in_manual_mode; - $("savepath_text").value = pref.save_path; - $("temppath_checkbox").checked = pref.temp_path_enabled; - $("temppath_text").value = pref.temp_path; + document.getElementById("savepath_text").value = pref.save_path; + document.getElementById("temppath_checkbox").checked = pref.temp_path_enabled; + document.getElementById("temppath_text").value = pref.temp_path; updateTempDirEnabled(); if (pref.export_dir !== "") { - $("exportdir_checkbox").checked = true; - $("exportdir_text").value = pref.export_dir; + document.getElementById("exportdir_checkbox").checked = true; + document.getElementById("exportdir_text").value = pref.export_dir; } else { - $("exportdir_checkbox").checked = false; - $("exportdir_text").value = ""; + document.getElementById("exportdir_checkbox").checked = false; + document.getElementById("exportdir_text").value = ""; } updateExportDirEnabled(); if (pref.export_dir_fin !== "") { - $("exportdirfin_checkbox").checked = true; - $("exportdirfin_text").value = pref.export_dir_fin; + document.getElementById("exportdirfin_checkbox").checked = true; + document.getElementById("exportdirfin_text").value = pref.export_dir_fin; } else { - $("exportdirfin_checkbox").checked = false; - $("exportdirfin_text").value = ""; + document.getElementById("exportdirfin_checkbox").checked = false; + document.getElementById("exportdirfin_text").value = ""; } updateExportDirFinEnabled(); @@ -2323,159 +2323,159 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD addWatchFolder(); // Excluded file names - $("excludedFileNamesCheckbox").checked = pref.excluded_file_names_enabled; - $("excludedFileNamesTextarea").value = pref.excluded_file_names; + document.getElementById("excludedFileNamesCheckbox").checked = pref.excluded_file_names_enabled; + document.getElementById("excludedFileNamesTextarea").value = pref.excluded_file_names; // Email notification upon download completion - $("mail_notification_checkbox").checked = pref.mail_notification_enabled; - $("src_email_txt").value = pref.mail_notification_sender; - $("dest_email_txt").value = pref.mail_notification_email; - $("smtp_server_txt").value = pref.mail_notification_smtp; - $("mail_ssl_checkbox").checked = pref.mail_notification_ssl_enabled; - $("mail_auth_checkbox").checked = pref.mail_notification_auth_enabled; - $("mail_username_text").value = pref.mail_notification_username; - $("mail_password_text").value = pref.mail_notification_password; + document.getElementById("mail_notification_checkbox").checked = pref.mail_notification_enabled; + document.getElementById("src_email_txt").value = pref.mail_notification_sender; + document.getElementById("dest_email_txt").value = pref.mail_notification_email; + document.getElementById("smtp_server_txt").value = pref.mail_notification_smtp; + document.getElementById("mail_ssl_checkbox").checked = pref.mail_notification_ssl_enabled; + document.getElementById("mail_auth_checkbox").checked = pref.mail_notification_auth_enabled; + document.getElementById("mail_username_text").value = pref.mail_notification_username; + document.getElementById("mail_password_text").value = pref.mail_notification_password; updateMailNotification(); updateMailAuthSettings(); // Run an external program on torrent added - $("autorunOnTorrentAddedCheckbox").checked = pref.autorun_on_torrent_added_enabled; - $("autorunOnTorrentAddedProgram").value = pref.autorun_on_torrent_added_program; + document.getElementById("autorunOnTorrentAddedCheckbox").checked = pref.autorun_on_torrent_added_enabled; + document.getElementById("autorunOnTorrentAddedProgram").value = pref.autorun_on_torrent_added_program; updateAutoRunOnTorrentAdded(); // Run an external program on torrent finished - $("autorun_checkbox").checked = pref.autorun_enabled; - $("autorunProg_txt").value = pref.autorun_program; + document.getElementById("autorun_checkbox").checked = pref.autorun_enabled; + document.getElementById("autorunProg_txt").value = pref.autorun_program; updateAutoRun(); // Connection tab // Listening Port - $("portValue").value = Number(pref.listen_port); - $("upnpCheckbox").checked = pref.upnp; + document.getElementById("portValue").value = Number(pref.listen_port); + document.getElementById("upnpCheckbox").checked = pref.upnp; // Connections Limits const maxConnec = Number(pref.max_connec); if (maxConnec <= 0) { - $("maxConnectionsCheckbox").checked = false; - $("maxConnectionsValue").value = 500; + document.getElementById("maxConnectionsCheckbox").checked = false; + document.getElementById("maxConnectionsValue").value = 500; } else { - $("maxConnectionsCheckbox").checked = true; - $("maxConnectionsValue").value = maxConnec; + document.getElementById("maxConnectionsCheckbox").checked = true; + document.getElementById("maxConnectionsValue").value = maxConnec; } updateMaxConnecEnabled(); const maxConnecPerTorrent = Number(pref.max_connec_per_torrent); if (maxConnecPerTorrent <= 0) { - $("maxConnectionsPerTorrentCheckbox").checked = false; - $("maxConnectionsPerTorrentValue").value = 100; + document.getElementById("maxConnectionsPerTorrentCheckbox").checked = false; + document.getElementById("maxConnectionsPerTorrentValue").value = 100; } else { - $("maxConnectionsPerTorrentCheckbox").checked = true; - $("maxConnectionsPerTorrentValue").value = maxConnecPerTorrent; + document.getElementById("maxConnectionsPerTorrentCheckbox").checked = true; + document.getElementById("maxConnectionsPerTorrentValue").value = maxConnecPerTorrent; } updateMaxConnecPerTorrentEnabled(); const maxUploads = Number(pref.max_uploads); if (maxUploads <= 0) { - $("maxUploadsCheckbox").checked = false; - $("max_uploads_value").value = 8; + document.getElementById("maxUploadsCheckbox").checked = false; + document.getElementById("max_uploads_value").value = 8; } else { - $("maxUploadsCheckbox").checked = true; - $("max_uploads_value").value = maxUploads; + document.getElementById("maxUploadsCheckbox").checked = true; + document.getElementById("max_uploads_value").value = maxUploads; } updateMaxUploadsEnabled(); const maxUploadsPerTorrent = Number(pref.max_uploads_per_torrent); if (maxUploadsPerTorrent <= 0) { - $("maxUploadsPerTorrentCheckbox").checked = false; - $("maxUploadsPerTorrentValue").value = 4; + document.getElementById("maxUploadsPerTorrentCheckbox").checked = false; + document.getElementById("maxUploadsPerTorrentValue").value = 4; } else { - $("maxUploadsPerTorrentCheckbox").checked = true; - $("maxUploadsPerTorrentValue").value = maxUploadsPerTorrent; + document.getElementById("maxUploadsPerTorrentCheckbox").checked = true; + document.getElementById("maxUploadsPerTorrentValue").value = maxUploadsPerTorrent; } updateMaxUploadsPerTorrentEnabled(); // I2P - $("i2pEnabledCheckbox").checked = pref.i2p_enabled; - $("i2pAddress").value = pref.i2p_address; - $("i2pPort").value = pref.i2p_port; - $("i2pMixedMode").checked = pref.i2p_mixed_mode; + document.getElementById("i2pEnabledCheckbox").checked = pref.i2p_enabled; + document.getElementById("i2pAddress").value = pref.i2p_address; + document.getElementById("i2pPort").value = pref.i2p_port; + document.getElementById("i2pMixedMode").checked = pref.i2p_mixed_mode; updateI2PSettingsEnabled(); // Proxy Server - $("peer_proxy_type_select").value = pref.proxy_type; - $("peer_proxy_host_text").value = pref.proxy_ip; - $("peer_proxy_port_value").value = pref.proxy_port; - $("peer_proxy_auth_checkbox").checked = pref.proxy_auth_enabled; - $("peer_proxy_username_text").value = pref.proxy_username; - $("peer_proxy_password_text").value = pref.proxy_password; - $("proxyHostnameLookupCheckbox").checked = pref.proxy_hostname_lookup; - $("proxy_bittorrent_checkbox").checked = pref.proxy_bittorrent; - $("use_peer_proxy_checkbox").checked = pref.proxy_peer_connections; - $("proxy_rss_checkbox").checked = pref.proxy_rss; - $("proxy_misc_checkbox").checked = pref.proxy_misc; + document.getElementById("peer_proxy_type_select").value = pref.proxy_type; + document.getElementById("peer_proxy_host_text").value = pref.proxy_ip; + document.getElementById("peer_proxy_port_value").value = pref.proxy_port; + document.getElementById("peer_proxy_auth_checkbox").checked = pref.proxy_auth_enabled; + document.getElementById("peer_proxy_username_text").value = pref.proxy_username; + document.getElementById("peer_proxy_password_text").value = pref.proxy_password; + document.getElementById("proxyHostnameLookupCheckbox").checked = pref.proxy_hostname_lookup; + document.getElementById("proxy_bittorrent_checkbox").checked = pref.proxy_bittorrent; + document.getElementById("use_peer_proxy_checkbox").checked = pref.proxy_peer_connections; + document.getElementById("proxy_rss_checkbox").checked = pref.proxy_rss; + document.getElementById("proxy_misc_checkbox").checked = pref.proxy_misc; updatePeerProxySettings(); // IP Filtering - $("ipfilter_text_checkbox").checked = pref.ip_filter_enabled; - $("ipfilter_text").value = pref.ip_filter_path; - $("ipfilter_trackers_checkbox").checked = pref.ip_filter_trackers; - $("banned_IPs_textarea").value = pref.banned_IPs; + document.getElementById("ipfilter_text_checkbox").checked = pref.ip_filter_enabled; + document.getElementById("ipfilter_text").value = pref.ip_filter_path; + document.getElementById("ipfilter_trackers_checkbox").checked = pref.ip_filter_trackers; + document.getElementById("banned_IPs_textarea").value = pref.banned_IPs; updateFilterSettings(); // Speed tab // Global Rate Limits - $("upLimitValue").value = (Number(pref.up_limit) / 1024); - $("dlLimitValue").value = (Number(pref.dl_limit) / 1024); + document.getElementById("upLimitValue").value = (Number(pref.up_limit) / 1024); + document.getElementById("dlLimitValue").value = (Number(pref.dl_limit) / 1024); // Alternative Global Rate Limits - $("altUpLimitValue").value = (Number(pref.alt_up_limit) / 1024); - $("altDlLimitValue").value = (Number(pref.alt_dl_limit) / 1024); + document.getElementById("altUpLimitValue").value = (Number(pref.alt_up_limit) / 1024); + document.getElementById("altDlLimitValue").value = (Number(pref.alt_dl_limit) / 1024); - $("enable_protocol_combobox").value = pref.bittorrent_protocol; - $("limit_utp_rate_checkbox").checked = pref.limit_utp_rate; - $("limit_tcp_overhead_checkbox").checked = pref.limit_tcp_overhead; - $("limit_lan_peers_checkbox").checked = pref.limit_lan_peers; + document.getElementById("enable_protocol_combobox").value = pref.bittorrent_protocol; + document.getElementById("limit_utp_rate_checkbox").checked = pref.limit_utp_rate; + document.getElementById("limit_tcp_overhead_checkbox").checked = pref.limit_tcp_overhead; + document.getElementById("limit_lan_peers_checkbox").checked = pref.limit_lan_peers; // Scheduling - $("limitSchedulingCheckbox").checked = pref.scheduler_enabled; - $("schedule_from_hour").value = time_padding(pref.schedule_from_hour); - $("schedule_from_min").value = time_padding(pref.schedule_from_min); - $("schedule_to_hour").value = time_padding(pref.schedule_to_hour); - $("schedule_to_min").value = time_padding(pref.schedule_to_min); - $("schedule_freq_select").value = pref.scheduler_days; + document.getElementById("limitSchedulingCheckbox").checked = pref.scheduler_enabled; + document.getElementById("schedule_from_hour").value = time_padding(pref.schedule_from_hour); + document.getElementById("schedule_from_min").value = time_padding(pref.schedule_from_min); + document.getElementById("schedule_to_hour").value = time_padding(pref.schedule_to_hour); + document.getElementById("schedule_to_min").value = time_padding(pref.schedule_to_min); + document.getElementById("schedule_freq_select").value = pref.scheduler_days; updateSchedulingEnabled(); // Bittorrent tab // Privacy - $("dht_checkbox").checked = pref.dht; - $("pex_checkbox").checked = pref.pex; - $("lsd_checkbox").checked = pref.lsd; + document.getElementById("dht_checkbox").checked = pref.dht; + document.getElementById("pex_checkbox").checked = pref.pex; + document.getElementById("lsd_checkbox").checked = pref.lsd; const encryption = Number(pref.encryption); - $("encryption_select").getChildren("option")[encryption].selected = true; - $("anonymous_mode_checkbox").checked = pref.anonymous_mode; + document.getElementById("encryption_select").getChildren("option")[encryption].selected = true; + document.getElementById("anonymous_mode_checkbox").checked = pref.anonymous_mode; - $("maxActiveCheckingTorrents").value = pref.max_active_checking_torrents; + document.getElementById("maxActiveCheckingTorrents").value = pref.max_active_checking_torrents; // Torrent Queueing - $("queueingCheckbox").checked = pref.queueing_enabled; - $("maxActiveDlValue").value = Number(pref.max_active_downloads); - $("maxActiveUpValue").value = Number(pref.max_active_uploads); - $("maxActiveToValue").value = Number(pref.max_active_torrents); - $("dontCountSlowTorrentsCheckbox").checked = pref.dont_count_slow_torrents; - $("dlRateThresholdValue").value = Number(pref.slow_torrent_dl_rate_threshold); - $("ulRateThresholdValue").value = Number(pref.slow_torrent_ul_rate_threshold); - $("torrentInactiveTimerValue").value = Number(pref.slow_torrent_inactive_timer); + document.getElementById("queueingCheckbox").checked = pref.queueing_enabled; + document.getElementById("maxActiveDlValue").value = Number(pref.max_active_downloads); + document.getElementById("maxActiveUpValue").value = Number(pref.max_active_uploads); + document.getElementById("maxActiveToValue").value = Number(pref.max_active_torrents); + document.getElementById("dontCountSlowTorrentsCheckbox").checked = pref.dont_count_slow_torrents; + document.getElementById("dlRateThresholdValue").value = Number(pref.slow_torrent_dl_rate_threshold); + document.getElementById("ulRateThresholdValue").value = Number(pref.slow_torrent_ul_rate_threshold); + document.getElementById("torrentInactiveTimerValue").value = Number(pref.slow_torrent_inactive_timer); updateQueueingSystem(); // Share Limiting - $("maxRatioCheckbox").checked = pref.max_ratio_enabled; - $("maxRatioValue").value = (pref.max_ratio_enabled ? pref.max_ratio : 1); - $("maxSeedingTimeCheckbox").checked = pref.max_seeding_time_enabled; - $("maxSeedingTimeValue").value = (pref.max_seeding_time_enabled ? Number(pref.max_seeding_time) : 1440); - $("maxInactiveSeedingTimeCheckbox").checked = pref.max_inactive_seeding_time_enabled; - $("maxInactiveSeedingTimeValue").value = (pref.max_inactive_seeding_time_enabled ? Number(pref.max_inactive_seeding_time) : 1440); + document.getElementById("maxRatioCheckbox").checked = pref.max_ratio_enabled; + document.getElementById("maxRatioValue").value = (pref.max_ratio_enabled ? pref.max_ratio : 1); + document.getElementById("maxSeedingTimeCheckbox").checked = pref.max_seeding_time_enabled; + document.getElementById("maxSeedingTimeValue").value = (pref.max_seeding_time_enabled ? Number(pref.max_seeding_time) : 1440); + document.getElementById("maxInactiveSeedingTimeCheckbox").checked = pref.max_inactive_seeding_time_enabled; + document.getElementById("maxInactiveSeedingTimeValue").value = (pref.max_inactive_seeding_time_enabled ? Number(pref.max_inactive_seeding_time) : 1440); let maxRatioAct = 0; switch (Number(pref.max_ratio_act)) { case 0: // Stop @@ -2492,151 +2492,151 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD maxRatioAct = 2; break; } - $("maxRatioSelect").getChildren("option")[maxRatioAct].selected = true; + document.getElementById("maxRatioSelect").getChildren("option")[maxRatioAct].selected = true; updateMaxRatioTimeEnabled(); // Add trackers - $("add_trackers_checkbox").checked = pref.add_trackers_enabled; - $("add_trackers_textarea").value = pref.add_trackers; - $("addTrackersFromURLCheckbox").checked = pref.add_trackers_from_url_enabled; - $("addTrackersURLListTextarea").value = pref.add_trackers_url_list; - $("addTrackersURL").value = pref.add_trackers_url; + document.getElementById("add_trackers_checkbox").checked = pref.add_trackers_enabled; + document.getElementById("add_trackers_textarea").value = pref.add_trackers; + document.getElementById("addTrackersFromURLCheckbox").checked = pref.add_trackers_from_url_enabled; + document.getElementById("addTrackersURLListTextarea").value = pref.add_trackers_url_list; + document.getElementById("addTrackersURL").value = pref.add_trackers_url; updateAddTrackersEnabled(); updateAddTrackersFromURLEnabled(); // RSS Tab - $("enable_fetching_rss_feeds_checkbox").checked = pref.rss_processing_enabled; - $("feed_refresh_interval").value = pref.rss_refresh_interval; - $("feedFetchDelay").value = pref.rss_fetch_delay; - $("maximum_article_number").value = pref.rss_max_articles_per_feed; - $("enable_auto_downloading_rss_torrents_checkbox").checked = pref.rss_auto_downloading_enabled; - $("downlock_repack_proper_episodes").checked = pref.rss_download_repack_proper_episodes; - $("rss_filter_textarea").value = pref.rss_smart_episode_filters; + document.getElementById("enable_fetching_rss_feeds_checkbox").checked = pref.rss_processing_enabled; + document.getElementById("feed_refresh_interval").value = pref.rss_refresh_interval; + document.getElementById("feedFetchDelay").value = pref.rss_fetch_delay; + document.getElementById("maximum_article_number").value = pref.rss_max_articles_per_feed; + document.getElementById("enable_auto_downloading_rss_torrents_checkbox").checked = pref.rss_auto_downloading_enabled; + document.getElementById("downlock_repack_proper_episodes").checked = pref.rss_download_repack_proper_episodes; + document.getElementById("rss_filter_textarea").value = pref.rss_smart_episode_filters; // WebUI tab // HTTP Server - $("webuiDomainTextarea").value = pref.web_ui_domain_list; - $("webuiAddressValue").value = pref.web_ui_address; - $("webuiPortValue").value = pref.web_ui_port; - $("webuiUpnpCheckbox").checked = pref.web_ui_upnp; - $("use_https_checkbox").checked = pref.use_https; - $("ssl_cert_text").value = pref.web_ui_https_cert_path; - $("ssl_key_text").value = pref.web_ui_https_key_path; + document.getElementById("webuiDomainTextarea").value = pref.web_ui_domain_list; + document.getElementById("webuiAddressValue").value = pref.web_ui_address; + document.getElementById("webuiPortValue").value = pref.web_ui_port; + document.getElementById("webuiUpnpCheckbox").checked = pref.web_ui_upnp; + document.getElementById("use_https_checkbox").checked = pref.use_https; + document.getElementById("ssl_cert_text").value = pref.web_ui_https_cert_path; + document.getElementById("ssl_key_text").value = pref.web_ui_https_key_path; updateHttpsSettings(); // Authentication - $("webui_username_text").value = pref.web_ui_username; - $("bypass_local_auth_checkbox").checked = pref.bypass_local_auth; - $("bypass_auth_subnet_whitelist_checkbox").checked = pref.bypass_auth_subnet_whitelist_enabled; - $("bypass_auth_subnet_whitelist_textarea").value = pref.bypass_auth_subnet_whitelist; + document.getElementById("webui_username_text").value = pref.web_ui_username; + document.getElementById("bypass_local_auth_checkbox").checked = pref.bypass_local_auth; + document.getElementById("bypass_auth_subnet_whitelist_checkbox").checked = pref.bypass_auth_subnet_whitelist_enabled; + document.getElementById("bypass_auth_subnet_whitelist_textarea").value = pref.bypass_auth_subnet_whitelist; updateBypasssAuthSettings(); - $("webUIMaxAuthFailCountInput").value = Number(pref.web_ui_max_auth_fail_count); - $("webUIBanDurationInput").value = Number(pref.web_ui_ban_duration); - $("webUISessionTimeoutInput").value = Number(pref.web_ui_session_timeout); + document.getElementById("webUIMaxAuthFailCountInput").value = Number(pref.web_ui_max_auth_fail_count); + document.getElementById("webUIBanDurationInput").value = Number(pref.web_ui_ban_duration); + document.getElementById("webUISessionTimeoutInput").value = Number(pref.web_ui_session_timeout); // Use alternative WebUI - $("use_alt_webui_checkbox").checked = pref.alternative_webui_enabled; - $("webui_files_location_textarea").value = pref.alternative_webui_path; + document.getElementById("use_alt_webui_checkbox").checked = pref.alternative_webui_enabled; + document.getElementById("webui_files_location_textarea").value = pref.alternative_webui_path; updateAlternativeWebUISettings(); // Security - $("clickjacking_protection_checkbox").checked = pref.web_ui_clickjacking_protection_enabled; - $("csrf_protection_checkbox").checked = pref.web_ui_csrf_protection_enabled; - $("secureCookieCheckbox").checked = pref.web_ui_secure_cookie_enabled; - $("host_header_validation_checkbox").checked = pref.web_ui_host_header_validation_enabled; + document.getElementById("clickjacking_protection_checkbox").checked = pref.web_ui_clickjacking_protection_enabled; + document.getElementById("csrf_protection_checkbox").checked = pref.web_ui_csrf_protection_enabled; + document.getElementById("secureCookieCheckbox").checked = pref.web_ui_secure_cookie_enabled; + document.getElementById("host_header_validation_checkbox").checked = pref.web_ui_host_header_validation_enabled; updateHostHeaderValidationSettings(); // Custom HTTP headers - $("webUIUseCustomHTTPHeadersCheckbox").checked = pref.web_ui_use_custom_http_headers_enabled; - $("webUICustomHTTPHeadersTextarea").value = pref.web_ui_custom_http_headers; + document.getElementById("webUIUseCustomHTTPHeadersCheckbox").checked = pref.web_ui_use_custom_http_headers_enabled; + document.getElementById("webUICustomHTTPHeadersTextarea").value = pref.web_ui_custom_http_headers; updateWebUICustomHTTPHeadersSettings(); // Reverse Proxy - $("webUIReverseProxySupportCheckbox").checked = pref.web_ui_reverse_proxy_enabled; - $("webUIReverseProxiesListTextarea").value = pref.web_ui_reverse_proxies_list; + document.getElementById("webUIReverseProxySupportCheckbox").checked = pref.web_ui_reverse_proxy_enabled; + document.getElementById("webUIReverseProxiesListTextarea").value = pref.web_ui_reverse_proxies_list; updateWebUIReverseProxySettings(); // Update my dynamic domain name - $("use_dyndns_checkbox").checked = pref.dyndns_enabled; - $("dyndns_select").value = pref.dyndns_service; - $("dyndns_domain_text").value = pref.dyndns_domain; - $("dyndns_username_text").value = pref.dyndns_username; - $("dyndns_password_text").value = pref.dyndns_password; + document.getElementById("use_dyndns_checkbox").checked = pref.dyndns_enabled; + document.getElementById("dyndns_select").value = pref.dyndns_service; + document.getElementById("dyndns_domain_text").value = pref.dyndns_domain; + document.getElementById("dyndns_username_text").value = pref.dyndns_username; + document.getElementById("dyndns_password_text").value = pref.dyndns_password; updateDynDnsSettings(); // Advanced settings // qBittorrent section - $("resumeDataStorageType").value = pref.resume_data_storage_type; - $("torrentContentRemoveOption").value = pref.torrent_content_remove_option; - $("memoryWorkingSetLimit").value = pref.memory_working_set_limit; + document.getElementById("resumeDataStorageType").value = pref.resume_data_storage_type; + document.getElementById("torrentContentRemoveOption").value = pref.torrent_content_remove_option; + document.getElementById("memoryWorkingSetLimit").value = pref.memory_working_set_limit; updateNetworkInterfaces(pref.current_network_interface, pref.current_interface_name); updateInterfaceAddresses(pref.current_network_interface, pref.current_interface_address); - $("saveResumeDataInterval").value = pref.save_resume_data_interval; - $("saveStatisticsInterval").value = pref.save_statistics_interval; - $("torrentFileSizeLimit").value = (pref.torrent_file_size_limit / 1024 / 1024); + document.getElementById("saveResumeDataInterval").value = pref.save_resume_data_interval; + document.getElementById("saveStatisticsInterval").value = pref.save_statistics_interval; + document.getElementById("torrentFileSizeLimit").value = (pref.torrent_file_size_limit / 1024 / 1024); document.getElementById("confirmTorrentRecheck").checked = pref.confirm_torrent_recheck; - $("recheckTorrentsOnCompletion").checked = pref.recheck_completed_torrents; - $("appInstanceName").value = pref.app_instance_name; - $("refreshInterval").value = pref.refresh_interval; - $("resolvePeerCountries").checked = pref.resolve_peer_countries; - $("reannounceWhenAddressChanged").checked = pref.reannounce_when_address_changed; - $("enableEmbeddedTracker").checked = pref.enable_embedded_tracker; - $("embeddedTrackerPort").value = pref.embedded_tracker_port; - $("embeddedTrackerPortForwarding").checked = pref.embedded_tracker_port_forwarding; - $("markOfTheWeb").checked = pref.mark_of_the_web; - $("ignoreSSLErrors").checked = pref.ignore_ssl_errors; - $("pythonExecutablePath").value = pref.python_executable_path; + document.getElementById("recheckTorrentsOnCompletion").checked = pref.recheck_completed_torrents; + document.getElementById("appInstanceName").value = pref.app_instance_name; + document.getElementById("refreshInterval").value = pref.refresh_interval; + document.getElementById("resolvePeerCountries").checked = pref.resolve_peer_countries; + document.getElementById("reannounceWhenAddressChanged").checked = pref.reannounce_when_address_changed; + document.getElementById("enableEmbeddedTracker").checked = pref.enable_embedded_tracker; + document.getElementById("embeddedTrackerPort").value = pref.embedded_tracker_port; + document.getElementById("embeddedTrackerPortForwarding").checked = pref.embedded_tracker_port_forwarding; + document.getElementById("markOfTheWeb").checked = pref.mark_of_the_web; + document.getElementById("ignoreSSLErrors").checked = pref.ignore_ssl_errors; + document.getElementById("pythonExecutablePath").value = pref.python_executable_path; // libtorrent section - $("bdecodeDepthLimit").value = pref.bdecode_depth_limit; - $("bdecodeTokenLimit").value = pref.bdecode_token_limit; - $("asyncIOThreads").value = pref.async_io_threads; - $("hashingThreads").value = pref.hashing_threads; - $("filePoolSize").value = pref.file_pool_size; - $("outstandMemoryWhenCheckingTorrents").value = pref.checking_memory_use; - $("diskCache").value = pref.disk_cache; - $("diskCacheExpiryInterval").value = pref.disk_cache_ttl; - $("diskQueueSize").value = (pref.disk_queue_size / 1024); - $("diskIOType").value = pref.disk_io_type; - $("diskIOReadMode").value = pref.disk_io_read_mode; - $("diskIOWriteMode").value = pref.disk_io_write_mode; - $("coalesceReadsAndWrites").checked = pref.enable_coalesce_read_write; - $("pieceExtentAffinity").checked = pref.enable_piece_extent_affinity; - $("sendUploadPieceSuggestions").checked = pref.enable_upload_suggestions; - $("sendBufferWatermark").value = pref.send_buffer_watermark; - $("sendBufferLowWatermark").value = pref.send_buffer_low_watermark; - $("sendBufferWatermarkFactor").value = pref.send_buffer_watermark_factor; - $("connectionSpeed").value = pref.connection_speed; - $("socketSendBufferSize").value = (pref.socket_send_buffer_size / 1024); - $("socketReceiveBufferSize").value = (pref.socket_receive_buffer_size / 1024); - $("socketBacklogSize").value = pref.socket_backlog_size; - $("outgoingPortsMin").value = pref.outgoing_ports_min; - $("outgoingPortsMax").value = pref.outgoing_ports_max; - $("UPnPLeaseDuration").value = pref.upnp_lease_duration; - $("peerToS").value = pref.peer_tos; - $("utpTCPMixedModeAlgorithm").value = pref.utp_tcp_mixed_mode; - $("hostnameCacheTTL").value = pref.hostname_cache_ttl; - $("IDNSupportCheckbox").checked = pref.idn_support_enabled; - $("allowMultipleConnectionsFromTheSameIPAddress").checked = pref.enable_multi_connections_from_same_ip; - $("validateHTTPSTrackerCertificate").checked = pref.validate_https_tracker_certificate; - $("mitigateSSRF").checked = pref.ssrf_mitigation; - $("blockPeersOnPrivilegedPorts").checked = pref.block_peers_on_privileged_ports; - $("uploadSlotsBehavior").value = pref.upload_slots_behavior; - $("uploadChokingAlgorithm").value = pref.upload_choking_algorithm; - $("announceAllTrackers").checked = pref.announce_to_all_trackers; - $("announceAllTiers").checked = pref.announce_to_all_tiers; - $("announceIP").value = pref.announce_ip; - $("announcePort").value = pref.announce_port; - $("maxConcurrentHTTPAnnounces").value = pref.max_concurrent_http_announces; - $("stopTrackerTimeout").value = pref.stop_tracker_timeout; - $("peerTurnover").value = pref.peer_turnover; - $("peerTurnoverCutoff").value = pref.peer_turnover_cutoff; - $("peerTurnoverInterval").value = pref.peer_turnover_interval; - $("requestQueueSize").value = pref.request_queue_size; - $("dhtBootstrapNodes").value = pref.dht_bootstrap_nodes; - $("i2pInboundQuantity").value = pref.i2p_inbound_quantity; - $("i2pOutboundQuantity").value = pref.i2p_outbound_quantity; - $("i2pInboundLength").value = pref.i2p_inbound_length; - $("i2pOutboundLength").value = pref.i2p_outbound_length; + document.getElementById("bdecodeDepthLimit").value = pref.bdecode_depth_limit; + document.getElementById("bdecodeTokenLimit").value = pref.bdecode_token_limit; + document.getElementById("asyncIOThreads").value = pref.async_io_threads; + document.getElementById("hashingThreads").value = pref.hashing_threads; + document.getElementById("filePoolSize").value = pref.file_pool_size; + document.getElementById("outstandMemoryWhenCheckingTorrents").value = pref.checking_memory_use; + document.getElementById("diskCache").value = pref.disk_cache; + document.getElementById("diskCacheExpiryInterval").value = pref.disk_cache_ttl; + document.getElementById("diskQueueSize").value = (pref.disk_queue_size / 1024); + document.getElementById("diskIOType").value = pref.disk_io_type; + document.getElementById("diskIOReadMode").value = pref.disk_io_read_mode; + document.getElementById("diskIOWriteMode").value = pref.disk_io_write_mode; + document.getElementById("coalesceReadsAndWrites").checked = pref.enable_coalesce_read_write; + document.getElementById("pieceExtentAffinity").checked = pref.enable_piece_extent_affinity; + document.getElementById("sendUploadPieceSuggestions").checked = pref.enable_upload_suggestions; + document.getElementById("sendBufferWatermark").value = pref.send_buffer_watermark; + document.getElementById("sendBufferLowWatermark").value = pref.send_buffer_low_watermark; + document.getElementById("sendBufferWatermarkFactor").value = pref.send_buffer_watermark_factor; + document.getElementById("connectionSpeed").value = pref.connection_speed; + document.getElementById("socketSendBufferSize").value = (pref.socket_send_buffer_size / 1024); + document.getElementById("socketReceiveBufferSize").value = (pref.socket_receive_buffer_size / 1024); + document.getElementById("socketBacklogSize").value = pref.socket_backlog_size; + document.getElementById("outgoingPortsMin").value = pref.outgoing_ports_min; + document.getElementById("outgoingPortsMax").value = pref.outgoing_ports_max; + document.getElementById("UPnPLeaseDuration").value = pref.upnp_lease_duration; + document.getElementById("peerToS").value = pref.peer_tos; + document.getElementById("utpTCPMixedModeAlgorithm").value = pref.utp_tcp_mixed_mode; + document.getElementById("hostnameCacheTTL").value = pref.hostname_cache_ttl; + document.getElementById("IDNSupportCheckbox").checked = pref.idn_support_enabled; + document.getElementById("allowMultipleConnectionsFromTheSameIPAddress").checked = pref.enable_multi_connections_from_same_ip; + document.getElementById("validateHTTPSTrackerCertificate").checked = pref.validate_https_tracker_certificate; + document.getElementById("mitigateSSRF").checked = pref.ssrf_mitigation; + document.getElementById("blockPeersOnPrivilegedPorts").checked = pref.block_peers_on_privileged_ports; + document.getElementById("uploadSlotsBehavior").value = pref.upload_slots_behavior; + document.getElementById("uploadChokingAlgorithm").value = pref.upload_choking_algorithm; + document.getElementById("announceAllTrackers").checked = pref.announce_to_all_trackers; + document.getElementById("announceAllTiers").checked = pref.announce_to_all_tiers; + document.getElementById("announceIP").value = pref.announce_ip; + document.getElementById("announcePort").value = pref.announce_port; + document.getElementById("maxConcurrentHTTPAnnounces").value = pref.max_concurrent_http_announces; + document.getElementById("stopTrackerTimeout").value = pref.stop_tracker_timeout; + document.getElementById("peerTurnover").value = pref.peer_turnover; + document.getElementById("peerTurnoverCutoff").value = pref.peer_turnover_cutoff; + document.getElementById("peerTurnoverInterval").value = pref.peer_turnover_interval; + document.getElementById("requestQueueSize").value = pref.request_queue_size; + document.getElementById("dhtBootstrapNodes").value = pref.dht_bootstrap_nodes; + document.getElementById("i2pInboundQuantity").value = pref.i2p_inbound_quantity; + document.getElementById("i2pOutboundQuantity").value = pref.i2p_outbound_quantity; + document.getElementById("i2pInboundLength").value = pref.i2p_inbound_length; + document.getElementById("i2pOutboundLength").value = pref.i2p_outbound_length; } }); }; @@ -2647,7 +2647,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD // Behavior tab // Language - settings["locale"] = $("locale_select").value; + settings["locale"] = document.getElementById("locale_select").value; const colorScheme = Number(document.getElementById("colorSchemeSelect").value); if (colorScheme === 0) LocalPreferences.remove("color_scheme"); @@ -2655,52 +2655,52 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD LocalPreferences.set("color_scheme", "light"); else LocalPreferences.set("color_scheme", "dark"); - settings["status_bar_external_ip"] = $("statusBarExternalIP").checked; - settings["performance_warning"] = $("performanceWarning").checked; + settings["status_bar_external_ip"] = document.getElementById("statusBarExternalIP").checked; + settings["performance_warning"] = document.getElementById("performanceWarning").checked; LocalPreferences.set("full_url_tracker_column", document.getElementById("displayFullURLTrackerColumn").checked.toString()); LocalPreferences.set("use_virtual_list", document.getElementById("useVirtualList").checked.toString()); LocalPreferences.set("hide_zero_status_filters", document.getElementById("hideZeroFiltersCheckbox").checked.toString()); - LocalPreferences.set("dblclick_download", $("dblclickDownloadSelect").value); - LocalPreferences.set("dblclick_complete", $("dblclickCompleteSelect").value); + LocalPreferences.set("dblclick_download", document.getElementById("dblclickDownloadSelect").value); + LocalPreferences.set("dblclick_complete", document.getElementById("dblclickCompleteSelect").value); settings["confirm_torrent_deletion"] = document.getElementById("confirmTorrentDeletion").checked; LocalPreferences.set("use_alt_row_colors", document.getElementById("useAltRowColorsInput").checked.toString()); - settings["file_log_enabled"] = $("filelog_checkbox").checked; - settings["file_log_path"] = $("filelog_save_path_input").value; - settings["file_log_backup_enabled"] = $("filelog_backup_checkbox").checked; - settings["file_log_max_size"] = Number($("filelog_max_size_input").value); - settings["file_log_delete_old"] = $("filelog_delete_old_checkbox").checked; - settings["file_log_age"] = Number($("filelog_age_input").value); - settings["file_log_age_type"] = Number($("filelog_age_type_select").value); + settings["file_log_enabled"] = document.getElementById("filelog_checkbox").checked; + settings["file_log_path"] = document.getElementById("filelog_save_path_input").value; + settings["file_log_backup_enabled"] = document.getElementById("filelog_backup_checkbox").checked; + settings["file_log_max_size"] = Number(document.getElementById("filelog_max_size_input").value); + settings["file_log_delete_old"] = document.getElementById("filelog_delete_old_checkbox").checked; + settings["file_log_age"] = Number(document.getElementById("filelog_age_input").value); + settings["file_log_age_type"] = Number(document.getElementById("filelog_age_type_select").value); // Downloads tab // When adding a torrent - settings["torrent_content_layout"] = $("contentlayout_select").getSelected()[0].value; - settings["add_to_top_of_queue"] = $("addToTopOfQueueCheckbox").checked; - settings["add_stopped_enabled"] = $("dontstartdownloads_checkbox").checked; - settings["torrent_stop_condition"] = $("stopConditionSelect").getSelected()[0].value; + settings["torrent_content_layout"] = document.getElementById("contentlayout_select").getSelected()[0].value; + settings["add_to_top_of_queue"] = document.getElementById("addToTopOfQueueCheckbox").checked; + settings["add_stopped_enabled"] = document.getElementById("dontstartdownloads_checkbox").checked; + settings["torrent_stop_condition"] = document.getElementById("stopConditionSelect").getSelected()[0].value; settings["merge_trackers"] = document.getElementById("mergeTrackersInput").checked; - settings["auto_delete_mode"] = Number($("deletetorrentfileafter_checkbox").checked); + settings["auto_delete_mode"] = Number(document.getElementById("deletetorrentfileafter_checkbox").checked); - settings["preallocate_all"] = $("preallocateall_checkbox").checked; - settings["incomplete_files_ext"] = $("appendext_checkbox").checked; - settings["use_unwanted_folder"] = $("unwantedfolder_checkbox").checked; + settings["preallocate_all"] = document.getElementById("preallocateall_checkbox").checked; + settings["incomplete_files_ext"] = document.getElementById("appendext_checkbox").checked; + settings["use_unwanted_folder"] = document.getElementById("unwantedfolder_checkbox").checked; // Saving Management - settings["auto_tmm_enabled"] = ($("default_tmm_combobox").value === "true"); - settings["torrent_changed_tmm_enabled"] = ($("torrent_changed_tmm_combobox").value === "true"); - settings["save_path_changed_tmm_enabled"] = ($("save_path_changed_tmm_combobox").value === "true"); - settings["category_changed_tmm_enabled"] = ($("category_changed_tmm_combobox").value === "true"); - settings["use_subcategories"] = $("use_subcategories_checkbox").checked; + settings["auto_tmm_enabled"] = (document.getElementById("default_tmm_combobox").value === "true"); + settings["torrent_changed_tmm_enabled"] = (document.getElementById("torrent_changed_tmm_combobox").value === "true"); + settings["save_path_changed_tmm_enabled"] = (document.getElementById("save_path_changed_tmm_combobox").value === "true"); + settings["category_changed_tmm_enabled"] = (document.getElementById("category_changed_tmm_combobox").value === "true"); + settings["use_subcategories"] = document.getElementById("use_subcategories_checkbox").checked; settings["use_category_paths_in_manual_mode"] = document.getElementById("categoryPathsManualModeCheckbox").checked; - settings["save_path"] = $("savepath_text").value; - settings["temp_path_enabled"] = $("temppath_checkbox").checked; - settings["temp_path"] = $("temppath_text").value; - if ($("exportdir_checkbox").checked) - settings["export_dir"] = $("exportdir_text").value; + settings["save_path"] = document.getElementById("savepath_text").value; + settings["temp_path_enabled"] = document.getElementById("temppath_checkbox").checked; + settings["temp_path"] = document.getElementById("temppath_text").value; + if (document.getElementById("exportdir_checkbox").checked) + settings["export_dir"] = document.getElementById("exportdir_text").value; else settings["export_dir"] = ""; - if ($("exportdirfin_checkbox").checked) - settings["export_dir_fin"] = $("exportdirfin_text").value; + if (document.getElementById("exportdirfin_checkbox").checked) + settings["export_dir_fin"] = document.getElementById("exportdirfin_text").value; else settings["export_dir_fin"] = ""; @@ -2708,40 +2708,40 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD settings["scan_dirs"] = getWatchedFolders(); // Excluded file names - settings["excluded_file_names_enabled"] = $("excludedFileNamesCheckbox").checked; - settings["excluded_file_names"] = $("excludedFileNamesTextarea").value; + settings["excluded_file_names_enabled"] = document.getElementById("excludedFileNamesCheckbox").checked; + settings["excluded_file_names"] = document.getElementById("excludedFileNamesTextarea").value; // Email notification upon download completion - settings["mail_notification_enabled"] = $("mail_notification_checkbox").checked; - settings["mail_notification_sender"] = $("src_email_txt").value; - settings["mail_notification_email"] = $("dest_email_txt").value; - settings["mail_notification_smtp"] = $("smtp_server_txt").value; - settings["mail_notification_ssl_enabled"] = $("mail_ssl_checkbox").checked; - settings["mail_notification_auth_enabled"] = $("mail_auth_checkbox").checked; - settings["mail_notification_username"] = $("mail_username_text").value; - settings["mail_notification_password"] = $("mail_password_text").value; + settings["mail_notification_enabled"] = document.getElementById("mail_notification_checkbox").checked; + settings["mail_notification_sender"] = document.getElementById("src_email_txt").value; + settings["mail_notification_email"] = document.getElementById("dest_email_txt").value; + settings["mail_notification_smtp"] = document.getElementById("smtp_server_txt").value; + settings["mail_notification_ssl_enabled"] = document.getElementById("mail_ssl_checkbox").checked; + settings["mail_notification_auth_enabled"] = document.getElementById("mail_auth_checkbox").checked; + settings["mail_notification_username"] = document.getElementById("mail_username_text").value; + settings["mail_notification_password"] = document.getElementById("mail_password_text").value; // Run an external program on torrent added - settings["autorun_on_torrent_added_enabled"] = $("autorunOnTorrentAddedCheckbox").checked; - settings["autorun_on_torrent_added_program"] = $("autorunOnTorrentAddedProgram").value; + settings["autorun_on_torrent_added_enabled"] = document.getElementById("autorunOnTorrentAddedCheckbox").checked; + settings["autorun_on_torrent_added_program"] = document.getElementById("autorunOnTorrentAddedProgram").value; // Run an external program on torrent finished - settings["autorun_enabled"] = $("autorun_checkbox").checked; - settings["autorun_program"] = $("autorunProg_txt").value; + settings["autorun_enabled"] = document.getElementById("autorun_checkbox").checked; + settings["autorun_program"] = document.getElementById("autorunProg_txt").value; // Connection tab // Listening Port - const listenPort = Number($("portValue").value); + const listenPort = Number(document.getElementById("portValue").value); if (Number.isNaN(listenPort) || (listenPort < 0) || (listenPort > 65535)) { alert("QBT_TR(The port used for incoming connections must be between 0 and 65535.)QBT_TR[CONTEXT=HttpServer]"); return; } settings["listen_port"] = listenPort; - settings["upnp"] = $("upnpCheckbox").checked; + settings["upnp"] = document.getElementById("upnpCheckbox").checked; // Connections Limits let maxConnec = -1; - if ($("maxConnectionsCheckbox").checked) { - maxConnec = Number($("maxConnectionsValue").value); + if (document.getElementById("maxConnectionsCheckbox").checked) { + maxConnec = Number(document.getElementById("maxConnectionsValue").value); if (Number.isNaN(maxConnec) || (maxConnec <= 0)) { alert("QBT_TR(Maximum number of connections limit must be greater than 0 or disabled.)QBT_TR[CONTEXT=HttpServer]"); return; @@ -2750,8 +2750,8 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD settings["max_connec"] = maxConnec; let maxConnecPerTorrent = -1; - if ($("maxConnectionsPerTorrentCheckbox").checked) { - maxConnecPerTorrent = Number($("maxConnectionsPerTorrentValue").value); + if (document.getElementById("maxConnectionsPerTorrentCheckbox").checked) { + maxConnecPerTorrent = Number(document.getElementById("maxConnectionsPerTorrentValue").value); if (Number.isNaN(maxConnecPerTorrent) || (maxConnecPerTorrent <= 0)) { alert("QBT_TR(Maximum number of connections per torrent limit must be greater than 0 or disabled.)QBT_TR[CONTEXT=HttpServer]"); return; @@ -2760,8 +2760,8 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD settings["max_connec_per_torrent"] = maxConnecPerTorrent; let maxUploads = -1; - if ($("maxUploadsCheckbox").checked) { - maxUploads = Number($("max_uploads_value").value); + if (document.getElementById("maxUploadsCheckbox").checked) { + maxUploads = Number(document.getElementById("max_uploads_value").value); if (Number.isNaN(maxUploads) || (maxUploads <= 0)) { alert("QBT_TR(Global number of upload slots limit must be greater than 0 or disabled.)QBT_TR[CONTEXT=HttpServer]"); return; @@ -2770,8 +2770,8 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD settings["max_uploads"] = maxUploads; let maxUploadsPerTorrent = -1; - if ($("maxUploadsPerTorrentCheckbox").checked) { - maxUploadsPerTorrent = Number($("maxUploadsPerTorrentValue").value); + if (document.getElementById("maxUploadsPerTorrentCheckbox").checked) { + maxUploadsPerTorrent = Number(document.getElementById("maxUploadsPerTorrentValue").value); if (Number.isNaN(maxUploadsPerTorrent) || (maxUploadsPerTorrent <= 0)) { alert("QBT_TR(Maximum number of upload slots per torrent limit must be greater than 0 or disabled.)QBT_TR[CONTEXT=HttpServer]"); return; @@ -2780,40 +2780,40 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD settings["max_uploads_per_torrent"] = maxUploadsPerTorrent; // I2P - settings["i2p_enabled"] = $("i2pEnabledCheckbox").checked; - settings["i2p_address"] = $("i2pAddress").value; - settings["i2p_port"] = Number($("i2pPort").value); - settings["i2p_mixed_mode"] = $("i2pMixedMode").checked; + settings["i2p_enabled"] = document.getElementById("i2pEnabledCheckbox").checked; + settings["i2p_address"] = document.getElementById("i2pAddress").value; + settings["i2p_port"] = Number(document.getElementById("i2pPort").value); + settings["i2p_mixed_mode"] = document.getElementById("i2pMixedMode").checked; // Proxy Server - settings["proxy_type"] = $("peer_proxy_type_select").value; - settings["proxy_ip"] = $("peer_proxy_host_text").value; - settings["proxy_port"] = Number($("peer_proxy_port_value").value); - settings["proxy_auth_enabled"] = $("peer_proxy_auth_checkbox").checked; - settings["proxy_username"] = $("peer_proxy_username_text").value; - settings["proxy_password"] = $("peer_proxy_password_text").value; - settings["proxy_hostname_lookup"] = $("proxyHostnameLookupCheckbox").checked; - settings["proxy_bittorrent"] = $("proxy_bittorrent_checkbox").checked; - settings["proxy_peer_connections"] = $("use_peer_proxy_checkbox").checked; - settings["proxy_rss"] = $("proxy_rss_checkbox").checked; - settings["proxy_misc"] = $("proxy_misc_checkbox").checked; + settings["proxy_type"] = document.getElementById("peer_proxy_type_select").value; + settings["proxy_ip"] = document.getElementById("peer_proxy_host_text").value; + settings["proxy_port"] = Number(document.getElementById("peer_proxy_port_value").value); + settings["proxy_auth_enabled"] = document.getElementById("peer_proxy_auth_checkbox").checked; + settings["proxy_username"] = document.getElementById("peer_proxy_username_text").value; + settings["proxy_password"] = document.getElementById("peer_proxy_password_text").value; + settings["proxy_hostname_lookup"] = document.getElementById("proxyHostnameLookupCheckbox").checked; + settings["proxy_bittorrent"] = document.getElementById("proxy_bittorrent_checkbox").checked; + settings["proxy_peer_connections"] = document.getElementById("use_peer_proxy_checkbox").checked; + settings["proxy_rss"] = document.getElementById("proxy_rss_checkbox").checked; + settings["proxy_misc"] = document.getElementById("proxy_misc_checkbox").checked; // IP Filtering - settings["ip_filter_enabled"] = $("ipfilter_text_checkbox").checked; - settings["ip_filter_path"] = $("ipfilter_text").value; - settings["ip_filter_trackers"] = $("ipfilter_trackers_checkbox").checked; - settings["banned_IPs"] = $("banned_IPs_textarea").value; + settings["ip_filter_enabled"] = document.getElementById("ipfilter_text_checkbox").checked; + settings["ip_filter_path"] = document.getElementById("ipfilter_text").value; + settings["ip_filter_trackers"] = document.getElementById("ipfilter_trackers_checkbox").checked; + settings["banned_IPs"] = document.getElementById("banned_IPs_textarea").value; // Speed tab // Global Rate Limits - const upLimit = Number($("upLimitValue").value) * 1024; + const upLimit = Number(document.getElementById("upLimitValue").value) * 1024; if (Number.isNaN(upLimit) || (upLimit < 0)) { alert("QBT_TR(Global upload rate limit must be greater than 0 or disabled.)QBT_TR[CONTEXT=HttpServer]"); return; } settings["up_limit"] = upLimit; - const dlLimit = Number($("dlLimitValue").value) * 1024; + const dlLimit = Number(document.getElementById("dlLimitValue").value) * 1024; if (Number.isNaN(dlLimit) || (dlLimit < 0)) { alert("QBT_TR(Global download rate limit must be greater than 0 or disabled.)QBT_TR[CONTEXT=HttpServer]"); return; @@ -2821,86 +2821,86 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD settings["dl_limit"] = dlLimit; // Alternative Global Rate Limits - const altUpLimit = Number($("altUpLimitValue").value) * 1024; + const altUpLimit = Number(document.getElementById("altUpLimitValue").value) * 1024; if (Number.isNaN(altUpLimit) || (altUpLimit < 0)) { alert("QBT_TR(Alternative upload rate limit must be greater than 0 or disabled.)QBT_TR[CONTEXT=HttpServer]"); return; } settings["alt_up_limit"] = altUpLimit; - const altDlLimit = Number($("altDlLimitValue").value) * 1024; + const altDlLimit = Number(document.getElementById("altDlLimitValue").value) * 1024; if (Number.isNaN(altDlLimit) || (altDlLimit < 0)) { alert("QBT_TR(Alternative download rate limit must be greater than 0 or disabled.)QBT_TR[CONTEXT=HttpServer]"); return; } settings["alt_dl_limit"] = altDlLimit; - settings["bittorrent_protocol"] = Number($("enable_protocol_combobox").value); - settings["limit_utp_rate"] = $("limit_utp_rate_checkbox").checked; - settings["limit_tcp_overhead"] = $("limit_tcp_overhead_checkbox").checked; - settings["limit_lan_peers"] = $("limit_lan_peers_checkbox").checked; + settings["bittorrent_protocol"] = Number(document.getElementById("enable_protocol_combobox").value); + settings["limit_utp_rate"] = document.getElementById("limit_utp_rate_checkbox").checked; + settings["limit_tcp_overhead"] = document.getElementById("limit_tcp_overhead_checkbox").checked; + settings["limit_lan_peers"] = document.getElementById("limit_lan_peers_checkbox").checked; // Scheduler - const schedulingEnabled = $("limitSchedulingCheckbox").checked; + const schedulingEnabled = document.getElementById("limitSchedulingCheckbox").checked; settings["scheduler_enabled"] = schedulingEnabled; if (schedulingEnabled) { - settings["schedule_from_hour"] = Number($("schedule_from_hour").value); - settings["schedule_from_min"] = Number($("schedule_from_min").value); - settings["schedule_to_hour"] = Number($("schedule_to_hour").value); - settings["schedule_to_min"] = Number($("schedule_to_min").value); - settings["scheduler_days"] = Number($("schedule_freq_select").value); + settings["schedule_from_hour"] = Number(document.getElementById("schedule_from_hour").value); + settings["schedule_from_min"] = Number(document.getElementById("schedule_from_min").value); + settings["schedule_to_hour"] = Number(document.getElementById("schedule_to_hour").value); + settings["schedule_to_min"] = Number(document.getElementById("schedule_to_min").value); + settings["scheduler_days"] = Number(document.getElementById("schedule_freq_select").value); } // Bittorrent tab // Privacy - settings["dht"] = $("dht_checkbox").checked; - settings["pex"] = $("pex_checkbox").checked; - settings["lsd"] = $("lsd_checkbox").checked; - settings["encryption"] = Number($("encryption_select").getSelected()[0].value); - settings["anonymous_mode"] = $("anonymous_mode_checkbox").checked; + settings["dht"] = document.getElementById("dht_checkbox").checked; + settings["pex"] = document.getElementById("pex_checkbox").checked; + settings["lsd"] = document.getElementById("lsd_checkbox").checked; + settings["encryption"] = Number(document.getElementById("encryption_select").getSelected()[0].value); + settings["anonymous_mode"] = document.getElementById("anonymous_mode_checkbox").checked; - settings["max_active_checking_torrents"] = Number($("maxActiveCheckingTorrents").value); + settings["max_active_checking_torrents"] = Number(document.getElementById("maxActiveCheckingTorrents").value); // Torrent Queueing - settings["queueing_enabled"] = $("queueingCheckbox").checked; - if ($("queueingCheckbox").checked) { - const maxActiveDownloads = Number($("maxActiveDlValue").value); + settings["queueing_enabled"] = document.getElementById("queueingCheckbox").checked; + if (document.getElementById("queueingCheckbox").checked) { + const maxActiveDownloads = Number(document.getElementById("maxActiveDlValue").value); if (Number.isNaN(maxActiveDownloads) || (maxActiveDownloads < -1)) { alert("QBT_TR(Maximum active downloads must be greater than -1.)QBT_TR[CONTEXT=HttpServer]"); return; } settings["max_active_downloads"] = maxActiveDownloads; - const maxActiveUploads = Number($("maxActiveUpValue").value); + const maxActiveUploads = Number(document.getElementById("maxActiveUpValue").value); if (Number.isNaN(maxActiveUploads) || (maxActiveUploads < -1)) { alert("QBT_TR(Maximum active uploads must be greater than -1.)QBT_TR[CONTEXT=HttpServer]"); return; } settings["max_active_uploads"] = maxActiveUploads; - const maxActiveTorrents = Number($("maxActiveToValue").value); + const maxActiveTorrents = Number(document.getElementById("maxActiveToValue").value); if (Number.isNaN(maxActiveTorrents) || (maxActiveTorrents < -1)) { alert("QBT_TR(Maximum active torrents must be greater than -1.)QBT_TR[CONTEXT=HttpServer]"); return; } settings["max_active_torrents"] = maxActiveTorrents; - settings["dont_count_slow_torrents"] = $("dontCountSlowTorrentsCheckbox").checked; + settings["dont_count_slow_torrents"] = document.getElementById("dontCountSlowTorrentsCheckbox").checked; - const dlRateThreshold = Number($("dlRateThresholdValue").value); + const dlRateThreshold = Number(document.getElementById("dlRateThresholdValue").value); if (Number.isNaN(dlRateThreshold) || (dlRateThreshold < 1)) { alert("QBT_TR(Download rate threshold must be greater than 0.)QBT_TR[CONTEXT=HttpServer]"); return; } settings["slow_torrent_dl_rate_threshold"] = dlRateThreshold; - const ulRateThreshold = Number($("ulRateThresholdValue").value); + const ulRateThreshold = Number(document.getElementById("ulRateThresholdValue").value); if (Number.isNaN(ulRateThreshold) || (ulRateThreshold < 1)) { alert("QBT_TR(Upload rate threshold must be greater than 0.)QBT_TR[CONTEXT=HttpServer]"); return; } settings["slow_torrent_ul_rate_threshold"] = ulRateThreshold; - const torrentInactiveTimer = Number($("torrentInactiveTimerValue").value); + const torrentInactiveTimer = Number(document.getElementById("torrentInactiveTimerValue").value); if (Number.isNaN(torrentInactiveTimer) || (torrentInactiveTimer < 1)) { alert("QBT_TR(Torrent inactivity timer must be greater than 0.)QBT_TR[CONTEXT=HttpServer]"); return; @@ -2910,78 +2910,78 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD // Share Ratio Limiting let maxRatio = -1; - if ($("maxRatioCheckbox").checked) { - maxRatio = Number($("maxRatioValue").value); + if (document.getElementById("maxRatioCheckbox").checked) { + maxRatio = Number(document.getElementById("maxRatioValue").value); if (isNaN(maxRatio) || (maxRatio < 0) || (maxRatio > 9998)) { alert("QBT_TR(Share ratio limit must be between 0 and 9998.)QBT_TR[CONTEXT=HttpServer]"); return; } } - settings["max_ratio_enabled"] = $("maxRatioCheckbox").checked; + settings["max_ratio_enabled"] = document.getElementById("maxRatioCheckbox").checked; settings["max_ratio"] = maxRatio; let maxSeedingTime = -1; - if ($("maxSeedingTimeCheckbox").checked) { - maxSeedingTime = Number($("maxSeedingTimeValue").value); + if (document.getElementById("maxSeedingTimeCheckbox").checked) { + maxSeedingTime = Number(document.getElementById("maxSeedingTimeValue").value); if (Number.isNaN(maxSeedingTime) || (maxSeedingTime < 0) || (maxSeedingTime > 525600)) { alert("QBT_TR(Seeding time limit must be between 0 and 525600 minutes.)QBT_TR[CONTEXT=HttpServer]"); return; } } - settings["max_seeding_time_enabled"] = $("maxSeedingTimeCheckbox").checked; + settings["max_seeding_time_enabled"] = document.getElementById("maxSeedingTimeCheckbox").checked; settings["max_seeding_time"] = maxSeedingTime; let maxInactiveSeedingTime = -1; - if ($("maxInactiveSeedingTimeCheckbox").checked) { - maxInactiveSeedingTime = Number($("maxInactiveSeedingTimeValue").value); + if (document.getElementById("maxInactiveSeedingTimeCheckbox").checked) { + maxInactiveSeedingTime = Number(document.getElementById("maxInactiveSeedingTimeValue").value); if (Number.isNaN(maxInactiveSeedingTime) || (maxInactiveSeedingTime < 0) || (maxInactiveSeedingTime > 525600)) { alert("QBT_TR(Seeding time limit must be between 0 and 525600 minutes.)QBT_TR[CONTEXT=HttpServer]"); return; } } - settings["max_inactive_seeding_time_enabled"] = $("maxInactiveSeedingTimeCheckbox").checked; + settings["max_inactive_seeding_time_enabled"] = document.getElementById("maxInactiveSeedingTimeCheckbox").checked; settings["max_inactive_seeding_time"] = maxInactiveSeedingTime; - settings["max_ratio_act"] = Number($("maxRatioSelect").value); + settings["max_ratio_act"] = Number(document.getElementById("maxRatioSelect").value); // Add trackers - settings["add_trackers_enabled"] = $("add_trackers_checkbox").checked; - settings["add_trackers"] = $("add_trackers_textarea").value; - settings["add_trackers_from_url_enabled"] = $("addTrackersFromURLCheckbox").checked; - settings["add_trackers_url"] = $("addTrackersURL").value; + settings["add_trackers_enabled"] = document.getElementById("add_trackers_checkbox").checked; + settings["add_trackers"] = document.getElementById("add_trackers_textarea").value; + settings["add_trackers_from_url_enabled"] = document.getElementById("addTrackersFromURLCheckbox").checked; + settings["add_trackers_url"] = document.getElementById("addTrackersURL").value; // RSS Tab - settings["rss_processing_enabled"] = $("enable_fetching_rss_feeds_checkbox").checked; - settings["rss_refresh_interval"] = Number($("feed_refresh_interval").value); - settings["rss_fetch_delay"] = Number($("feedFetchDelay").value); - settings["rss_max_articles_per_feed"] = Number($("maximum_article_number").value); - settings["rss_auto_downloading_enabled"] = $("enable_auto_downloading_rss_torrents_checkbox").checked; - settings["rss_download_repack_proper_episodes"] = $("downlock_repack_proper_episodes").checked; - settings["rss_smart_episode_filters"] = $("rss_filter_textarea").value; + settings["rss_processing_enabled"] = document.getElementById("enable_fetching_rss_feeds_checkbox").checked; + settings["rss_refresh_interval"] = Number(document.getElementById("feed_refresh_interval").value); + settings["rss_fetch_delay"] = Number(document.getElementById("feedFetchDelay").value); + settings["rss_max_articles_per_feed"] = Number(document.getElementById("maximum_article_number").value); + settings["rss_auto_downloading_enabled"] = document.getElementById("enable_auto_downloading_rss_torrents_checkbox").checked; + settings["rss_download_repack_proper_episodes"] = document.getElementById("downlock_repack_proper_episodes").checked; + settings["rss_smart_episode_filters"] = document.getElementById("rss_filter_textarea").value; // WebUI tab // HTTP Server - settings["web_ui_domain_list"] = $("webuiDomainTextarea").value; - const webUIAddress = $("webuiAddressValue").value.toString(); - const webUIPort = Number($("webuiPortValue").value); + settings["web_ui_domain_list"] = document.getElementById("webuiDomainTextarea").value; + const webUIAddress = document.getElementById("webuiAddressValue").value.toString(); + const webUIPort = Number(document.getElementById("webuiPortValue").value); if (Number.isNaN(webUIPort) || (webUIPort < 1) || (webUIPort > 65535)) { alert("QBT_TR(The port used for the WebUI must be between 1 and 65535.)QBT_TR[CONTEXT=HttpServer]"); return; } settings["web_ui_address"] = webUIAddress; settings["web_ui_port"] = webUIPort; - settings["web_ui_upnp"] = $("webuiUpnpCheckbox").checked; + settings["web_ui_upnp"] = document.getElementById("webuiUpnpCheckbox").checked; - const useHTTPS = $("use_https_checkbox").checked; + const useHTTPS = document.getElementById("use_https_checkbox").checked; settings["use_https"] = useHTTPS; - const httpsCertificate = $("ssl_cert_text").value; + const httpsCertificate = document.getElementById("ssl_cert_text").value; settings["web_ui_https_cert_path"] = httpsCertificate; if (useHTTPS && (httpsCertificate.length === 0)) { alert("QBT_TR(HTTPS certificate should not be empty)QBT_TR[CONTEXT=OptionsDialog]"); return; } - const httpsKey = $("ssl_key_text").value; + const httpsKey = document.getElementById("ssl_key_text").value; settings["web_ui_https_key_path"] = httpsKey; if (useHTTPS && (httpsKey.length === 0)) { alert("QBT_TR(HTTPS key should not be empty)QBT_TR[CONTEXT=OptionsDialog]"); @@ -2989,12 +2989,12 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD } // Authentication - const web_ui_username = $("webui_username_text").value; + const web_ui_username = document.getElementById("webui_username_text").value; if (web_ui_username.length < 3) { alert("QBT_TR(The WebUI username must be at least 3 characters long.)QBT_TR[CONTEXT=OptionsDialog]"); return; } - const web_ui_password = $("webui_password_text").value; + const web_ui_password = document.getElementById("webui_password_text").value; if ((0 < web_ui_password.length) && (web_ui_password.length < 6)) { alert("QBT_TR(The WebUI password must be at least 6 characters long.)QBT_TR[CONTEXT=OptionsDialog]"); return; @@ -3003,16 +3003,16 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD settings["web_ui_username"] = web_ui_username; if (web_ui_password.length > 0) settings["web_ui_password"] = web_ui_password; - settings["bypass_local_auth"] = $("bypass_local_auth_checkbox").checked; - settings["bypass_auth_subnet_whitelist_enabled"] = $("bypass_auth_subnet_whitelist_checkbox").checked; - settings["bypass_auth_subnet_whitelist"] = $("bypass_auth_subnet_whitelist_textarea").value; - settings["web_ui_max_auth_fail_count"] = Number($("webUIMaxAuthFailCountInput").value); - settings["web_ui_ban_duration"] = Number($("webUIBanDurationInput").value); - settings["web_ui_session_timeout"] = Number($("webUISessionTimeoutInput").value); + settings["bypass_local_auth"] = document.getElementById("bypass_local_auth_checkbox").checked; + settings["bypass_auth_subnet_whitelist_enabled"] = document.getElementById("bypass_auth_subnet_whitelist_checkbox").checked; + settings["bypass_auth_subnet_whitelist"] = document.getElementById("bypass_auth_subnet_whitelist_textarea").value; + settings["web_ui_max_auth_fail_count"] = Number(document.getElementById("webUIMaxAuthFailCountInput").value); + settings["web_ui_ban_duration"] = Number(document.getElementById("webUIBanDurationInput").value); + settings["web_ui_session_timeout"] = Number(document.getElementById("webUISessionTimeoutInput").value); // Use alternative WebUI - const alternative_webui_enabled = $("use_alt_webui_checkbox").checked; - const webui_files_location_textarea = $("webui_files_location_textarea").value; + const alternative_webui_enabled = document.getElementById("use_alt_webui_checkbox").checked; + const webui_files_location_textarea = document.getElementById("webui_files_location_textarea").value; if (alternative_webui_enabled && (webui_files_location_textarea.trim() === "")) { alert("QBT_TR(The alternative WebUI files location cannot be blank.)QBT_TR[CONTEXT=OptionsDialog]"); return; @@ -3021,105 +3021,105 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD settings["alternative_webui_path"] = webui_files_location_textarea; // Security - settings["web_ui_clickjacking_protection_enabled"] = $("clickjacking_protection_checkbox").checked; - settings["web_ui_csrf_protection_enabled"] = $("csrf_protection_checkbox").checked; - settings["web_ui_secure_cookie_enabled"] = $("secureCookieCheckbox").checked; - settings["web_ui_host_header_validation_enabled"] = $("host_header_validation_checkbox").checked; + settings["web_ui_clickjacking_protection_enabled"] = document.getElementById("clickjacking_protection_checkbox").checked; + settings["web_ui_csrf_protection_enabled"] = document.getElementById("csrf_protection_checkbox").checked; + settings["web_ui_secure_cookie_enabled"] = document.getElementById("secureCookieCheckbox").checked; + settings["web_ui_host_header_validation_enabled"] = document.getElementById("host_header_validation_checkbox").checked; // Custom HTTP headers - settings["web_ui_use_custom_http_headers_enabled"] = $("webUIUseCustomHTTPHeadersCheckbox").checked; - settings["web_ui_custom_http_headers"] = $("webUICustomHTTPHeadersTextarea").value; + settings["web_ui_use_custom_http_headers_enabled"] = document.getElementById("webUIUseCustomHTTPHeadersCheckbox").checked; + settings["web_ui_custom_http_headers"] = document.getElementById("webUICustomHTTPHeadersTextarea").value; // Reverse Proxy - settings["web_ui_reverse_proxy_enabled"] = $("webUIReverseProxySupportCheckbox").checked; - settings["web_ui_reverse_proxies_list"] = $("webUIReverseProxiesListTextarea").value; + settings["web_ui_reverse_proxy_enabled"] = document.getElementById("webUIReverseProxySupportCheckbox").checked; + settings["web_ui_reverse_proxies_list"] = document.getElementById("webUIReverseProxiesListTextarea").value; // Update my dynamic domain name - settings["dyndns_enabled"] = $("use_dyndns_checkbox").checked; - settings["dyndns_service"] = Number($("dyndns_select").value); - settings["dyndns_domain"] = $("dyndns_domain_text").value; - settings["dyndns_username"] = $("dyndns_username_text").value; - settings["dyndns_password"] = $("dyndns_password_text").value; + settings["dyndns_enabled"] = document.getElementById("use_dyndns_checkbox").checked; + settings["dyndns_service"] = Number(document.getElementById("dyndns_select").value); + settings["dyndns_domain"] = document.getElementById("dyndns_domain_text").value; + settings["dyndns_username"] = document.getElementById("dyndns_username_text").value; + settings["dyndns_password"] = document.getElementById("dyndns_password_text").value; // Update advanced settings // qBittorrent section - settings["resume_data_storage_type"] = $("resumeDataStorageType").value; - settings["torrent_content_remove_option"] = $("torrentContentRemoveOption").value; - settings["memory_working_set_limit"] = Number($("memoryWorkingSetLimit").value); - settings["current_network_interface"] = $("networkInterface").value; - settings["current_interface_address"] = $("optionalIPAddressToBind").value; - settings["save_resume_data_interval"] = Number($("saveResumeDataInterval").value); - settings["save_statistics_interval"] = Number($("saveStatisticsInterval").value); - settings["torrent_file_size_limit"] = ($("torrentFileSizeLimit").value * 1024 * 1024); + settings["resume_data_storage_type"] = document.getElementById("resumeDataStorageType").value; + settings["torrent_content_remove_option"] = document.getElementById("torrentContentRemoveOption").value; + settings["memory_working_set_limit"] = Number(document.getElementById("memoryWorkingSetLimit").value); + settings["current_network_interface"] = document.getElementById("networkInterface").value; + settings["current_interface_address"] = document.getElementById("optionalIPAddressToBind").value; + settings["save_resume_data_interval"] = Number(document.getElementById("saveResumeDataInterval").value); + settings["save_statistics_interval"] = Number(document.getElementById("saveStatisticsInterval").value); + settings["torrent_file_size_limit"] = (document.getElementById("torrentFileSizeLimit").value * 1024 * 1024); settings["confirm_torrent_recheck"] = document.getElementById("confirmTorrentRecheck").checked; - settings["recheck_completed_torrents"] = $("recheckTorrentsOnCompletion").checked; - settings["app_instance_name"] = $("appInstanceName").value; - settings["refresh_interval"] = Number($("refreshInterval").value); - settings["resolve_peer_countries"] = $("resolvePeerCountries").checked; - settings["reannounce_when_address_changed"] = $("reannounceWhenAddressChanged").checked; - settings["enable_embedded_tracker"] = $("enableEmbeddedTracker").checked; - settings["embedded_tracker_port"] = Number($("embeddedTrackerPort").value); - settings["embedded_tracker_port_forwarding"] = $("embeddedTrackerPortForwarding").checked; - settings["mark_of_the_web"] = $("markOfTheWeb").checked; - settings["ignore_ssl_errors"] = $("ignoreSSLErrors").checked; - settings["python_executable_path"] = $("pythonExecutablePath").value; + settings["recheck_completed_torrents"] = document.getElementById("recheckTorrentsOnCompletion").checked; + settings["app_instance_name"] = document.getElementById("appInstanceName").value; + settings["refresh_interval"] = Number(document.getElementById("refreshInterval").value); + settings["resolve_peer_countries"] = document.getElementById("resolvePeerCountries").checked; + settings["reannounce_when_address_changed"] = document.getElementById("reannounceWhenAddressChanged").checked; + settings["enable_embedded_tracker"] = document.getElementById("enableEmbeddedTracker").checked; + settings["embedded_tracker_port"] = Number(document.getElementById("embeddedTrackerPort").value); + settings["embedded_tracker_port_forwarding"] = document.getElementById("embeddedTrackerPortForwarding").checked; + settings["mark_of_the_web"] = document.getElementById("markOfTheWeb").checked; + settings["ignore_ssl_errors"] = document.getElementById("ignoreSSLErrors").checked; + settings["python_executable_path"] = document.getElementById("pythonExecutablePath").value; // libtorrent section - settings["bdecode_depth_limit"] = Number($("bdecodeDepthLimit").value); - settings["bdecode_token_limit"] = Number($("bdecodeTokenLimit").value); - settings["async_io_threads"] = Number($("asyncIOThreads").value); - settings["hashing_threads"] = Number($("hashingThreads").value); - settings["file_pool_size"] = Number($("filePoolSize").value); - settings["checking_memory_use"] = Number($("outstandMemoryWhenCheckingTorrents").value); - settings["disk_cache"] = Number($("diskCache").value); - settings["disk_cache_ttl"] = Number($("diskCacheExpiryInterval").value); - settings["disk_queue_size"] = (Number($("diskQueueSize").value) * 1024); - settings["disk_io_type"] = Number($("diskIOType").value); - settings["disk_io_read_mode"] = Number($("diskIOReadMode").value); - settings["disk_io_write_mode"] = Number($("diskIOWriteMode").value); - settings["enable_coalesce_read_write"] = $("coalesceReadsAndWrites").checked; - settings["enable_piece_extent_affinity"] = $("pieceExtentAffinity").checked; - settings["enable_upload_suggestions"] = $("sendUploadPieceSuggestions").checked; - settings["send_buffer_watermark"] = Number($("sendBufferWatermark").value); - settings["send_buffer_low_watermark"] = Number($("sendBufferLowWatermark").value); - settings["send_buffer_watermark_factor"] = Number($("sendBufferWatermarkFactor").value); - settings["connection_speed"] = Number($("connectionSpeed").value); - settings["socket_send_buffer_size"] = ($("socketSendBufferSize").value * 1024); - settings["socket_receive_buffer_size"] = ($("socketReceiveBufferSize").value * 1024); - settings["socket_backlog_size"] = Number($("socketBacklogSize").value); - settings["outgoing_ports_min"] = Number($("outgoingPortsMin").value); - settings["outgoing_ports_max"] = Number($("outgoingPortsMax").value); - settings["upnp_lease_duration"] = Number($("UPnPLeaseDuration").value); - settings["peer_tos"] = Number($("peerToS").value); - settings["utp_tcp_mixed_mode"] = Number($("utpTCPMixedModeAlgorithm").value); - settings["hostname_cache_ttl"] = Number($("hostnameCacheTTL").value); - settings["idn_support_enabled"] = $("IDNSupportCheckbox").checked; - settings["enable_multi_connections_from_same_ip"] = $("allowMultipleConnectionsFromTheSameIPAddress").checked; - settings["validate_https_tracker_certificate"] = $("validateHTTPSTrackerCertificate").checked; - settings["ssrf_mitigation"] = $("mitigateSSRF").checked; - settings["block_peers_on_privileged_ports"] = $("blockPeersOnPrivilegedPorts").checked; - settings["upload_slots_behavior"] = Number($("uploadSlotsBehavior").value); - settings["upload_choking_algorithm"] = Number($("uploadChokingAlgorithm").value); - settings["announce_to_all_trackers"] = $("announceAllTrackers").checked; - settings["announce_to_all_tiers"] = $("announceAllTiers").checked; - settings["announce_ip"] = $("announceIP").value; - const announcePort = Number($("announcePort").value); + settings["bdecode_depth_limit"] = Number(document.getElementById("bdecodeDepthLimit").value); + settings["bdecode_token_limit"] = Number(document.getElementById("bdecodeTokenLimit").value); + settings["async_io_threads"] = Number(document.getElementById("asyncIOThreads").value); + settings["hashing_threads"] = Number(document.getElementById("hashingThreads").value); + settings["file_pool_size"] = Number(document.getElementById("filePoolSize").value); + settings["checking_memory_use"] = Number(document.getElementById("outstandMemoryWhenCheckingTorrents").value); + settings["disk_cache"] = Number(document.getElementById("diskCache").value); + settings["disk_cache_ttl"] = Number(document.getElementById("diskCacheExpiryInterval").value); + settings["disk_queue_size"] = (Number(document.getElementById("diskQueueSize").value) * 1024); + settings["disk_io_type"] = Number(document.getElementById("diskIOType").value); + settings["disk_io_read_mode"] = Number(document.getElementById("diskIOReadMode").value); + settings["disk_io_write_mode"] = Number(document.getElementById("diskIOWriteMode").value); + settings["enable_coalesce_read_write"] = document.getElementById("coalesceReadsAndWrites").checked; + settings["enable_piece_extent_affinity"] = document.getElementById("pieceExtentAffinity").checked; + settings["enable_upload_suggestions"] = document.getElementById("sendUploadPieceSuggestions").checked; + settings["send_buffer_watermark"] = Number(document.getElementById("sendBufferWatermark").value); + settings["send_buffer_low_watermark"] = Number(document.getElementById("sendBufferLowWatermark").value); + settings["send_buffer_watermark_factor"] = Number(document.getElementById("sendBufferWatermarkFactor").value); + settings["connection_speed"] = Number(document.getElementById("connectionSpeed").value); + settings["socket_send_buffer_size"] = (document.getElementById("socketSendBufferSize").value * 1024); + settings["socket_receive_buffer_size"] = (document.getElementById("socketReceiveBufferSize").value * 1024); + settings["socket_backlog_size"] = Number(document.getElementById("socketBacklogSize").value); + settings["outgoing_ports_min"] = Number(document.getElementById("outgoingPortsMin").value); + settings["outgoing_ports_max"] = Number(document.getElementById("outgoingPortsMax").value); + settings["upnp_lease_duration"] = Number(document.getElementById("UPnPLeaseDuration").value); + settings["peer_tos"] = Number(document.getElementById("peerToS").value); + settings["utp_tcp_mixed_mode"] = Number(document.getElementById("utpTCPMixedModeAlgorithm").value); + settings["hostname_cache_ttl"] = Number(document.getElementById("hostnameCacheTTL").value); + settings["idn_support_enabled"] = document.getElementById("IDNSupportCheckbox").checked; + settings["enable_multi_connections_from_same_ip"] = document.getElementById("allowMultipleConnectionsFromTheSameIPAddress").checked; + settings["validate_https_tracker_certificate"] = document.getElementById("validateHTTPSTrackerCertificate").checked; + settings["ssrf_mitigation"] = document.getElementById("mitigateSSRF").checked; + settings["block_peers_on_privileged_ports"] = document.getElementById("blockPeersOnPrivilegedPorts").checked; + settings["upload_slots_behavior"] = Number(document.getElementById("uploadSlotsBehavior").value); + settings["upload_choking_algorithm"] = Number(document.getElementById("uploadChokingAlgorithm").value); + settings["announce_to_all_trackers"] = document.getElementById("announceAllTrackers").checked; + settings["announce_to_all_tiers"] = document.getElementById("announceAllTiers").checked; + settings["announce_ip"] = document.getElementById("announceIP").value; + const announcePort = Number(document.getElementById("announcePort").value); if (Number.isNaN(announcePort) || (announcePort < 0) || (announcePort > 65535)) { alert("QBT_TR(The announce port must be between 0 and 65535.)QBT_TR[CONTEXT=OptionsDialog]"); return; } settings["announce_port"] = announcePort; - settings["max_concurrent_http_announces"] = Number($("maxConcurrentHTTPAnnounces").value); - settings["stop_tracker_timeout"] = Number($("stopTrackerTimeout").value); - settings["peer_turnover"] = Number($("peerTurnover").value); - settings["peer_turnover_cutoff"] = Number($("peerTurnoverCutoff").value); - settings["peer_turnover_interval"] = Number($("peerTurnoverInterval").value); - settings["request_queue_size"] = Number($("requestQueueSize").value); - settings["dht_bootstrap_nodes"] = $("dhtBootstrapNodes").value; - settings["i2p_inbound_quantity"] = Number($("i2pInboundQuantity").value); - settings["i2p_outbound_quantity"] = Number($("i2pOutboundQuantity").value); - settings["i2p_inbound_length"] = Number($("i2pInboundLength").value); - settings["i2p_outbound_length"] = Number($("i2pOutboundLength").value); + settings["max_concurrent_http_announces"] = Number(document.getElementById("maxConcurrentHTTPAnnounces").value); + settings["stop_tracker_timeout"] = Number(document.getElementById("stopTrackerTimeout").value); + settings["peer_turnover"] = Number(document.getElementById("peerTurnover").value); + settings["peer_turnover_cutoff"] = Number(document.getElementById("peerTurnoverCutoff").value); + settings["peer_turnover_interval"] = Number(document.getElementById("peerTurnoverInterval").value); + settings["request_queue_size"] = Number(document.getElementById("requestQueueSize").value); + settings["dht_bootstrap_nodes"] = document.getElementById("dhtBootstrapNodes").value; + settings["i2p_inbound_quantity"] = Number(document.getElementById("i2pInboundQuantity").value); + settings["i2p_outbound_quantity"] = Number(document.getElementById("i2pOutboundQuantity").value); + settings["i2p_inbound_length"] = Number(document.getElementById("i2pInboundLength").value); + settings["i2p_outbound_length"] = Number(document.getElementById("i2pOutboundLength").value); // Send it to qBT window.parent.qBittorrent.Cache.preferences.set({ @@ -3137,7 +3137,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD }; const setup = () => { - watchedFoldersTable = new HtmlTable($("watched_folders_tab")); + watchedFoldersTable = new HtmlTable(document.getElementById("watched_folders_tab")); const buildInfo = window.qBittorrent.Cache.buildInfo.get(); @@ -3145,29 +3145,29 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD const libtorrentVersion = window.qBittorrent.Misc.parseVersion(buildInfo.libtorrent); if (libtorrentVersion.valid) { if (libtorrentVersion.major >= 2) { - $("rowDiskCache").style.display = "none"; - $("rowDiskCacheExpiryInterval").style.display = "none"; - $("rowCoalesceReadsAndWrites").style.display = "none"; + document.getElementById("rowDiskCache").style.display = "none"; + document.getElementById("rowDiskCacheExpiryInterval").style.display = "none"; + document.getElementById("rowCoalesceReadsAndWrites").style.display = "none"; } else { - $("fieldsetI2p").style.display = "none"; - $("rowMemoryWorkingSetLimit").style.display = "none"; - $("rowHashingThreads").style.display = "none"; - $("rowDiskIOType").style.display = "none"; - $("rowI2pInboundQuantity").style.display = "none"; - $("rowI2pOutboundQuantity").style.display = "none"; - $("rowI2pInboundLength").style.display = "none"; - $("rowI2pOutboundLength").style.display = "none"; + document.getElementById("fieldsetI2p").style.display = "none"; + document.getElementById("rowMemoryWorkingSetLimit").style.display = "none"; + document.getElementById("rowHashingThreads").style.display = "none"; + document.getElementById("rowDiskIOType").style.display = "none"; + document.getElementById("rowI2pInboundQuantity").style.display = "none"; + document.getElementById("rowI2pOutboundQuantity").style.display = "none"; + document.getElementById("rowI2pInboundLength").style.display = "none"; + document.getElementById("rowI2pOutboundLength").style.display = "none"; } if (!((libtorrentVersion.major >= 2) && (libtorrentVersion.minor >= 0) && (libtorrentVersion.fix >= 6))) - $("diskIOWriteModeWriteThrough").style.display = "none"; + document.getElementById("diskIOWriteModeWriteThrough").style.display = "none"; } if ((buildInfo.platform !== "macos") && (buildInfo.platform !== "windows")) - $("rowMarkOfTheWeb").style.display = "none"; + document.getElementById("rowMarkOfTheWeb").style.display = "none"; - $("networkInterface").addEventListener("change", function() { + document.getElementById("networkInterface").addEventListener("change", function() { updateInterfaceAddresses(this.value, ""); }); diff --git a/src/webui/www/private/views/preferencesToolbar.html b/src/webui/www/private/views/preferencesToolbar.html index c2ff79993..20eb487aa 100644 --- a/src/webui/www/private/views/preferencesToolbar.html +++ b/src/webui/www/private/views/preferencesToolbar.html @@ -36,37 +36,37 @@ // Tabs MochaUI.initializeTabs("preferencesTabs"); - $("PrefBehaviorLink").addEventListener("click", (e) => { + document.getElementById("PrefBehaviorLink").addEventListener("click", (e) => { Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible"))); - $("BehaviorTab").classList.remove("invisible"); + document.getElementById("BehaviorTab").classList.remove("invisible"); }); - $("PrefDownloadsLink").addEventListener("click", (e) => { + document.getElementById("PrefDownloadsLink").addEventListener("click", (e) => { Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible"))); - $("DownloadsTab").classList.remove("invisible"); + document.getElementById("DownloadsTab").classList.remove("invisible"); }); - $("PrefConnectionLink").addEventListener("click", (e) => { + document.getElementById("PrefConnectionLink").addEventListener("click", (e) => { Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible"))); - $("ConnectionTab").classList.remove("invisible"); + document.getElementById("ConnectionTab").classList.remove("invisible"); }); - $("PrefSpeedLink").addEventListener("click", (e) => { + document.getElementById("PrefSpeedLink").addEventListener("click", (e) => { Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible"))); - $("SpeedTab").classList.remove("invisible"); + document.getElementById("SpeedTab").classList.remove("invisible"); }); - $("PrefBittorrentLink").addEventListener("click", (e) => { + document.getElementById("PrefBittorrentLink").addEventListener("click", (e) => { Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible"))); - $("BittorrentTab").classList.remove("invisible"); + document.getElementById("BittorrentTab").classList.remove("invisible"); }); - $("PrefRSSLink").addEventListener("click", (e) => { + document.getElementById("PrefRSSLink").addEventListener("click", (e) => { Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible"))); - $("RSSTab").classList.remove("invisible"); + document.getElementById("RSSTab").classList.remove("invisible"); }); - $("PrefWebUILink").addEventListener("click", (e) => { + document.getElementById("PrefWebUILink").addEventListener("click", (e) => { Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible"))); - $("WebUITab").classList.remove("invisible"); + document.getElementById("WebUITab").classList.remove("invisible"); }); - $("PrefAdvancedLink").addEventListener("click", (e) => { + document.getElementById("PrefAdvancedLink").addEventListener("click", (e) => { Array.prototype.forEach.call(document.querySelectorAll(".PrefTab"), (tab => tab.classList.add("invisible"))); - $("AdvancedTab").classList.remove("invisible"); + document.getElementById("AdvancedTab").classList.remove("invisible"); }); })(); diff --git a/src/webui/www/private/views/rss.html b/src/webui/www/private/views/rss.html index 7088f6f8f..76c0fdbdd 100644 --- a/src/webui/www/private/views/rss.html +++ b/src/webui/www/private/views/rss.html @@ -218,7 +218,7 @@ const pref = window.parent.qBittorrent.Cache.preferences.get(); if (!pref.rss_processing_enabled) - $("rssFetchingDisabled").classList.remove("invisible"); + document.getElementById("rssFetchingDisabled").classList.remove("invisible"); const rssFeedContextMenu = new window.qBittorrent.ContextMenu.RssFeedContextMenu({ targets: "#rssFeedTableDiv tbody tr", @@ -263,13 +263,13 @@ } }); - rssFeedContextMenu.addTarget($("rssFeedTableDiv")); + rssFeedContextMenu.addTarget(document.getElementById("rssFeedTableDiv")); // deselect feed when clicking on empty part of table - $("rssFeedTableDiv").addEventListener("click", (e) => { + document.getElementById("rssFeedTableDiv").addEventListener("click", (e) => { rssFeedTable.deselectAll(); rssFeedTable.deselectRow(); }); - $("rssFeedTableDiv").addEventListener("contextmenu", (e) => { + document.getElementById("rssFeedTableDiv").addEventListener("contextmenu", (e) => { if (e.target.nodeName === "DIV") { rssFeedTable.deselectAll(); rssFeedTable.deselectRow(); diff --git a/src/webui/www/private/views/rssDownloader.html b/src/webui/www/private/views/rssDownloader.html index 4a0b8d6ce..8da31614e 100644 --- a/src/webui/www/private/views/rssDownloader.html +++ b/src/webui/www/private/views/rssDownloader.html @@ -370,30 +370,30 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also const pref = window.parent.qBittorrent.Cache.preferences.get(); if (!pref.rss_auto_downloading_enabled) - $("rssDownloaderDisabled").classList.remove("invisible"); + document.getElementById("rssDownloaderDisabled").classList.remove("invisible"); // recalculate height - const warningHeight = $("rssDownloaderDisabled").getBoundingClientRect().height; + const warningHeight = document.getElementById("rssDownloaderDisabled").getBoundingClientRect().height; - $("leftRssDownloaderColumn").style.height = `calc(100% - ${warningHeight}px)`; - $("centerRssDownloaderColumn").style.height = `calc(100% - ${warningHeight}px)`; - $("rightRssDownloaderColumn").style.height = `calc(100% - ${warningHeight}px)`; + document.getElementById("leftRssDownloaderColumn").style.height = `calc(100% - ${warningHeight}px)`; + document.getElementById("centerRssDownloaderColumn").style.height = `calc(100% - ${warningHeight}px)`; + document.getElementById("rightRssDownloaderColumn").style.height = `calc(100% - ${warningHeight}px)`; - $("rulesTable").style.height = `calc(100% - ${$("rulesTableDesc").getBoundingClientRect().height}px)`; - $("rssDownloaderArticlesTable").style.height = `calc(100% - ${$("articleTableDesc").getBoundingClientRect().height}px)`; + document.getElementById("rulesTable").style.height = `calc(100% - ${document.getElementById("rulesTableDesc").getBoundingClientRect().height}px)`; + document.getElementById("rssDownloaderArticlesTable").style.height = `calc(100% - ${document.getElementById("articleTableDesc").getBoundingClientRect().height}px)`; - const centerRowNotTableHeight = $("saveButton").getBoundingClientRect().height - + $("ruleSettings").getBoundingClientRect().height + 15; + const centerRowNotTableHeight = document.getElementById("saveButton").getBoundingClientRect().height + + document.getElementById("ruleSettings").getBoundingClientRect().height + 15; - $("rssDownloaderFeeds").style.height = `calc(100% - ${centerRowNotTableHeight}px)`; + document.getElementById("rssDownloaderFeeds").style.height = `calc(100% - ${centerRowNotTableHeight}px)`; // firefox calculates the height of the table inside fieldset differently and thus doesn't need the offset if (navigator.userAgent.toLowerCase().includes("firefox")) { - $("rssDownloaderFeedsTable").style.height = "100%"; + document.getElementById("rssDownloaderFeedsTable").style.height = "100%"; } else { - const outsideTableHeight = ($("rssDownloaderFeedsTable").getBoundingClientRect().top - $("rssDownloaderFeeds").getBoundingClientRect().top) - 10; - $("rssDownloaderFeedsTable").style.height = `calc(100% - ${outsideTableHeight}px)`; + const outsideTableHeight = (document.getElementById("rssDownloaderFeedsTable").getBoundingClientRect().top - document.getElementById("rssDownloaderFeeds").getBoundingClientRect().top) - 10; + document.getElementById("rssDownloaderFeedsTable").style.height = `calc(100% - ${outsideTableHeight}px)`; } const rssDownloaderRuleContextMenu = new window.qBittorrent.ContextMenu.RssDownloaderRuleContextMenu({ @@ -419,9 +419,9 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also rssDownloaderFeedSelectionTable.setup("rssDownloaderFeedSelectionTableDiv", "rssDownloaderFeedSelectionFixedHeaderDiv"); rssDownloaderArticlesTable.setup("rssDownloaderArticlesTableDiv", "rssDownloaderArticlesFixedHeaderDiv"); - rssDownloaderRuleContextMenu.addTarget($("rulesTable")); + rssDownloaderRuleContextMenu.addTarget(document.getElementById("rulesTable")); // deselect feed when clicking on empty part of table - $("rulesTable").addEventListener("click", (e) => { + document.getElementById("rulesTable").addEventListener("click", (e) => { if (e.target.nodeName === "DIV") { rssDownloaderRulesTable.deselectAll(); rssDownloaderRulesTable.deselectRow(); @@ -439,7 +439,7 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also const responseJSON = await response.json(); - const combobox = $("assignCategoryCombobox"); + const combobox = document.getElementById("assignCategoryCombobox"); for (const cat in responseJSON) { if (!Object.hasOwn(responseJSON, cat)) continue; @@ -475,8 +475,8 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also }; flatten(responseJSON); }); - $("savetoDifferentDir").addEventListener("click", () => { - $("saveToText").disabled = !$("savetoDifferentDir").checked; + document.getElementById("savetoDifferentDir").addEventListener("click", () => { + document.getElementById("saveToText").disabled = !document.getElementById("savetoDifferentDir").checked; }); updateRulesList(); }; @@ -599,27 +599,27 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also const lastSelectedRow = rssDownloaderRulesTable.selectedRows.at(-1); const rule = rssDownloaderRulesTable.getRow(lastSelectedRow).full_data.name; - rulesList[rule].useRegex = $("useRegEx").checked; - rulesList[rule].mustContain = $("mustContainText").value; - rulesList[rule].mustNotContain = $("mustNotContainText").value; - rulesList[rule].episodeFilter = $("episodeFilterText").value; - rulesList[rule].smartFilter = $("useSmartFilter").checked; - rulesList[rule].ignoreDays = Number($("ignoreDaysValue").value); + rulesList[rule].useRegex = document.getElementById("useRegEx").checked; + rulesList[rule].mustContain = document.getElementById("mustContainText").value; + rulesList[rule].mustNotContain = document.getElementById("mustNotContainText").value; + rulesList[rule].episodeFilter = document.getElementById("episodeFilterText").value; + rulesList[rule].smartFilter = document.getElementById("useSmartFilter").checked; + rulesList[rule].ignoreDays = Number(document.getElementById("ignoreDaysValue").value); rulesList[rule].affectedFeeds = [...rssDownloaderFeedSelectionTable.getRowValues()] .filter((row) => row.full_data.checked) .map((row) => row.full_data.url); - rulesList[rule].torrentParams.category = $("assignCategoryCombobox").value; - rulesList[rule].torrentParams.tags = $("ruleAddTags").value.split(","); - if ($("savetoDifferentDir").checked) { - rulesList[rule].torrentParams.save_path = $("saveToText").value; + rulesList[rule].torrentParams.category = document.getElementById("assignCategoryCombobox").value; + rulesList[rule].torrentParams.tags = document.getElementById("ruleAddTags").value.split(","); + if (document.getElementById("savetoDifferentDir").checked) { + rulesList[rule].torrentParams.save_path = document.getElementById("saveToText").value; rulesList[rule].torrentParams.use_auto_tmm = false; } else { rulesList[rule].torrentParams.save_path = ""; } - switch ($("addStoppedCombobox").value) { + switch (document.getElementById("addStoppedCombobox").value) { case "default": rulesList[rule].torrentParams.stopped = null; break; @@ -631,7 +631,7 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also break; } - switch ($("contentLayoutCombobox").value) { + switch (document.getElementById("contentLayoutCombobox").value) { case "Default": rulesList[rule].torrentParams.content_layout = null; break; @@ -701,89 +701,89 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also const showRule = (ruleName) => { if (ruleName === "") { // disable all - $("saveButton").disabled = true; - $("useRegEx").disabled = true; - $("mustContainText").disabled = true; - $("mustNotContainText").disabled = true; - $("episodeFilterText").disabled = true; - $("useSmartFilter").disabled = true; - $("assignCategoryCombobox").disabled = true; - $("ruleAddTags").disabled = true; - $("savetoDifferentDir").disabled = true; - $("saveToText").disabled = true; - $("ignoreDaysValue").disabled = true; - $("addStoppedCombobox").disabled = true; - $("contentLayoutCombobox").disabled = true; + document.getElementById("saveButton").disabled = true; + document.getElementById("useRegEx").disabled = true; + document.getElementById("mustContainText").disabled = true; + document.getElementById("mustNotContainText").disabled = true; + document.getElementById("episodeFilterText").disabled = true; + document.getElementById("useSmartFilter").disabled = true; + document.getElementById("assignCategoryCombobox").disabled = true; + document.getElementById("ruleAddTags").disabled = true; + document.getElementById("savetoDifferentDir").disabled = true; + document.getElementById("saveToText").disabled = true; + document.getElementById("ignoreDaysValue").disabled = true; + document.getElementById("addStoppedCombobox").disabled = true; + document.getElementById("contentLayoutCombobox").disabled = true; // reset all boxes - $("useRegEx").checked = false; - $("mustContainText").value = ""; - $("mustNotContainText").value = ""; - $("episodeFilterText").value = ""; - $("useSmartFilter").checked = false; - $("assignCategoryCombobox").value = "default"; - $("ruleAddTags").value = ""; - $("savetoDifferentDir").checked = false; - $("saveToText").value = ""; - $("ignoreDaysValue").value = 0; - $("lastMatchText").textContent = "QBT_TR(Last Match: Unknown)QBT_TR[CONTEXT=AutomatedRssDownloader]"; - $("addStoppedCombobox").value = "default"; - $("contentLayoutCombobox").value = "Default"; + document.getElementById("useRegEx").checked = false; + document.getElementById("mustContainText").value = ""; + document.getElementById("mustNotContainText").value = ""; + document.getElementById("episodeFilterText").value = ""; + document.getElementById("useSmartFilter").checked = false; + document.getElementById("assignCategoryCombobox").value = "default"; + document.getElementById("ruleAddTags").value = ""; + document.getElementById("savetoDifferentDir").checked = false; + document.getElementById("saveToText").value = ""; + document.getElementById("ignoreDaysValue").value = 0; + document.getElementById("lastMatchText").textContent = "QBT_TR(Last Match: Unknown)QBT_TR[CONTEXT=AutomatedRssDownloader]"; + document.getElementById("addStoppedCombobox").value = "default"; + document.getElementById("contentLayoutCombobox").value = "Default"; rssDownloaderFeedSelectionTable.clear(); rssDownloaderArticlesTable.clear(); - $("mustContainText").title = ""; - $("mustNotContainText").title = ""; - $("episodeFilterText").title = ""; + document.getElementById("mustContainText").title = ""; + document.getElementById("mustNotContainText").title = ""; + document.getElementById("episodeFilterText").title = ""; } else { // enable all - $("saveButton").disabled = false; - $("useRegEx").disabled = false; - $("mustContainText").disabled = false; - $("mustNotContainText").disabled = false; - $("episodeFilterText").disabled = false; - $("useSmartFilter").disabled = false; - $("assignCategoryCombobox").disabled = false; - $("ruleAddTags").disabled = false; - $("savetoDifferentDir").disabled = false; - $("ignoreDaysValue").disabled = false; - $("addStoppedCombobox").disabled = false; - $("contentLayoutCombobox").disabled = false; + document.getElementById("saveButton").disabled = false; + document.getElementById("useRegEx").disabled = false; + document.getElementById("mustContainText").disabled = false; + document.getElementById("mustNotContainText").disabled = false; + document.getElementById("episodeFilterText").disabled = false; + document.getElementById("useSmartFilter").disabled = false; + document.getElementById("assignCategoryCombobox").disabled = false; + document.getElementById("ruleAddTags").disabled = false; + document.getElementById("savetoDifferentDir").disabled = false; + document.getElementById("ignoreDaysValue").disabled = false; + document.getElementById("addStoppedCombobox").disabled = false; + document.getElementById("contentLayoutCombobox").disabled = false; // load rule settings - $("useRegEx").checked = rulesList[ruleName].useRegex; - $("mustContainText").value = rulesList[ruleName].mustContain; - $("mustNotContainText").value = rulesList[ruleName].mustNotContain; - $("episodeFilterText").value = rulesList[ruleName].episodeFilter; - $("useSmartFilter").checked = rulesList[ruleName].smartFilter; + document.getElementById("useRegEx").checked = rulesList[ruleName].useRegex; + document.getElementById("mustContainText").value = rulesList[ruleName].mustContain; + document.getElementById("mustNotContainText").value = rulesList[ruleName].mustNotContain; + document.getElementById("episodeFilterText").value = rulesList[ruleName].episodeFilter; + document.getElementById("useSmartFilter").checked = rulesList[ruleName].smartFilter; - $("assignCategoryCombobox").value = rulesList[ruleName].torrentParams.category ? rulesList[ruleName].torrentParams.category : "default"; - $("ruleAddTags").value = rulesList[ruleName].torrentParams.tags.join(","); - $("savetoDifferentDir").checked = rulesList[ruleName].torrentParams.save_path !== ""; - $("saveToText").disabled = !$("savetoDifferentDir").checked; - $("saveToText").value = rulesList[ruleName].torrentParams.save_path; - $("ignoreDaysValue").value = rulesList[ruleName].ignoreDays; + document.getElementById("assignCategoryCombobox").value = rulesList[ruleName].torrentParams.category ? rulesList[ruleName].torrentParams.category : "default"; + document.getElementById("ruleAddTags").value = rulesList[ruleName].torrentParams.tags.join(","); + document.getElementById("savetoDifferentDir").checked = rulesList[ruleName].torrentParams.save_path !== ""; + document.getElementById("saveToText").disabled = !document.getElementById("savetoDifferentDir").checked; + document.getElementById("saveToText").value = rulesList[ruleName].torrentParams.save_path; + document.getElementById("ignoreDaysValue").value = rulesList[ruleName].ignoreDays; // calculate days since last match if (rulesList[ruleName].lastMatch !== "") { const timeDiffInMs = new Date().getTime() - new Date(rulesList[ruleName].lastMatch).getTime(); const daysAgo = Math.floor(timeDiffInMs / (1000 * 60 * 60 * 24)).toString(); - $("lastMatchText").textContent = " QBT_TR(Last Match: %1 days ago)QBT_TR[CONTEXT=AutomatedRssDownloader]".replace("%1", daysAgo); + document.getElementById("lastMatchText").textContent = " QBT_TR(Last Match: %1 days ago)QBT_TR[CONTEXT=AutomatedRssDownloader]".replace("%1", daysAgo); } else { - $("lastMatchText").textContent = "QBT_TR(Last Match: Unknown)QBT_TR[CONTEXT=AutomatedRssDownloader]"; + document.getElementById("lastMatchText").textContent = "QBT_TR(Last Match: Unknown)QBT_TR[CONTEXT=AutomatedRssDownloader]"; } if ((rulesList[ruleName].torrentParams.stopped === undefined) || (rulesList[ruleName].torrentParams.stopped === null)) - $("addStoppedCombobox").value = "default"; + document.getElementById("addStoppedCombobox").value = "default"; else - $("addStoppedCombobox").value = rulesList[ruleName].torrentParams.stopped ? "always" : "never"; + document.getElementById("addStoppedCombobox").value = rulesList[ruleName].torrentParams.stopped ? "always" : "never"; if ((rulesList[ruleName].torrentParams.content_layout === undefined) || (rulesList[ruleName].torrentParams.content_layout === null)) - $("contentLayoutCombobox").value = "Default"; + document.getElementById("contentLayoutCombobox").value = "Default"; else - $("contentLayoutCombobox").value = rulesList[ruleName].torrentParams.content_layout; + document.getElementById("contentLayoutCombobox").value = rulesList[ruleName].torrentParams.content_layout; setElementTitles(); @@ -804,7 +804,7 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also const setElementTitles = () => { let mainPart; - if ($("useRegEx").checked) { + if (document.getElementById("useRegEx").checked) { mainPart = "QBT_TR(Regex mode: use Perl-compatible regular expressions)QBT_TR[CONTEXT=AutomatedRssDownloader]\n\n"; } else { @@ -818,8 +818,8 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also const secondPart = "QBT_TR(An expression with an empty %1 clause (e.g. %2))QBT_TR[CONTEXT=AutomatedRssDownloader]" .replace("%1", "|").replace("%2", "expr|"); - $("mustContainText").title = `${mainPart}${secondPart}QBT_TR( will match all articles.)QBT_TR[CONTEXT=AutomatedRssDownloader]`; - $("mustNotContainText").title = `${mainPart}${secondPart}QBT_TR( will exclude all articles.)QBT_TR[CONTEXT=AutomatedRssDownloader]`; + document.getElementById("mustContainText").title = `${mainPart}${secondPart}QBT_TR( will match all articles.)QBT_TR[CONTEXT=AutomatedRssDownloader]`; + document.getElementById("mustNotContainText").title = `${mainPart}${secondPart}QBT_TR( will exclude all articles.)QBT_TR[CONTEXT=AutomatedRssDownloader]`; let episodeFilterTitle = "QBT_TR(Matches articles based on episode filter.)QBT_TR[CONTEXT=AutomatedRssDownloader]\n\n" + "QBT_TR(Example: )QBT_TR[CONTEXT=AutomatedRssDownloader]" @@ -835,7 +835,7 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also + " ● QBT_TR(Infinite range: 1x25-; matches episodes 25 and upward of season one, and all episodes of later seasons)QBT_TR[CONTEXT=AutomatedRssDownloader]"; episodeFilterTitle = episodeFilterTitle.replace(//g, "").replace(/<\/b>/g, ""); - $("episodeFilterText").title = episodeFilterTitle; + document.getElementById("episodeFilterText").title = episodeFilterTitle; }; return exports(); From 70dbe9468aba9162df139232480777c4d929269c Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Thu, 17 Apr 2025 18:48:12 +0800 Subject: [PATCH 03/45] WebUI: disallow unnecessary semicolons --- src/webui/www/eslint.config.mjs | 1 + src/webui/www/private/scripts/client.js | 2 +- src/webui/www/private/scripts/contextmenu.js | 22 +++++++++---------- src/webui/www/private/scripts/dynamicTable.js | 2 +- .../www/private/scripts/localpreferences.js | 2 +- src/webui/www/private/scripts/pathAutofill.js | 2 +- src/webui/www/private/scripts/search.js | 2 +- src/webui/www/private/views/preferences.html | 2 +- src/webui/www/private/views/rss.html | 2 +- 9 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/webui/www/eslint.config.mjs b/src/webui/www/eslint.config.mjs index 6aafb8d64..24de0c776 100644 --- a/src/webui/www/eslint.config.mjs +++ b/src/webui/www/eslint.config.mjs @@ -40,6 +40,7 @@ export default [ "prefer-template": "error", "radix": "error", "PreferArrowFunctions/prefer-arrow-functions": "error", + "Stylistic/no-extra-semi": "error", "Stylistic/no-mixed-operators": [ "error", { diff --git a/src/webui/www/private/scripts/client.js b/src/webui/www/private/scripts/client.js index 15e7af365..0abc9c924 100644 --- a/src/webui/www/private/scripts/client.js +++ b/src/webui/www/private/scripts/client.js @@ -1818,5 +1818,5 @@ window.addEventListener("load", async () => { console.error(`Unexpected 'selected_window_tab' value: ${previouslyUsedTab}`); $("transfersTabLink").click(); break; - }; + } }); diff --git a/src/webui/www/private/scripts/contextmenu.js b/src/webui/www/private/scripts/contextmenu.js index 7831461bf..4a389d424 100644 --- a/src/webui/www/private/scripts/contextmenu.js +++ b/src/webui/www/private/scripts/contextmenu.js @@ -292,7 +292,7 @@ window.qBittorrent.ContextMenu ??= (() => { this.options.actions[action](element, this, action); return this; } - }; + } class FilterListContextMenu extends ContextMenu { constructor(options) { @@ -316,7 +316,7 @@ window.qBittorrent.ContextMenu ??= (() => { .setEnabled("stopTorrents", torrentsVisible) .setEnabled("deleteTorrents", torrentsVisible); } - }; + } class TorrentsTableContextMenu extends ContextMenu { updateMenuItems() { @@ -577,13 +577,13 @@ window.qBittorrent.ContextMenu ??= (() => { contextTagList.appendChild(setTagItem); } } - }; + } class StatusesFilterContextMenu extends FilterListContextMenu { updateMenuItems() { this.updateTorrentActions(); } - }; + } class CategoriesFilterContextMenu extends FilterListContextMenu { updateMenuItems() { @@ -604,7 +604,7 @@ window.qBittorrent.ContextMenu ??= (() => { this.updateTorrentActions(); } - }; + } class TagsFilterContextMenu extends FilterListContextMenu { updateMenuItems() { @@ -616,7 +616,7 @@ window.qBittorrent.ContextMenu ??= (() => { this.updateTorrentActions(); } - }; + } class TrackersFilterContextMenu extends FilterListContextMenu { updateMenuItems() { @@ -628,7 +628,7 @@ window.qBittorrent.ContextMenu ??= (() => { this.updateTorrentActions(); } - }; + } class SearchPluginsTableContextMenu extends ContextMenu { updateMenuItems() { @@ -642,7 +642,7 @@ window.qBittorrent.ContextMenu ??= (() => { this.showItem("Uninstall"); } - }; + } class RssFeedContextMenu extends ContextMenu { updateMenuItems() { @@ -715,9 +715,9 @@ window.qBittorrent.ContextMenu ??= (() => { break; } } - }; + } - class RssArticleContextMenu extends ContextMenu {}; + class RssArticleContextMenu extends ContextMenu {} class RssDownloaderRuleContextMenu extends ContextMenu { adjustMenuPosition(e) { @@ -765,7 +765,7 @@ window.qBittorrent.ContextMenu ??= (() => { break; } } - }; + } return exports(); })(); diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index d05cd8c53..cd0147067 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -3128,7 +3128,7 @@ window.qBittorrent.DynamicTable ??= (() => { img.height = "22"; td.append(img); } - }; + } }, newColumn: function(name, style, caption, defaultWidth, defaultVisible) { const column = {}; diff --git a/src/webui/www/private/scripts/localpreferences.js b/src/webui/www/private/scripts/localpreferences.js index deb0c159f..73f341127 100644 --- a/src/webui/www/private/scripts/localpreferences.js +++ b/src/webui/www/private/scripts/localpreferences.js @@ -61,7 +61,7 @@ window.qBittorrent.LocalPreferences ??= (() => { console.error(err); } } - }; + } return exports(); })(); diff --git a/src/webui/www/private/scripts/pathAutofill.js b/src/webui/www/private/scripts/pathAutofill.js index 2e260f145..3568b8f71 100644 --- a/src/webui/www/private/scripts/pathAutofill.js +++ b/src/webui/www/private/scripts/pathAutofill.js @@ -85,7 +85,7 @@ window.qBittorrent.pathAutofill ??= (() => { input.addEventListener("input", function() { showPathSuggestions(this, "all"); }); input.classList.add("pathAutoFillInitialized"); } - }; + } return exports(); })(); diff --git a/src/webui/www/private/scripts/search.js b/src/webui/www/private/scripts/search.js index 3dc0b454b..47f9ad3a2 100644 --- a/src/webui/www/private/scripts/search.js +++ b/src/webui/www/private/scripts/search.js @@ -603,7 +603,7 @@ window.qBittorrent.Search ??= (() => { option.value = category.id; option.textContent = category.name; categoryOptions.push(option); - }; + } // first category is "All Categories" if (categoryOptions.length > 1) { diff --git a/src/webui/www/private/views/preferences.html b/src/webui/www/private/views/preferences.html index 07109e68e..b392e263d 100644 --- a/src/webui/www/private/views/preferences.html +++ b/src/webui/www/private/views/preferences.html @@ -1891,7 +1891,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD case "other": other = $(`cb_watch_txt_${i}`).value.trim(); break; - }; + } folders[fpath] = other; } diff --git a/src/webui/www/private/views/rss.html b/src/webui/www/private/views/rss.html index 7088f6f8f..7db062c83 100644 --- a/src/webui/www/private/views/rss.html +++ b/src/webui/www/private/views/rss.html @@ -232,7 +232,7 @@ if ((row.full_data.dataPath.slice(0, selectedPath.length) === selectedPath) && (row.full_data.dataUid !== "")) feedsToUpdate.add(row); } - }; + } feedsToUpdate.forEach((feed) => refreshFeed(feed.full_data.dataUid)); }, markRead: markSelectedAsRead, From 1077cbba2b7d9a04c1d447aba35c94af463a26a4 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Thu, 17 Apr 2025 19:29:26 +0800 Subject: [PATCH 04/45] WebUI: ensure consistent shorthand syntax --- src/webui/www/eslint.config.mjs | 1 + src/webui/www/private/scripts/rename-files.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/webui/www/eslint.config.mjs b/src/webui/www/eslint.config.mjs index 24de0c776..58ff348bf 100644 --- a/src/webui/www/eslint.config.mjs +++ b/src/webui/www/eslint.config.mjs @@ -34,6 +34,7 @@ export default [ "no-undef": "off", "no-unused-vars": "off", "no-var": "error", + "object-shorthand": ["error", "consistent"], "operator-assignment": "error", "prefer-arrow-callback": "error", "prefer-const": "error", diff --git a/src/webui/www/private/scripts/rename-files.js b/src/webui/www/private/scripts/rename-files.js index 5087f793e..a320c83df 100644 --- a/src/webui/www/private/scripts/rename-files.js +++ b/src/webui/www/private/scripts/rename-files.js @@ -22,7 +22,7 @@ window.qBittorrent.MultiRename ??= (() => { // Search Options _inner_search: "", - setSearch(val) { + setSearch: function(val) { this._inner_search = val; this._inner_update(); this.onChanged(this.matchedFiles); @@ -33,7 +33,7 @@ window.qBittorrent.MultiRename ??= (() => { // Replacement Options _inner_replacement: "", - setReplacement(val) { + setReplacement: function(val) { this._inner_replacement = val; this._inner_update(); this.onChanged(this.matchedFiles); From e9fee414df8171cf9885275b19e77cba193dc1b9 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Thu, 17 Apr 2025 19:37:03 +0800 Subject: [PATCH 05/45] WebUI: disallow async functions which have no await expression --- src/webui/www/eslint.config.mjs | 1 + src/webui/www/private/downloadlimit.html | 4 ++-- src/webui/www/private/newtag.html | 4 ++-- src/webui/www/private/scripts/cache.js | 6 +++--- src/webui/www/private/shareratio.html | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/webui/www/eslint.config.mjs b/src/webui/www/eslint.config.mjs index 58ff348bf..ed4f3ab22 100644 --- a/src/webui/www/eslint.config.mjs +++ b/src/webui/www/eslint.config.mjs @@ -40,6 +40,7 @@ export default [ "prefer-const": "error", "prefer-template": "error", "radix": "error", + "require-await": "error", "PreferArrowFunctions/prefer-arrow-functions": "error", "Stylistic/no-extra-semi": "error", "Stylistic/no-mixed-operators": [ diff --git a/src/webui/www/private/downloadlimit.html b/src/webui/www/private/downloadlimit.html index d703cf79e..8f2f9da89 100644 --- a/src/webui/www/private/downloadlimit.html +++ b/src/webui/www/private/downloadlimit.html @@ -56,7 +56,7 @@ limit: limit }) }) - .then(async (response) => { + .then((response) => { if (!response.ok) return; @@ -72,7 +72,7 @@ limit: limit }) }) - .then(async (response) => { + .then((response) => { if (!response.ok) return; diff --git a/src/webui/www/private/newtag.html b/src/webui/www/private/newtag.html index a8067fecc..8287c5ef3 100644 --- a/src/webui/www/private/newtag.html +++ b/src/webui/www/private/newtag.html @@ -64,7 +64,7 @@ tags: tagName }) }) - .then(async (response) => { + .then((response) => { if (!response.ok) return; @@ -83,7 +83,7 @@ tags: tagName }) }) - .then(async (response) => { + .then((response) => { if (!response.ok) return; diff --git a/src/webui/www/private/scripts/cache.js b/src/webui/www/private/scripts/cache.js index 3b93c8757..999a5db2d 100644 --- a/src/webui/www/private/scripts/cache.js +++ b/src/webui/www/private/scripts/cache.js @@ -53,7 +53,7 @@ window.qBittorrent.Cache ??= (() => { class BuildInfoCache { #m_store = {}; - async init() { + init() { return fetch("api/v2/app/buildInfo", { method: "GET", cache: "no-store" @@ -80,7 +80,7 @@ window.qBittorrent.Cache ??= (() => { // onFailure: () => {}, // onSuccess: () => {} // } - async init(obj = {}) { + init(obj = {}) { return fetch("api/v2/app/preferences", { method: "GET", cache: "no-store" @@ -153,7 +153,7 @@ window.qBittorrent.Cache ??= (() => { class QbtVersionCache { #m_store = ""; - async init() { + init() { return fetch("api/v2/app/version", { method: "GET", cache: "no-store" diff --git a/src/webui/www/private/shareratio.html b/src/webui/www/private/shareratio.html index b106e72b8..726fbed29 100644 --- a/src/webui/www/private/shareratio.html +++ b/src/webui/www/private/shareratio.html @@ -108,7 +108,7 @@ inactiveSeedingTimeLimit: inactiveSeedingTimeLimitValue }) }) - .then(async (response) => { + .then((response) => { if (!response.ok) return; From fdd17159eb5cd18634ae5b62d3448635fdba382f Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Sun, 20 Apr 2025 17:46:12 +0800 Subject: [PATCH 06/45] WebUI: remove unused variable --- src/webui/www/private/scripts/dynamicTable.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index cd0147067..bf019e1d2 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -2858,7 +2858,6 @@ window.qBittorrent.DynamicTable ??= (() => { // progress this.columns["progress"].updateTd = function(td, row) { - const id = row.rowId; const value = Number(this.getRowValue(row)); const progressBar = td.firstElementChild; From 33aaa867b5ef82519e90c1bb4daaea4c8f0d2006 Mon Sep 17 00:00:00 2001 From: Vladimir Golovnev Date: Sun, 27 Apr 2025 16:21:20 +0300 Subject: [PATCH 07/45] Drop support of Qt 6.5 PR #22599. --- .github/workflows/ci_ubuntu.yaml | 3 ++- .github/workflows/coverity-scan.yaml | 2 +- CMakeLists.txt | 2 +- INSTALL | 2 +- cmake/Modules/CommonConfig.cmake | 2 +- src/app/application.cpp | 2 -- src/base/bittorrent/sessionimpl.cpp | 4 ---- src/base/search/searchdownloadhandler.cpp | 2 +- src/base/search/searchhandler.cpp | 2 +- src/base/search/searchpluginmanager.cpp | 2 +- src/base/utils/foreignapps.cpp | 2 +- src/gui/utils.cpp | 2 -- test/testutilsversion.cpp | 8 -------- 13 files changed, 10 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci_ubuntu.yaml b/.github/workflows/ci_ubuntu.yaml index 704ab0630..807eef19f 100644 --- a/.github/workflows/ci_ubuntu.yaml +++ b/.github/workflows/ci_ubuntu.yaml @@ -21,7 +21,7 @@ jobs: matrix: libt_version: ["2.0.11", "1.2.20"] qbt_gui: ["GUI=ON", "GUI=OFF"] - qt_version: ["6.5.2"] + qt_version: ["6.6.3"] env: boost_path: "${{ github.workspace }}/../boost" @@ -162,6 +162,7 @@ jobs: - name: Package AppImage run: | + rm -f "${{ runner.workspace }}/Qt/${{ matrix.qt_version }}/gcc_64/plugins/sqldrivers/libqsqlmimer.so" ./linuxdeploy-x86_64.AppImage --appdir qbittorrent --plugin qt rm qbittorrent/apprun-hooks/* cp .github/workflows/helper/appimage/export_vars.sh qbittorrent/apprun-hooks/export_vars.sh diff --git a/.github/workflows/coverity-scan.yaml b/.github/workflows/coverity-scan.yaml index ce970c773..22c5a7082 100644 --- a/.github/workflows/coverity-scan.yaml +++ b/.github/workflows/coverity-scan.yaml @@ -16,7 +16,7 @@ jobs: matrix: libt_version: ["2.0.11"] qbt_gui: ["GUI=ON"] - qt_version: ["6.5.2"] + qt_version: ["6.6.3"] env: boost_path: "${{ github.workspace }}/../boost" diff --git a/CMakeLists.txt b/CMakeLists.txt index 86ede6b3c..97ecb3684 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ project(qBittorrent # version requirements - older versions may work, but you are on your own set(minBoostVersion 1.76) -set(minQt6Version 6.5.0) +set(minQt6Version 6.6.0) set(minOpenSSLVersion 3.0.2) set(minLibtorrent1Version 1.2.19) set(minLibtorrentVersion 2.0.10) diff --git a/INSTALL b/INSTALL index ec3ff78ea..b17e323fb 100644 --- a/INSTALL +++ b/INSTALL @@ -11,7 +11,7 @@ qBittorrent - A BitTorrent client in C++ / Qt - OpenSSL >= 3.0.2 - - Qt 6.5.0 - 6.x + - Qt 6.6.0 - 6.x - zlib >= 1.2.11 diff --git a/cmake/Modules/CommonConfig.cmake b/cmake/Modules/CommonConfig.cmake index b57dc4bcf..85535313a 100644 --- a/cmake/Modules/CommonConfig.cmake +++ b/cmake/Modules/CommonConfig.cmake @@ -20,7 +20,7 @@ target_compile_features(qbt_common_cfg INTERFACE ) target_compile_definitions(qbt_common_cfg INTERFACE - QT_DISABLE_DEPRECATED_UP_TO=0x060500 + QT_DISABLE_DEPRECATED_UP_TO=0x060600 QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_BYTEARRAY diff --git a/src/app/application.cpp b/src/app/application.cpp index 90e785e1a..a6666c57e 100644 --- a/src/app/application.cpp +++ b/src/app/application.cpp @@ -674,9 +674,7 @@ void Application::runExternalProgram(const QString &programTemplate, const BitTo QProcess proc; proc.setProgram(command); proc.setArguments(args); -#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)) proc.setUnixProcessParameters(QProcess::UnixProcessFlag::CloseFileDescriptors); -#endif if (proc.startDetached()) { diff --git a/src/base/bittorrent/sessionimpl.cpp b/src/base/bittorrent/sessionimpl.cpp index 64d274f19..e88b7cd5c 100644 --- a/src/base/bittorrent/sessionimpl.cpp +++ b/src/base/bittorrent/sessionimpl.cpp @@ -1642,11 +1642,7 @@ void SessionImpl::endStartup(ResumeSessionContext *context) auto wakeupCheckTimer = new QTimer(this); connect(wakeupCheckTimer, &QTimer::timeout, this, [this] { -#if (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)) const bool hasSystemSlept = m_wakeupCheckTimestamp.durationElapsed() > 100s; -#else - const bool hasSystemSlept = m_wakeupCheckTimestamp.elapsed() > std::chrono::milliseconds(100s).count(); -#endif if (hasSystemSlept) { LogMsg(tr("System wake-up event detected. Re-announcing to all the trackers...")); diff --git a/src/base/search/searchdownloadhandler.cpp b/src/base/search/searchdownloadhandler.cpp index 34289bf8c..c2dca0790 100644 --- a/src/base/search/searchdownloadhandler.cpp +++ b/src/base/search/searchdownloadhandler.cpp @@ -42,7 +42,7 @@ SearchDownloadHandler::SearchDownloadHandler(const QString &pluginName, const QS , m_downloadProcess {new QProcess(this)} { m_downloadProcess->setProcessEnvironment(m_manager->proxyEnvironment()); -#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)) +#ifdef Q_OS_UNIX m_downloadProcess->setUnixProcessParameters(QProcess::UnixProcessFlag::CloseFileDescriptors); #endif connect(m_downloadProcess, qOverload(&QProcess::finished) diff --git a/src/base/search/searchhandler.cpp b/src/base/search/searchhandler.cpp index 114ddce5f..f847d187a 100644 --- a/src/base/search/searchhandler.cpp +++ b/src/base/search/searchhandler.cpp @@ -72,7 +72,7 @@ SearchHandler::SearchHandler(const QString &pattern, const QString &category, co // Load environment variables (proxy) m_searchProcess->setProcessEnvironment(m_manager->proxyEnvironment()); m_searchProcess->setProgram(Utils::ForeignApps::pythonInfo().executableName); -#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)) +#ifdef Q_OS_UNIX m_searchProcess->setUnixProcessParameters(QProcess::UnixProcessFlag::CloseFileDescriptors); #endif diff --git a/src/base/search/searchpluginmanager.cpp b/src/base/search/searchpluginmanager.cpp index c79ba5d60..5caa611bf 100644 --- a/src/base/search/searchpluginmanager.cpp +++ b/src/base/search/searchpluginmanager.cpp @@ -546,7 +546,7 @@ void SearchPluginManager::update() { QProcess nova; nova.setProcessEnvironment(proxyEnvironment()); -#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)) +#ifdef Q_OS_UNIX nova.setUnixProcessParameters(QProcess::UnixProcessFlag::CloseFileDescriptors); #endif diff --git a/src/base/utils/foreignapps.cpp b/src/base/utils/foreignapps.cpp index 038d5128f..d4e58c1a8 100644 --- a/src/base/utils/foreignapps.cpp +++ b/src/base/utils/foreignapps.cpp @@ -57,7 +57,7 @@ namespace info = {}; QProcess proc; -#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)) +#ifdef Q_OS_UNIX proc.setUnixProcessParameters(QProcess::UnixProcessFlag::CloseFileDescriptors); #endif proc.start(exeName, {u"--version"_s}, QIODevice::ReadOnly); diff --git a/src/gui/utils.cpp b/src/gui/utils.cpp index ac5d922dc..e987d75c0 100644 --- a/src/gui/utils.cpp +++ b/src/gui/utils.cpp @@ -176,9 +176,7 @@ void Utils::Gui::openFolderSelect(const Path &path) const int lineMaxLength = 64; QProcess proc; -#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0) proc.setUnixProcessParameters(QProcess::UnixProcessFlag::CloseFileDescriptors); -#endif proc.start(u"xdg-mime"_s, {u"query"_s, u"default"_s, u"inode/directory"_s}); proc.waitForFinished(); const auto output = QString::fromLocal8Bit(proc.readLine(lineMaxLength).simplified()); diff --git a/test/testutilsversion.cpp b/test/testutilsversion.cpp index 733fadac8..63d8360dd 100644 --- a/test/testutilsversion.cpp +++ b/test/testutilsversion.cpp @@ -80,9 +80,7 @@ private slots: { const Utils::Version<1> version1 {1}; QCOMPARE(version1[0], 1); -#if (QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)) QVERIFY_THROWS_EXCEPTION(std::out_of_range, version1[1]); -#endif QCOMPARE(version1.majorNumber(), 1); // should not compile: // version1.minorNumber(); @@ -92,9 +90,7 @@ private slots: const Utils::Version<2, 1> version2 {2}; QCOMPARE(version2[0], 2); QCOMPARE(version2[1], 0); -#if (QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)) QVERIFY_THROWS_EXCEPTION(std::out_of_range, version2[2]); -#endif QCOMPARE(version2.majorNumber(), 2); QCOMPARE(version2.minorNumber(), 0); // should not compile: @@ -105,9 +101,7 @@ private slots: QCOMPARE(version3[0], 3); QCOMPARE(version3[1], 2); QCOMPARE(version3[2], 0); -#if (QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)) QVERIFY_THROWS_EXCEPTION(std::out_of_range, version3[3]); -#endif QCOMPARE(version3.majorNumber(), 3); QCOMPARE(version3.minorNumber(), 2); QCOMPARE(version3.revisionNumber(), 0); @@ -119,9 +113,7 @@ private slots: QCOMPARE(version4[1], 11); QCOMPARE(version4[2], 12); QCOMPARE(version4[3], 13); -#if (QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)) QVERIFY_THROWS_EXCEPTION(std::out_of_range, version4[4]); -#endif QCOMPARE(version4.majorNumber(), 10); QCOMPARE(version4.minorNumber(), 11); QCOMPARE(version4.revisionNumber(), 12); From 732b2bcbdb80debe1622dfe78dfd5530f2b0d008 Mon Sep 17 00:00:00 2001 From: Vladimir Golovnev Date: Sun, 27 Apr 2025 16:24:07 +0300 Subject: [PATCH 08/45] Provide asynchronous results via QFuture Makes asynchronous logic to look more straightforward. Allows caller to choose blocking or non-blocking way of obtaining asynchronous results via the same interface. PR #22598. --- src/base/bittorrent/filesearcher.cpp | 24 ++-- src/base/bittorrent/filesearcher.h | 21 ++- src/base/bittorrent/sessionimpl.cpp | 87 ++++++------ src/base/bittorrent/sessionimpl.h | 8 +- src/base/bittorrent/torrent.h | 15 +-- src/base/bittorrent/torrentcontenthandler.h | 7 +- src/base/bittorrent/torrentimpl.cpp | 142 +++++--------------- src/base/bittorrent/torrentimpl.h | 19 +-- src/gui/addnewtorrentdialog.cpp | 15 ++- src/gui/properties/peerlistwidget.cpp | 5 +- src/gui/properties/propertieswidget.cpp | 16 +-- src/gui/torrentcontentmodel.cpp | 6 +- src/gui/trackerlist/trackerlistmodel.cpp | 5 +- src/webui/api/synccontroller.cpp | 5 +- src/webui/api/torrentscontroller.cpp | 13 +- 15 files changed, 165 insertions(+), 223 deletions(-) diff --git a/src/base/bittorrent/filesearcher.cpp b/src/base/bittorrent/filesearcher.cpp index 2fcd31f8f..9b1a1f9cc 100644 --- a/src/base/bittorrent/filesearcher.cpp +++ b/src/base/bittorrent/filesearcher.cpp @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2020 Vladimir Golovnev + * Copyright (C) 2020-2025 Vladimir Golovnev * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -27,13 +27,14 @@ */ #include "filesearcher.h" -#include "base/bittorrent/common.h" -#include "base/bittorrent/infohash.h" -void FileSearcher::search(const BitTorrent::TorrentID &id, const PathList &originalFileNames - , const Path &savePath, const Path &downloadPath, const bool forceAppendExt) +#include + +#include "base/bittorrent/common.h" + +namespace { - const auto findInDir = [](const Path &dirPath, PathList &fileNames, const bool forceAppendExt) -> bool + bool findInDir(const Path &dirPath, PathList &fileNames, const bool forceAppendExt) { bool found = false; for (Path &fileName : fileNames) @@ -58,7 +59,13 @@ void FileSearcher::search(const BitTorrent::TorrentID &id, const PathList &origi } return found; - }; + } +} + +void FileSearcher::search(const PathList &originalFileNames, const Path &savePath + , const Path &downloadPath, const bool forceAppendExt, QPromise promise) +{ + promise.start(); Path usedPath = savePath; PathList adjustedFileNames = originalFileNames; @@ -69,5 +76,6 @@ void FileSearcher::search(const BitTorrent::TorrentID &id, const PathList &origi findInDir(usedPath, adjustedFileNames, forceAppendExt); } - emit searchFinished(id, usedPath, adjustedFileNames); + promise.addResult(FileSearchResult {.savePath = usedPath, .fileNames = adjustedFileNames}); + promise.finish(); } diff --git a/src/base/bittorrent/filesearcher.h b/src/base/bittorrent/filesearcher.h index 04495bd76..cfd7ada73 100644 --- a/src/base/bittorrent/filesearcher.h +++ b/src/base/bittorrent/filesearcher.h @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2020 Vladimir Golovnev + * Copyright (C) 2020-2025 Vladimir Golovnev * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -32,10 +32,13 @@ #include "base/path.h" -namespace BitTorrent +template class QPromise; + +struct FileSearchResult { - class TorrentID; -} + Path savePath; + PathList fileNames; +}; class FileSearcher final : public QObject { @@ -43,12 +46,8 @@ class FileSearcher final : public QObject Q_DISABLE_COPY_MOVE(FileSearcher) public: - FileSearcher() = default; + using QObject::QObject; -public slots: - void search(const BitTorrent::TorrentID &id, const PathList &originalFileNames - , const Path &savePath, const Path &downloadPath, bool forceAppendExt); - -signals: - void searchFinished(const BitTorrent::TorrentID &id, const Path &savePath, const PathList &fileNames); + void search(const PathList &originalFileNames, const Path &savePath + , const Path &downloadPath, bool forceAppendExt, QPromise promise); }; diff --git a/src/base/bittorrent/sessionimpl.cpp b/src/base/bittorrent/sessionimpl.cpp index e88b7cd5c..d9827b150 100644 --- a/src/base/bittorrent/sessionimpl.cpp +++ b/src/base/bittorrent/sessionimpl.cpp @@ -61,6 +61,7 @@ #include #include #include +#include #include #include #include @@ -69,6 +70,7 @@ #include #include #include +#include #include #include #include @@ -622,7 +624,6 @@ SessionImpl::SessionImpl(QObject *parent) m_fileSearcher = new FileSearcher; m_fileSearcher->moveToThread(m_ioThread.get()); connect(m_ioThread.get(), &QThread::finished, m_fileSearcher, &QObject::deleteLater); - connect(m_fileSearcher, &FileSearcher::searchFinished, this, &SessionImpl::fileSearchFinished); m_torrentContentRemover = new TorrentContentRemover; m_torrentContentRemover->moveToThread(m_ioThread.get()); @@ -2376,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 ¶ms = loadingTorrentsIter.value(); - lt::add_torrent_params &p = params.ltAddTorrentParams; - - p.save_path = savePath.toString().toStdString(); - const TorrentInfo torrentInfo {*p.ti}; - const auto nativeIndexes = torrentInfo.nativeIndexes(); - for (int i = 0; i < fileNames.size(); ++i) - p.renamed_files[nativeIndexes[i]] = fileNames[i].toString().toStdString(); - - m_nativeSession->async_add_torrent(p); - } -} - void SessionImpl::torrentContentRemovingFinished(const QString &torrentName, const QString &errorMessage) { if (errorMessage.isEmpty()) @@ -2828,11 +2804,12 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr lt::add_torrent_params &p = loadTorrentParams.ltAddTorrentParams; p = source.ltAddTorrentParams(); - bool isFindingIncompleteFiles = false; - const bool useAutoTMM = loadTorrentParams.useAutoTMM; const Path actualSavePath = useAutoTMM ? categorySavePath(loadTorrentParams.category) : loadTorrentParams.savePath; + bool needFindIncompleteFiles = false; + PathList filePaths; + if (hasMetadata) { // Torrent that is being added with metadata is considered to be added as stopped @@ -2847,7 +2824,7 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr Q_ASSERT(addTorrentParams.filePaths.isEmpty() || (addTorrentParams.filePaths.size() == torrentInfo.filesCount())); - PathList filePaths = addTorrentParams.filePaths; + filePaths = addTorrentParams.filePaths; if (filePaths.isEmpty()) { filePaths = torrentInfo.filePaths(); @@ -2893,13 +2870,9 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr if (!loadTorrentParams.hasFinishedStatus) { - const Path actualDownloadPath = useAutoTMM - ? categoryDownloadPath(loadTorrentParams.category) : loadTorrentParams.downloadPath; - findIncompleteFiles(torrentInfo, actualSavePath, actualDownloadPath, filePaths); - isFindingIncompleteFiles = true; + needFindIncompleteFiles = true; } - - if (!isFindingIncompleteFiles) + else { for (int index = 0; index < filePaths.size(); ++index) p.renamed_files[nativeIndexes[index]] = filePaths.at(index).toString().toStdString(); @@ -2998,23 +2971,49 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr m_loadingTorrents.insert(id, loadTorrentParams); if (infoHash.isHybrid()) m_hybridTorrentsByAltID.insert(altID, nullptr); - if (!isFindingIncompleteFiles) + + if (needFindIncompleteFiles) + { + const Path actualDownloadPath = useAutoTMM + ? categoryDownloadPath(loadTorrentParams.category) : loadTorrentParams.downloadPath; + findIncompleteFiles(actualSavePath, actualDownloadPath, filePaths).then(this + , [this, id](const FileSearchResult &result) + { + const auto loadingTorrentsIter = m_loadingTorrents.find(id); + Q_ASSERT(loadingTorrentsIter != m_loadingTorrents.end()); + if (loadingTorrentsIter == m_loadingTorrents.end()) [[unlikely]] + return; + + LoadTorrentParams ¶ms = loadingTorrentsIter.value(); + lt::add_torrent_params &p = params.ltAddTorrentParams; + + p.save_path = result.savePath.toString().toStdString(); + const TorrentInfo torrentInfo {*p.ti}; + const auto nativeIndexes = torrentInfo.nativeIndexes(); + for (int i = 0; i < result.fileNames.size(); ++i) + p.renamed_files[nativeIndexes[i]] = result.fileNames[i].toString().toStdString(); + + m_nativeSession->async_add_torrent(p); + }); + } + else + { m_nativeSession->async_add_torrent(p); + } return true; } -void SessionImpl::findIncompleteFiles(const TorrentInfo &torrentInfo, const Path &savePath - , const Path &downloadPath, const PathList &filePaths) const +QFuture SessionImpl::findIncompleteFiles(const Path &savePath, const Path &downloadPath, const PathList &filePaths) const { - Q_ASSERT(filePaths.isEmpty() || (filePaths.size() == torrentInfo.filesCount())); - - const auto searchId = TorrentID::fromInfoHash(torrentInfo.infoHash()); - const PathList originalFileNames = (filePaths.isEmpty() ? torrentInfo.filePaths() : filePaths); - QMetaObject::invokeMethod(m_fileSearcher, [=, this] + QPromise promise; + QFuture future = promise.future(); + QMetaObject::invokeMethod(m_fileSearcher, [=, this, promise = std::move(promise)]() mutable { - m_fileSearcher->search(searchId, originalFileNames, savePath, downloadPath, isAppendExtensionEnabled()); + m_fileSearcher->search(filePaths, savePath, downloadPath, isAppendExtensionEnabled(), std::move(promise)); }); + + return future; } void SessionImpl::enablePortMapping() diff --git a/src/base/bittorrent/sessionimpl.h b/src/base/bittorrent/sessionimpl.h index 1ad2108ff..e878cf4a6 100644 --- a/src/base/bittorrent/sessionimpl.h +++ b/src/base/bittorrent/sessionimpl.h @@ -61,12 +61,16 @@ class QString; class QTimer; class QUrl; +template class QFuture; + class BandwidthScheduler; class FileSearcher; class FilterParserThread; class FreeDiskSpaceChecker; class NativeSessionExtension; +struct FileSearchResult; + namespace BitTorrent { enum class MoveStorageMode; @@ -478,8 +482,7 @@ namespace BitTorrent bool addMoveTorrentStorageJob(TorrentImpl *torrent, const Path &newPath, MoveStorageMode mode, MoveStorageContext context); - void findIncompleteFiles(const TorrentInfo &torrentInfo, const Path &savePath - , const Path &downloadPath, const PathList &filePaths = {}) const; + QFuture findIncompleteFiles(const Path &savePath, const Path &downloadPath, const PathList &filePaths = {}) const; void enablePortMapping(); void disablePortMapping(); @@ -514,7 +517,6 @@ namespace BitTorrent void generateResumeData(); void handleIPFilterParsed(int ruleCount); void handleIPFilterError(); - void fileSearchFinished(const TorrentID &id, const Path &savePath, const PathList &fileNames); void torrentContentRemovingFinished(const QString &torrentName, const QString &errorMessage); private: diff --git a/src/base/bittorrent/torrent.h b/src/base/bittorrent/torrent.h index d2eefbabf..fc817b86c 100644 --- a/src/base/bittorrent/torrent.h +++ b/src/base/bittorrent/torrent.h @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2015-2024 Vladimir Golovnev + * Copyright (C) 2015-2025 Vladimir Golovnev * Copyright (C) 2006 Christophe Dumez * * This program is free software; you can redistribute it and/or @@ -45,6 +45,8 @@ class QByteArray; class QDateTime; class QUrl; +template class QFuture; + namespace BitTorrent { enum class DownloadPriority; @@ -275,10 +277,7 @@ namespace BitTorrent virtual bool isDHTDisabled() const = 0; virtual bool isPEXDisabled() const = 0; virtual bool isLSDDisabled() const = 0; - virtual QList peers() const = 0; virtual QBitArray pieces() const = 0; - virtual QBitArray downloadingPieces() const = 0; - virtual QList pieceAvailability() const = 0; virtual qreal distributedCopies() const = 0; virtual qreal maxRatio() const = 0; virtual int maxSeedingTime() const = 0; @@ -325,10 +324,10 @@ namespace BitTorrent virtual nonstd::expected exportToBuffer() const = 0; virtual nonstd::expected exportToFile(const Path &path) const = 0; - virtual void fetchPeerInfo(std::function)> resultHandler) const = 0; - virtual void fetchURLSeeds(std::function)> resultHandler) const = 0; - virtual void fetchPieceAvailability(std::function)> resultHandler) const = 0; - virtual void fetchDownloadingPieces(std::function resultHandler) const = 0; + virtual QFuture> fetchPeerInfo() const = 0; + virtual QFuture> fetchURLSeeds() const = 0; + virtual QFuture> fetchPieceAvailability() const = 0; + virtual QFuture fetchDownloadingPieces() const = 0; TorrentID id() const; bool isRunning() const; diff --git a/src/base/bittorrent/torrentcontenthandler.h b/src/base/bittorrent/torrentcontenthandler.h index 2e3702d2c..350db753e 100644 --- a/src/base/bittorrent/torrentcontenthandler.h +++ b/src/base/bittorrent/torrentcontenthandler.h @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2022-2023 Vladimir Golovnev + * Copyright (C) 2022-2025 Vladimir Golovnev * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -34,6 +34,8 @@ #include "abstractfilestorage.h" #include "downloadpriority.h" +template class QFuture; + namespace BitTorrent { class TorrentContentHandler : public QObject, public AbstractFileStorage @@ -52,8 +54,7 @@ namespace BitTorrent * This is not the same as torrrent availability, it is just a fraction of pieces * that can be downloaded right now. It varies between 0 to 1. */ - virtual QList availableFileFractions() const = 0; - virtual void fetchAvailableFileFractions(std::function)> resultHandler) const = 0; + virtual QFuture> fetchAvailableFileFractions() const = 0; virtual void prioritizeFiles(const QList &priorities) = 0; virtual void flushCache() const = 0; diff --git a/src/base/bittorrent/torrentimpl.cpp b/src/base/bittorrent/torrentimpl.cpp index 45cc7f3bf..a670db151 100644 --- a/src/base/bittorrent/torrentimpl.cpp +++ b/src/base/bittorrent/torrentimpl.cpp @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2015-2024 Vladimir Golovnev + * Copyright (C) 2015-2025 Vladimir Golovnev * Copyright (C) 2006 Christophe Dumez * * This program is free software; you can redistribute it and/or @@ -51,7 +51,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -67,6 +69,7 @@ #include "common.h" #include "downloadpriority.h" #include "extensiondata.h" +#include "filesearcher.h" #include "loadtorrentparams.h" #include "ltqbitarray.h" #include "lttypecast.h" @@ -1465,48 +1468,11 @@ bool TorrentImpl::isLSDDisabled() const return static_cast(m_nativeStatus.flags & lt::torrent_flags::disable_lsd); } -QList TorrentImpl::peers() const -{ - std::vector nativePeers; - m_nativeHandle.get_peer_info(nativePeers); - - QList peers; - peers.reserve(static_cast(nativePeers.size())); - - for (const lt::peer_info &peer : nativePeers) - peers.append(PeerInfo(peer, pieces())); - - return peers; -} - QBitArray TorrentImpl::pieces() const { return m_pieces; } -QBitArray TorrentImpl::downloadingPieces() const -{ - if (!hasMetadata()) - return {}; - - std::vector 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 TorrentImpl::pieceAvailability() const -{ - std::vector avail; - m_nativeHandle.piece_availability(avail); - - return {avail.cbegin(), avail.cend()}; -} - qreal TorrentImpl::distributedCopies() const { return m_nativeStatus.distributed_copies; @@ -1751,12 +1717,6 @@ void TorrentImpl::applyFirstLastPiecePriority(const bool enabled) m_nativeHandle.prioritize_pieces(piecePriorities); } -void TorrentImpl::fileSearchFinished(const Path &savePath, const PathList &fileNames) -{ - if (m_maintenanceJob == MaintenanceJob::HandleMetadata) - endReceivedMetadataHandling(savePath, fileNames); -} - TrackerEntryStatus TorrentImpl::updateTrackerEntryStatus(const lt::announce_entry &announceEntry, const QHash> &updateInfo) { const auto it = std::find_if(m_trackerEntryStatuses.begin(), m_trackerEntryStatuses.end() @@ -2150,7 +2110,7 @@ void TorrentImpl::handleSaveResumeDataAlert(const lt::save_resume_data_alert *p) // URL seed list have been changed by libtorrent for some reason, so we need to update cached one. // Unfortunately, URL seed list containing in "resume data" is generated according to different rules // than the list we usually cache, so we have to request it from the appropriate source. - fetchURLSeeds([this](const QList &urlSeeds) { m_urlSeeds = urlSeeds; }); + fetchURLSeeds().then(this, [this](const QList &urlSeeds) { m_urlSeeds = urlSeeds; }); } if ((m_maintenanceJob == MaintenanceJob::HandleMetadata) && p->params.ti) @@ -2197,7 +2157,12 @@ void TorrentImpl::handleSaveResumeDataAlert(const lt::save_resume_data_alert *p) filePaths[i] = Path(it->second); } - m_session->findIncompleteFiles(metadata, savePath(), downloadPath(), filePaths); + m_session->findIncompleteFiles(savePath(), downloadPath(), filePaths).then(this + , [this](const FileSearchResult &result) + { + if (m_maintenanceJob == MaintenanceJob::HandleMetadata) + endReceivedMetadataHandling(result.savePath, result.fileNames); + }); } else { @@ -2930,9 +2895,9 @@ nonstd::expected TorrentImpl::exportToFile(const Path &path) cons return {}; } -void TorrentImpl::fetchPeerInfo(std::function)> resultHandler) const +QFuture> TorrentImpl::fetchPeerInfo() const { - invokeAsync([nativeHandle = m_nativeHandle, allPieces = pieces()]() -> QList + return invokeAsync([nativeHandle = m_nativeHandle, allPieces = pieces()]() -> QList { try { @@ -2947,13 +2912,12 @@ void TorrentImpl::fetchPeerInfo(std::function)> resultHand catch (const std::exception &) {} return {}; - } - , std::move(resultHandler)); + }); } -void TorrentImpl::fetchURLSeeds(std::function)> resultHandler) const +QFuture> TorrentImpl::fetchURLSeeds() const { - invokeAsync([nativeHandle = m_nativeHandle]() -> QList + return invokeAsync([nativeHandle = m_nativeHandle]() -> QList { try { @@ -2967,13 +2931,12 @@ void TorrentImpl::fetchURLSeeds(std::function)> resultHandler) catch (const std::exception &) {} return {}; - } - , std::move(resultHandler)); + }); } -void TorrentImpl::fetchPieceAvailability(std::function)> resultHandler) const +QFuture> TorrentImpl::fetchPieceAvailability() const { - invokeAsync([nativeHandle = m_nativeHandle]() -> QList + return invokeAsync([nativeHandle = m_nativeHandle]() -> QList { try { @@ -2984,13 +2947,12 @@ void TorrentImpl::fetchPieceAvailability(std::function)> result catch (const std::exception &) {} return {}; - } - , std::move(resultHandler)); + }); } -void TorrentImpl::fetchDownloadingPieces(std::function resultHandler) const +QFuture TorrentImpl::fetchDownloadingPieces() const { - invokeAsync([nativeHandle = m_nativeHandle, torrentInfo = m_torrentInfo]() -> QBitArray + return invokeAsync([nativeHandle = m_nativeHandle, torrentInfo = m_torrentInfo]() -> QBitArray { try { @@ -3009,13 +2971,12 @@ void TorrentImpl::fetchDownloadingPieces(std::function resultH catch (const std::exception &) {} return {}; - } - , std::move(resultHandler)); + }); } -void TorrentImpl::fetchAvailableFileFractions(std::function)> resultHandler) const +QFuture> TorrentImpl::fetchAvailableFileFractions() const { - invokeAsync([nativeHandle = m_nativeHandle, torrentInfo = m_torrentInfo]() -> QList + return invokeAsync([nativeHandle = m_nativeHandle, torrentInfo = m_torrentInfo]() -> QList { if (!torrentInfo.isValid() || (torrentInfo.filesCount() <= 0)) return {}; @@ -3049,8 +3010,7 @@ void TorrentImpl::fetchAvailableFileFractions(std::function)> catch (const std::exception &) {} return {}; - } - , std::move(resultHandler)); + }); } void TorrentImpl::prioritizeFiles(const QList &priorities) @@ -3090,47 +3050,17 @@ void TorrentImpl::prioritizeFiles(const QList &priorities) manageActualFilePaths(); } -QList TorrentImpl::availableFileFractions() const +template +QFuture> TorrentImpl::invokeAsync(Func &&func) const { - Q_ASSERT(hasMetadata()); - - const int filesCount = this->filesCount(); - if (filesCount <= 0) return {}; - - const QList piecesAvailability = pieceAvailability(); - // libtorrent returns empty array for seeding only torrents - if (piecesAvailability.empty()) return QList(filesCount, -1); - - QList res; - res.reserve(filesCount); - for (int i = 0; i < filesCount; ++i) + QPromise> promise; + const auto future = promise.future(); + m_session->invokeAsync([func = std::forward(func), promise = std::move(promise)]() mutable { - const TorrentInfo::PieceRange filePieces = m_torrentInfo.filePieces(i); - - int availablePieces = 0; - for (const int piece : filePieces) - availablePieces += (piecesAvailability[piece] > 0) ? 1 : 0; - - const qreal availability = filePieces.isEmpty() - ? 1 // the file has no pieces, so it is available by default - : static_cast(availablePieces) / filePieces.size(); - res.push_back(availability); - } - return res; -} - -template -void TorrentImpl::invokeAsync(Func func, Callback resultHandler) const -{ - m_session->invokeAsync([session = m_session - , func = std::move(func) - , resultHandler = std::move(resultHandler) - , thisTorrent = QPointer(this)]() mutable - { - session->invoke([result = func(), thisTorrent, resultHandler = std::move(resultHandler)] - { - if (thisTorrent) - resultHandler(result); - }); + promise.start(); + promise.addResult(func()); + promise.finish(); }); + + return future; } diff --git a/src/base/bittorrent/torrentimpl.h b/src/base/bittorrent/torrentimpl.h index 5c54b2d00..87137cd73 100644 --- a/src/base/bittorrent/torrentimpl.h +++ b/src/base/bittorrent/torrentimpl.h @@ -203,10 +203,7 @@ namespace BitTorrent bool isDHTDisabled() const override; bool isPEXDisabled() const override; bool isLSDDisabled() const override; - QList peers() const override; QBitArray pieces() const override; - QBitArray downloadingPieces() const override; - QList pieceAvailability() const override; qreal distributedCopies() const override; qreal maxRatio() const override; int maxSeedingTime() const override; @@ -220,7 +217,6 @@ namespace BitTorrent int connectionsCount() const override; int connectionsLimit() const override; qlonglong nextAnnounce() const override; - QList availableFileFractions() const override; void setName(const QString &name) override; void setSequentialDownload(bool enable) override; @@ -258,11 +254,11 @@ namespace BitTorrent nonstd::expected exportToBuffer() const override; nonstd::expected exportToFile(const Path &path) const override; - void fetchPeerInfo(std::function)> resultHandler) const override; - void fetchURLSeeds(std::function)> resultHandler) const override; - void fetchPieceAvailability(std::function)> resultHandler) const override; - void fetchDownloadingPieces(std::function resultHandler) const override; - void fetchAvailableFileFractions(std::function)> resultHandler) const override; + QFuture> fetchPeerInfo() const override; + QFuture> fetchURLSeeds() const override; + QFuture> fetchPieceAvailability() const override; + QFuture fetchDownloadingPieces() const override; + QFuture> fetchAvailableFileFractions() const override; bool needSaveResumeData() const; @@ -278,7 +274,6 @@ namespace BitTorrent void requestResumeData(lt::resume_data_flags_t flags = {}); void deferredRequestResumeData(); void handleMoveStorageJobFinished(const Path &path, MoveStorageContext context, bool hasOutstandingJob); - void fileSearchFinished(const Path &savePath, const PathList &fileNames); TrackerEntryStatus updateTrackerEntryStatus(const lt::announce_entry &announceEntry, const QHash> &updateInfo); void resetTrackerEntryStatuses(); @@ -326,8 +321,8 @@ namespace BitTorrent nonstd::expected exportTorrent() const; - template - void invokeAsync(Func func, Callback resultHandler) const; + template + QFuture> invokeAsync(Func &&func) const; SessionImpl *const m_session = nullptr; lt::session *m_nativeSession = nullptr; diff --git a/src/gui/addnewtorrentdialog.cpp b/src/gui/addnewtorrentdialog.cpp index 321e1528b..8954a1c4d 100644 --- a/src/gui/addnewtorrentdialog.cpp +++ b/src/gui/addnewtorrentdialog.cpp @@ -32,12 +32,14 @@ #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -242,14 +244,13 @@ public: return QList(filesCount(), 0); } - QList availableFileFractions() const override + QFuture> fetchAvailableFileFractions() const override { - return QList(filesCount(), 0); - } - - void fetchAvailableFileFractions(std::function)> resultHandler) const override - { - resultHandler(availableFileFractions()); +#if (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)) + return QtFuture::makeReadyValueFuture(QList(filesCount(), 0)); +#else + return QtFuture::makeReadyFuture(QList(filesCount(), 0)); +#endif } void prioritizeFiles(const QList &priorities) override diff --git a/src/gui/properties/peerlistwidget.cpp b/src/gui/properties/peerlistwidget.cpp index 8546d7143..a6c44d106 100644 --- a/src/gui/properties/peerlistwidget.cpp +++ b/src/gui/properties/peerlistwidget.cpp @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2023 Vladimir Golovnev + * Copyright (C) 2023-2025 Vladimir Golovnev * Copyright (C) 2006 Christophe Dumez * * This program is free software; you can redistribute it and/or @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -406,7 +407,7 @@ void PeerListWidget::loadPeers(const BitTorrent::Torrent *torrent) return; using TorrentPtr = QPointer; - torrent->fetchPeerInfo([this, torrent = TorrentPtr(torrent)](const QList &peers) + torrent->fetchPeerInfo().then(this, [this, torrent = TorrentPtr(torrent)](const QList &peers) { if (torrent != m_properties->getCurrentTorrent()) return; diff --git a/src/gui/properties/propertieswidget.cpp b/src/gui/properties/propertieswidget.cpp index ad9673272..303043a80 100644 --- a/src/gui/properties/propertieswidget.cpp +++ b/src/gui/properties/propertieswidget.cpp @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2022-2024 Vladimir Golovnev + * Copyright (C) 2022-2025 Vladimir Golovnev * Copyright (C) 2006 Christophe Dumez * * This program is free software; you can redistribute it and/or @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -471,15 +472,15 @@ void PropertiesWidget::loadDynamicData() if (m_torrent->hasMetadata()) { - using TorrentPtr = QPointer; - m_ui->labelTotalPiecesVal->setText(tr("%1 x %2 (have %3)", "(torrent pieces) eg 152 x 4MB (have 25)").arg(m_torrent->piecesCount()).arg(Utils::Misc::friendlyUnit(m_torrent->pieceLength())).arg(m_torrent->piecesHave())); if (!m_torrent->isFinished() && !m_torrent->isStopped() && !m_torrent->isQueued() && !m_torrent->isChecking()) { // Pieces availability showPiecesAvailability(true); - m_torrent->fetchPieceAvailability([this, torrent = TorrentPtr(m_torrent)](const QList &pieceAvailability) + + using TorrentPtr = QPointer; + m_torrent->fetchPieceAvailability().then(this, [this, torrent = TorrentPtr(m_torrent)](const QList &pieceAvailability) { if (torrent == m_torrent) m_piecesAvailability->setAvailability(pieceAvailability); @@ -496,10 +497,9 @@ void PropertiesWidget::loadDynamicData() qreal progress = m_torrent->progress() * 100.; m_ui->labelProgressVal->setText(Utils::String::fromDouble(progress, 1) + u'%'); - m_torrent->fetchDownloadingPieces([this, torrent = TorrentPtr(m_torrent)](const QBitArray &downloadingPieces) + m_torrent->fetchDownloadingPieces().then(this, [this](const QBitArray &downloadingPieces) { - if (torrent == m_torrent) - m_downloadedPieces->setProgress(m_torrent->pieces(), downloadingPieces); + m_downloadedPieces->setProgress(m_torrent->pieces(), downloadingPieces); }); } else @@ -525,7 +525,7 @@ void PropertiesWidget::loadUrlSeeds() return; using TorrentPtr = QPointer; - m_torrent->fetchURLSeeds([this, torrent = TorrentPtr(m_torrent)](const QList &urlSeeds) + m_torrent->fetchURLSeeds().then(this, [this, torrent = TorrentPtr(m_torrent)](const QList &urlSeeds) { if (torrent != m_torrent) return; diff --git a/src/gui/torrentcontentmodel.cpp b/src/gui/torrentcontentmodel.cpp index e75fc1856..32e44c16f 100644 --- a/src/gui/torrentcontentmodel.cpp +++ b/src/gui/torrentcontentmodel.cpp @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2022-2024 Vladimir Golovnev + * Copyright (C) 2022-2025 Vladimir Golovnev * Copyright (C) 2006-2012 Christophe Dumez * * This program is free software; you can redistribute it and/or @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -219,7 +220,8 @@ void TorrentContentModel::updateFilesAvailability() Q_ASSERT(m_contentHandler && m_contentHandler->hasMetadata()); using HandlerPtr = QPointer; - m_contentHandler->fetchAvailableFileFractions([this, handler = HandlerPtr(m_contentHandler)](const QList &availableFileFractions) + m_contentHandler->fetchAvailableFileFractions().then(this + , [this, handler = HandlerPtr(m_contentHandler)](const QList &availableFileFractions) { if (handler != m_contentHandler) return; diff --git a/src/gui/trackerlist/trackerlistmodel.cpp b/src/gui/trackerlist/trackerlistmodel.cpp index 78465488c..b13b067b6 100644 --- a/src/gui/trackerlist/trackerlistmodel.cpp +++ b/src/gui/trackerlist/trackerlistmodel.cpp @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2023-2024 Vladimir Golovnev + * Copyright (C) 2023-2025 Vladimir Golovnev * Copyright (C) 2006 Christophe Dumez * * This program is free software; you can redistribute it and/or @@ -42,6 +42,7 @@ #include #include +#include #include #include #include @@ -309,7 +310,7 @@ void TrackerListModel::populate() m_items->emplace_back(std::make_shared(u"** [LSD] **", privateTorrentMessage)); using TorrentPtr = QPointer; - m_torrent->fetchPeerInfo([this, torrent = TorrentPtr(m_torrent)](const QList &peers) + m_torrent->fetchPeerInfo().then(this, [this, torrent = TorrentPtr(m_torrent)](const QList &peers) { if (torrent != m_torrent) return; diff --git a/src/webui/api/synccontroller.cpp b/src/webui/api/synccontroller.cpp index 222b066aa..574a833ed 100644 --- a/src/webui/api/synccontroller.cpp +++ b/src/webui/api/synccontroller.cpp @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2018-2024 Vladimir Golovnev + * Copyright (C) 2018-2025 Vladimir Golovnev * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -28,6 +28,7 @@ #include "synccontroller.h" +#include #include #include #include @@ -745,7 +746,7 @@ void SyncController::torrentPeersAction() QVariantMap data; QVariantHash peers; - const QList peersList = torrent->peers(); + const QList peersList = torrent->fetchPeerInfo().takeResult(); bool resolvePeerCountries = Preferences::instance()->resolvePeerCountries(); diff --git a/src/webui/api/torrentscontroller.cpp b/src/webui/api/torrentscontroller.cpp index 6fd5f6fbf..c877fd5db 100644 --- a/src/webui/api/torrentscontroller.cpp +++ b/src/webui/api/torrentscontroller.cpp @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2018-2023 Vladimir Golovnev + * Copyright (C) 2018-2025 Vladimir Golovnev * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -180,9 +181,11 @@ namespace QJsonArray getStickyTrackers(const BitTorrent::Torrent *const torrent) { int seedsDHT = 0, seedsPeX = 0, seedsLSD = 0, leechesDHT = 0, leechesPeX = 0, leechesLSD = 0; - for (const BitTorrent::PeerInfo &peer : asConst(torrent->peers())) + const QList peersList = torrent->fetchPeerInfo().takeResult(); + for (const BitTorrent::PeerInfo &peer : peersList) { - if (peer.isConnecting()) continue; + if (peer.isConnecting()) + continue; if (peer.isSeed()) { @@ -727,7 +730,7 @@ void TorrentsController::filesAction() { const QList priorities = torrent->filePriorities(); const QList fp = torrent->filesProgress(); - const QList fileAvailability = torrent->availableFileFractions(); + const QList fileAvailability = torrent->fetchAvailableFileFractions().takeResult(); const BitTorrent::TorrentInfo info = torrent->info(); for (const int index : asConst(fileIndexes)) { @@ -796,7 +799,7 @@ void TorrentsController::pieceStatesAction() for (int i = 0; i < states.size(); ++i) pieceStates.append(static_cast(states[i]) * 2); - const QBitArray dlstates = torrent->downloadingPieces(); + const QBitArray dlstates = torrent->fetchDownloadingPieces().takeResult(); for (int i = 0; i < states.size(); ++i) { if (dlstates[i]) From c2f2a385824c6b118c364f1b152f5f5839fb11f1 Mon Sep 17 00:00:00 2001 From: Vladimir Golovnev Date: Mon, 28 Apr 2025 17:26:51 +0300 Subject: [PATCH 09/45] Call `QPromise::start()` early to avoid race condition PR #22617. --- src/base/bittorrent/filesearcher.cpp | 5 +---- src/base/bittorrent/filesearcher.h | 2 +- src/base/bittorrent/sessionimpl.cpp | 4 +++- src/base/bittorrent/torrentimpl.cpp | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/base/bittorrent/filesearcher.cpp b/src/base/bittorrent/filesearcher.cpp index 9b1a1f9cc..e7241b889 100644 --- a/src/base/bittorrent/filesearcher.cpp +++ b/src/base/bittorrent/filesearcher.cpp @@ -63,10 +63,8 @@ namespace } void FileSearcher::search(const PathList &originalFileNames, const Path &savePath - , const Path &downloadPath, const bool forceAppendExt, QPromise promise) + , const Path &downloadPath, const bool forceAppendExt, QPromise &promise) { - promise.start(); - Path usedPath = savePath; PathList adjustedFileNames = originalFileNames; const bool found = findInDir(usedPath, adjustedFileNames, (forceAppendExt && downloadPath.isEmpty())); @@ -77,5 +75,4 @@ void FileSearcher::search(const PathList &originalFileNames, const Path &savePat } promise.addResult(FileSearchResult {.savePath = usedPath, .fileNames = adjustedFileNames}); - promise.finish(); } diff --git a/src/base/bittorrent/filesearcher.h b/src/base/bittorrent/filesearcher.h index cfd7ada73..f225b95dc 100644 --- a/src/base/bittorrent/filesearcher.h +++ b/src/base/bittorrent/filesearcher.h @@ -49,5 +49,5 @@ public: using QObject::QObject; void search(const PathList &originalFileNames, const Path &savePath - , const Path &downloadPath, bool forceAppendExt, QPromise promise); + , const Path &downloadPath, bool forceAppendExt, QPromise &promise); }; diff --git a/src/base/bittorrent/sessionimpl.cpp b/src/base/bittorrent/sessionimpl.cpp index d9827b150..f3d68cf5f 100644 --- a/src/base/bittorrent/sessionimpl.cpp +++ b/src/base/bittorrent/sessionimpl.cpp @@ -3008,9 +3008,11 @@ QFuture SessionImpl::findIncompleteFiles(const Path &savePath, { QPromise promise; QFuture future = promise.future(); + promise.start(); QMetaObject::invokeMethod(m_fileSearcher, [=, this, promise = std::move(promise)]() mutable { - m_fileSearcher->search(filePaths, savePath, downloadPath, isAppendExtensionEnabled(), std::move(promise)); + m_fileSearcher->search(filePaths, savePath, downloadPath, isAppendExtensionEnabled(), promise); + promise.finish(); }); return future; diff --git a/src/base/bittorrent/torrentimpl.cpp b/src/base/bittorrent/torrentimpl.cpp index a670db151..f4ae0e0fa 100644 --- a/src/base/bittorrent/torrentimpl.cpp +++ b/src/base/bittorrent/torrentimpl.cpp @@ -3055,9 +3055,9 @@ QFuture> TorrentImpl::invokeAsync(Func &&func) const { QPromise> promise; const auto future = promise.future(); + promise.start(); m_session->invokeAsync([func = std::forward(func), promise = std::move(promise)]() mutable { - promise.start(); promise.addResult(func()); promise.finish(); }); From 0791828b84c150ce11170ea88f848fc77658cd06 Mon Sep 17 00:00:00 2001 From: tehcneko Date: Tue, 29 Apr 2025 20:16:00 +0800 Subject: [PATCH 10/45] WebUI: fix virtual list defects Fixes https://github.com/qbittorrent/qBittorrent/pull/22502#issuecomment-2822201721 and https://github.com/qbittorrent/qBittorrent/pull/22502#issuecomment-2822253388. PR #22597. --- src/webui/www/private/scripts/dynamicTable.js | 46 +++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index 59a52e5c5..3b6cc19de 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -911,6 +911,9 @@ window.qBittorrent.DynamicTable ??= (() => { // set the scrollable height this.table.style.height = `${rows.length * this.rowHeight}px`; + if (this.dynamicTableDiv.offsetHeight === 0) + return; + this.renderedHeight = this.dynamicTableDiv.offsetHeight; // show extra 6 rows at top/bottom to reduce flickering const extraRowCount = 6; // how many rows can be shown in the visible area @@ -947,17 +950,22 @@ window.qBittorrent.DynamicTable ??= (() => { this.updateRow(row, true); // refresh row height based on first row - setTimeout(() => { - if (this.tableBody.firstChild === null) - return; - const tr = this.tableBody.firstChild; - if (this.rowHeight !== tr.offsetHeight) { - this.rowHeight = tr.offsetHeight; - // rerender on row height change - this.rerender(); - } - - }); + const tr = this.tableBody.firstChild; + if (tr !== null) { + const updateRowHeight = () => { + if (tr.offsetHeight === 0) + return; + if (this.rowHeight !== tr.offsetHeight) { + this.rowHeight = tr.offsetHeight; + // rerender on row height change + this.rerender(); + } + }; + if (tr.offsetHeight === 0) + setTimeout(updateRowHeight); + else + updateRowHeight(); + } }, createRowElement: function(row, top = -1) { @@ -2650,8 +2658,18 @@ window.qBittorrent.DynamicTable ??= (() => { this._updateNodeCollapseIcon(node, shouldCollapse); - for (const child of node.children) - this._updateNodeVisibility(child, shouldCollapse); + this._updateNodeChildVisibility(node, shouldCollapse); + }, + + _updateNodeChildVisibility: function(root, shouldHide) { + const stack = [...root.children]; + while (stack.length > 0) { + const node = stack.pop(); + + this._updateNodeVisibility(node, (shouldHide ? shouldHide : this.isCollapsed(node.root.rowId))); + + stack.push(...node.children); + } }, clear: function() { @@ -2914,7 +2932,7 @@ window.qBittorrent.DynamicTable ??= (() => { _filterNodes: function(node, filterTerms, filteredRows) { if (node.isFolder && (!this.useVirtualList || !this.isCollapsed(node.rowId))) { - const childAdded = node.children.reduce((acc, child) => { + const childAdded = node.children.toReversed().reduce((acc, child) => { // we must execute the function before ORing w/ acc or we'll stop checking child nodes after the first successful match return (this._filterNodes(child, filterTerms, filteredRows) || acc); }, false); From 4c91cd9372ea36f9e1e80219b8384a0c01c03d1a Mon Sep 17 00:00:00 2001 From: skomerko <168652295+skomerko@users.noreply.github.com> Date: Mon, 28 Apr 2025 20:32:54 +0200 Subject: [PATCH 11/45] WebUI: Use modern class syntax to create dynamic table classes --- src/webui/www/private/scripts/dynamicTable.js | 780 +++++++++--------- 1 file changed, 370 insertions(+), 410 deletions(-) diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index 3b6cc19de..c23606140 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -67,11 +67,8 @@ window.qBittorrent.DynamicTable ??= (() => { let DynamicTableHeaderContextMenuClass = null; let progressColumnWidth = -1; - const DynamicTable = new Class({ - - initialize: () => {}, - - setup: function(dynamicTableDivId, dynamicTableFixedHeaderDivId, contextMenu, useVirtualList = false) { + class DynamicTable { + setup(dynamicTableDivId, dynamicTableFixedHeaderDivId, contextMenu, useVirtualList = false) { this.dynamicTableDivId = dynamicTableDivId; this.dynamicTableFixedHeaderDivId = dynamicTableFixedHeaderDivId; this.dynamicTableDiv = document.getElementById(dynamicTableDivId); @@ -96,9 +93,9 @@ window.qBittorrent.DynamicTable ??= (() => { this.setupHeaderMenu(); this.setupAltRow(); this.setupVirtualList(); - }, + } - setupVirtualList: function() { + setupVirtualList() { if (!this.useVirtualList) return; this.table.style.position = "relative"; @@ -112,9 +109,9 @@ window.qBittorrent.DynamicTable ??= (() => { this.rerender(); }); new ResizeObserver(resizeCallback).observe(this.dynamicTableDiv); - }, + } - setupCommonEvents: function() { + setupCommonEvents() { const tableFixedHeaderDiv = document.getElementById(this.dynamicTableFixedHeaderDivId); const tableElement = tableFixedHeaderDiv.querySelector("table"); @@ -194,9 +191,9 @@ window.qBittorrent.DynamicTable ??= (() => { } } }); - }, + } - setupHeaderEvents: function() { + setupHeaderEvents() { this.currentHeaderAction = ""; this.canResize = false; @@ -372,9 +369,9 @@ window.qBittorrent.DynamicTable ??= (() => { onCancel: onCancel }); } - }, + } - setupDynamicTableHeaderContextMenuClass: function() { + setupDynamicTableHeaderContextMenuClass() { DynamicTableHeaderContextMenuClass ??= class extends window.qBittorrent.ContextMenu.ContextMenu { updateMenuItems() { for (let i = 0; i < this.dynamicTable.columns.length; ++i) { @@ -387,16 +384,16 @@ window.qBittorrent.DynamicTable ??= (() => { } } }; - }, + } - showColumn: function(columnName, show) { + showColumn(columnName, show) { this.columns[columnName].visible = show ? "1" : "0"; LocalPreferences.set(`column_${columnName}_visible_${this.dynamicTableDivId}`, show ? "1" : "0"); this.updateColumn(columnName); this.columns[columnName].onVisibilityChange?.(columnName); - }, + } - _calculateColumnBodyWidth: function(column) { + _calculateColumnBodyWidth(column) { const columnIndex = this.getColumnPos(column.name); const bodyColumn = document.getElementById(this.dynamicTableDivId).querySelectorAll("tr>th")[columnIndex]; const canvas = document.createElement("canvas"); @@ -418,9 +415,9 @@ window.qBittorrent.DynamicTable ??= (() => { // slight buffer to prevent clipping return longestTd.width + 10; - }, + } - _setColumnWidth: function(columnName, width) { + _setColumnWidth(columnName, width) { const column = this.columns[columnName]; column.width = width; @@ -433,9 +430,9 @@ window.qBittorrent.DynamicTable ??= (() => { this.rerender(); column.onResize?.(column.name); - }, + } - autoResizeColumn: function(columnName) { + autoResizeColumn(columnName) { const column = this.columns[columnName]; let width = column.staticWidth ?? 0; @@ -458,13 +455,13 @@ window.qBittorrent.DynamicTable ??= (() => { this._setColumnWidth(column.name, width); this.saveColumnWidth(column.name); - }, + } - saveColumnWidth: function(columnName) { + saveColumnWidth(columnName) { LocalPreferences.set(`column_${columnName}_width_${this.dynamicTableDivId}`, this.columns[columnName].width); - }, + } - setupHeaderMenu: function() { + setupHeaderMenu() { this.setupDynamicTableHeaderContextMenuClass(); const menuId = `${this.dynamicTableDivId}_headerMenu`; @@ -551,11 +548,11 @@ window.qBittorrent.DynamicTable ??= (() => { }); this.headerContextMenu.dynamicTable = this; - }, + } - initColumns: () => {}, + initColumns() {} - newColumn: function(name, style, caption, defaultWidth, defaultVisible) { + newColumn(name, style, caption, defaultWidth, defaultVisible) { const column = {}; column["name"] = name; column["title"] = name; @@ -594,9 +591,9 @@ window.qBittorrent.DynamicTable ??= (() => { this.hiddenTableHeader.append(document.createElement("th")); this.fixedTableHeader.append(document.createElement("th")); - }, + } - loadColumnsOrder: function() { + loadColumnsOrder() { const columnsOrder = []; const val = LocalPreferences.get(`columns_order_${this.dynamicTableDivId}`); if ((val === null) || (val === undefined)) @@ -613,9 +610,9 @@ window.qBittorrent.DynamicTable ??= (() => { for (let i = 0; i < this.columns.length; ++i) this.columns[i] = this.columns[columnsOrder[i]]; - }, + } - saveColumnsOrder: function() { + saveColumnsOrder() { let val = ""; for (let i = 0; i < this.columns.length; ++i) { if (i > 0) @@ -623,15 +620,15 @@ window.qBittorrent.DynamicTable ??= (() => { val += this.columns[i].name; } LocalPreferences.set(`columns_order_${this.dynamicTableDivId}`, val); - }, + } - updateTableHeaders: function() { + updateTableHeaders() { this.updateHeader(this.hiddenTableHeader); this.updateHeader(this.fixedTableHeader); this.setSortedColumnIcon(this.sortedColumn, null, (this.reverseSort === "1")); - }, + } - updateHeader: function(header) { + updateHeader(header) { const ths = this.getRowCells(header); for (let i = 0; i < ths.length; ++i) { const th = ths[i]; @@ -644,17 +641,17 @@ window.qBittorrent.DynamicTable ??= (() => { th.classList.toggle("invisible", ((this.columns[i].visible === "0") || this.columns[i].force_hide)); } } - }, + } - getColumnPos: function(columnName) { + getColumnPos(columnName) { for (let i = 0; i < this.columns.length; ++i) { if (this.columns[i].name === columnName) return i; } return -1; - }, + } - updateColumn: function(columnName, updateCellData = false) { + updateColumn(columnName, updateCellData = false) { const column = this.columns[columnName]; const pos = this.getColumnPos(columnName); const ths = this.getRowCells(this.hiddenTableHeader); @@ -669,17 +666,17 @@ window.qBittorrent.DynamicTable ??= (() => { if (updateCellData) column.updateTd(td, this.rows.get(tr.rowId)); } - }, + } - getSortedColumn: function() { + getSortedColumn() { return LocalPreferences.get(`sorted_column_${this.dynamicTableDivId}`); - }, + } /** * @param {string} column name to sort by * @param {string|null} reverse defaults to implementation-specific behavior when not specified. Should only be passed when restoring previous state. */ - setSortedColumn: function(column, reverse = null) { + setSortedColumn(column, reverse = null) { if (column !== this.sortedColumn) { const oldColumn = this.sortedColumn; this.sortedColumn = column; @@ -694,9 +691,9 @@ window.qBittorrent.DynamicTable ??= (() => { LocalPreferences.set(`sorted_column_${this.dynamicTableDivId}`, column); LocalPreferences.set(`reverse_sort_${this.dynamicTableDivId}`, this.reverseSort); this.updateTable(false); - }, + } - setSortedColumnIcon: function(newColumn, oldColumn, isReverse) { + setSortedColumnIcon(newColumn, oldColumn, isReverse) { const getCol = (headerDivId, colName) => { const colElem = document.querySelectorAll(`#${headerDivId} .column_${colName}`); if (colElem.length === 1) @@ -714,48 +711,48 @@ window.qBittorrent.DynamicTable ??= (() => { oldColElem.classList.remove("sorted"); oldColElem.classList.remove("reverse"); } - }, + } - getSelectedRowId: function() { + getSelectedRowId() { if (this.selectedRows.length > 0) return this.selectedRows[0]; return ""; - }, + } - isRowSelected: function(rowId) { + isRowSelected(rowId) { return this.selectedRows.contains(rowId); - }, + } - setupAltRow: function() { + setupAltRow() { const useAltRowColors = (LocalPreferences.get("use_alt_row_colors", "true") === "true"); if (useAltRowColors) document.getElementById(this.dynamicTableDivId).classList.add("altRowColors"); - }, + } - selectAll: function() { + selectAll() { this.deselectAll(); for (const row of this.getFilteredAndSortedRows()) this.selectedRows.push(row.rowId); this.setRowClass(); - }, + } - deselectAll: function() { + deselectAll() { this.selectedRows.empty(); - }, + } - selectRow: function(rowId) { + selectRow(rowId) { this.selectedRows.push(rowId); this.setRowClass(); this.onSelectedRowChanged(); - }, + } - deselectRow: function(rowId) { + deselectRow(rowId) { this.selectedRows.erase(rowId); this.setRowClass(); this.onSelectedRowChanged(); - }, + } - selectRows: function(rowId1, rowId2) { + selectRows(rowId1, rowId2) { this.deselectAll(); if (rowId1 === rowId2) { this.selectRow(rowId1); @@ -774,22 +771,22 @@ window.qBittorrent.DynamicTable ??= (() => { } this.setRowClass(); this.onSelectedRowChanged(); - }, + } - reselectRows: function(rowIds) { + reselectRows(rowIds) { this.deselectAll(); this.selectedRows = rowIds.slice(); this.setRowClass(); - }, + } - setRowClass: function() { + setRowClass() { for (const tr of this.getTrs()) tr.classList.toggle("selected", this.isRowSelected(tr.rowId)); - }, + } - onSelectedRowChanged: () => {}, + onSelectedRowChanged() {} - updateRowData: function(data) { + updateRowData(data) { // ensure rowId is a string const rowId = `${data["rowId"]}`; let row; @@ -811,21 +808,21 @@ window.qBittorrent.DynamicTable ??= (() => { continue; row["full_data"][x] = data[x]; } - }, + } - getTrs: function() { + getTrs() { return this.tableBody.querySelectorAll("tr"); - }, + } - getRowCells: (tr) => { + getRowCells(tr) { return tr.querySelectorAll("td, th"); - }, + } - getRow: function(rowId) { + getRow(rowId) { return this.rows.get(rowId); - }, + } - getFilteredAndSortedRows: function() { + getFilteredAndSortedRows() { const filteredRows = []; for (const row of this.getRowValues()) { @@ -842,13 +839,13 @@ window.qBittorrent.DynamicTable ??= (() => { return -res; }); return filteredRows; - }, + } - getTrByRowId: function(rowId) { + getTrByRowId(rowId) { return Array.prototype.find.call(this.getTrs(), (tr => tr.rowId === rowId)); - }, + } - updateTable: function(fullUpdate = false) { + updateTable(fullUpdate = false) { const rows = this.getFilteredAndSortedRows(); for (let i = 0; i < this.selectedRows.length; ++i) { @@ -905,9 +902,9 @@ window.qBittorrent.DynamicTable ??= (() => { while ((rowPos < trs.length) && (trs.length > 0)) trs.pop().destroy(); } - }, + } - rerender: function(rows = this.getFilteredAndSortedRows()) { + rerender(rows = this.getFilteredAndSortedRows()) { // set the scrollable height this.table.style.height = `${rows.length * this.rowHeight}px`; @@ -966,9 +963,9 @@ window.qBittorrent.DynamicTable ??= (() => { else updateRowHeight(); } - }, + } - createRowElement: function(row, top = -1) { + createRowElement(row, top = -1) { const tr = document.createElement("tr"); // set tabindex so element receives keydown events // more info: https://developer.mozilla.org/en-US/docs/Web/API/Element/keydown_event @@ -986,9 +983,9 @@ window.qBittorrent.DynamicTable ??= (() => { // update context menu this.contextMenu?.addTarget(tr); return tr; - }, + } - updateRowElement: function(tr, rowId, top) { + updateRowElement(tr, rowId, top) { tr.dataset.rowId = rowId; tr.rowId = rowId; @@ -998,9 +995,9 @@ window.qBittorrent.DynamicTable ??= (() => { tr.style.position = "absolute"; tr.style.top = `${top}px`; } - }, + } - updateRow: function(tr, fullUpdate) { + updateRow(tr, fullUpdate) { const row = this.rows.get(tr.rowId); const data = row[fullUpdate ? "full_data" : "data"]; @@ -1015,9 +1012,9 @@ window.qBittorrent.DynamicTable ??= (() => { this.columns[i].updateTd(tds[i], row); } row["data"] = {}; - }, + } - removeRow: function(rowId) { + removeRow(rowId) { this.selectedRows.erase(rowId); this.rows.delete(rowId); if (this.useVirtualList) { @@ -1027,9 +1024,9 @@ window.qBittorrent.DynamicTable ??= (() => { const tr = this.getTrByRowId(rowId); tr?.destroy(); } - }, + } - clear: function() { + clear() { this.deselectAll(); this.rows.clear(); if (this.useVirtualList) { @@ -1039,29 +1036,29 @@ window.qBittorrent.DynamicTable ??= (() => { for (const tr of this.getTrs()) tr.destroy(); } - }, + } - selectedRowsIds: function() { + selectedRowsIds() { return this.selectedRows.slice(); - }, + } - getRowIds: function() { + getRowIds() { return this.rows.keys(); - }, + } - getRowValues: function() { + getRowValues() { return this.rows.values(); - }, + } - getRowItems: function() { + getRowItems() { return this.rows.entries(); - }, + } - getRowSize: function() { + getRowSize() { return this.rows.size; - }, + } - selectNextRow: function() { + selectNextRow() { const visibleRows = Array.prototype.filter.call(this.getTrs(), (tr => !tr.classList.contains("invisible") && (tr.style.display !== "none"))); const selectedRowId = this.getSelectedRowId(); @@ -1081,9 +1078,9 @@ window.qBittorrent.DynamicTable ??= (() => { const newRow = visibleRows[selectedIndex + 1]; this.selectRow(newRow.getAttribute("data-row-id")); } - }, + } - selectPreviousRow: function() { + selectPreviousRow() { const visibleRows = Array.prototype.filter.call(this.getTrs(), (tr => !tr.classList.contains("invisible") && (tr.style.display !== "none"))); const selectedRowId = this.getSelectedRowId(); @@ -1103,19 +1100,16 @@ window.qBittorrent.DynamicTable ??= (() => { const newRow = visibleRows[selectedIndex - 1]; this.selectRow(newRow.getAttribute("data-row-id")); } - }, - }); - - const TorrentsTable = new Class({ - Extends: DynamicTable, - - setupVirtualList: function() { - this.parent(); + } + } + class TorrentsTable extends DynamicTable { + setupVirtualList() { + super.setupVirtualList(); this.rowHeight = 22; - }, + } - initColumns: function() { + initColumns() { this.newColumn("priority", "", "#", 30, true); this.newColumn("state_icon", "", "QBT_TR(Status Icon)QBT_TR[CONTEXT=TransferListModel]", 30, false); this.newColumn("name", "", "QBT_TR(Name)QBT_TR[CONTEXT=TransferListModel]", 200, true); @@ -1162,9 +1156,9 @@ window.qBittorrent.DynamicTable ??= (() => { this.columns["time_active"].dataProperties.push("seeding_time"); this.initColumnsFunctions(); - }, + } - initColumnsFunctions: function() { + initColumnsFunctions() { const getStateIconClasses = (state) => { let stateClass = "stateUnknown"; // normalize states @@ -1583,9 +1577,9 @@ window.qBittorrent.DynamicTable ??= (() => { td.textContent = string; td.title = string; }; - }, + } - applyFilter: (row, filterName, category, tag, tracker, filterTerms) => { + applyFilter(row, filterName, category, tag, tracker, filterTerms) { const state = row["full_data"].state; let inactive = false; @@ -1733,9 +1727,9 @@ window.qBittorrent.DynamicTable ??= (() => { } return true; - }, + } - getFilteredTorrentsNumber: function(filterName, category, tag, tracker) { + getFilteredTorrentsNumber(filterName, category, tag, tracker) { let cnt = 0; for (const row of this.rows.values()) { @@ -1743,9 +1737,9 @@ window.qBittorrent.DynamicTable ??= (() => { ++cnt; } return cnt; - }, + } - getFilteredTorrentsHashes: function(filterName, category, tag, tracker) { + getFilteredTorrentsHashes(filterName, category, tag, tracker) { const rowsHashes = []; const useRegex = document.getElementById("torrentsFilterRegexBox").checked; const filterText = document.getElementById("torrentsFilterInput").value.trim().toLowerCase(); @@ -1765,9 +1759,9 @@ window.qBittorrent.DynamicTable ??= (() => { } return rowsHashes; - }, + } - getFilteredAndSortedRows: function() { + getFilteredAndSortedRows() { const filteredRows = []; const useRegex = document.getElementById("torrentsFilterRegexBox").checked; @@ -1798,10 +1792,10 @@ window.qBittorrent.DynamicTable ??= (() => { return -res; }); return filteredRows; - }, + } - setupCommonEvents: function() { - this.parent(); + setupCommonEvents() { + super.setupCommonEvents(); this.dynamicTableDiv.addEventListener("dblclick", (e) => { const tr = e.target.closest("tr"); if (!tr) @@ -1830,21 +1824,19 @@ window.qBittorrent.DynamicTable ??= (() => { else stopFN(); }); - }, + } - getCurrentTorrentID: function() { + getCurrentTorrentID() { return this.getSelectedRowId(); - }, + } - onSelectedRowChanged: () => { + onSelectedRowChanged() { updatePropertiesPanel(); } - }); + } - const TorrentPeersTable = new Class({ - Extends: DynamicTable, - - initColumns: function() { + class TorrentPeersTable extends DynamicTable { + initColumns() { this.newColumn("country", "", "QBT_TR(Country/Region)QBT_TR[CONTEXT=PeerListWidget]", 22, true); this.newColumn("ip", "", "QBT_TR(IP)QBT_TR[CONTEXT=PeerListWidget]", 80, true); this.newColumn("port", "", "QBT_TR(Port)QBT_TR[CONTEXT=PeerListWidget]", 35, true); @@ -1863,10 +1855,9 @@ window.qBittorrent.DynamicTable ??= (() => { this.columns["country"].dataProperties.push("country_code"); this.columns["flags"].dataProperties.push("flags_desc"); this.initColumnsFunctions(); - }, - - initColumnsFunctions: function() { + } + initColumnsFunctions() { // country this.columns["country"].updateTd = function(td, row) { const country = this.getRowValue(row, 0); @@ -1949,12 +1940,10 @@ window.qBittorrent.DynamicTable ??= (() => { }; } - }); + } - const SearchResultsTable = new Class({ - Extends: DynamicTable, - - initColumns: function() { + class SearchResultsTable extends DynamicTable { + initColumns() { this.newColumn("fileName", "", "QBT_TR(Name)QBT_TR[CONTEXT=SearchResultsTable]", 500, true); this.newColumn("fileSize", "", "QBT_TR(Size)QBT_TR[CONTEXT=SearchResultsTable]", 100, true); this.newColumn("nbSeeders", "", "QBT_TR(Seeders)QBT_TR[CONTEXT=SearchResultsTable]", 100, true); @@ -1964,9 +1953,9 @@ window.qBittorrent.DynamicTable ??= (() => { this.newColumn("pubDate", "", "QBT_TR(Published On)QBT_TR[CONTEXT=SearchResultsTable]", 200, true); this.initColumnsFunctions(); - }, + } - initColumnsFunctions: function() { + initColumnsFunctions() { const displaySize = function(td, row) { const size = window.qBittorrent.Misc.friendlyUnit(this.getRowValue(row), false); td.textContent = size; @@ -1989,9 +1978,9 @@ window.qBittorrent.DynamicTable ??= (() => { this.columns["nbSeeders"].updateTd = displayNum; this.columns["nbLeechers"].updateTd = displayNum; this.columns["pubDate"].updateTd = displayDate; - }, + } - getFilteredAndSortedRows: function() { + getFilteredAndSortedRows() { const getSizeFilters = () => { let minSize = (window.qBittorrent.Search.searchSizeFilter.min > 0.00) ? (window.qBittorrent.Search.searchSizeFilter.min * Math.pow(1024, window.qBittorrent.Search.searchSizeFilter.minUnit)) : 0.00; let maxSize = (window.qBittorrent.Search.searchSizeFilter.max > 0.00) ? (window.qBittorrent.Search.searchSizeFilter.max * Math.pow(1024, window.qBittorrent.Search.searchSizeFilter.maxUnit)) : 0.00; @@ -2064,22 +2053,20 @@ window.qBittorrent.DynamicTable ??= (() => { }); return filteredRows; - }, - }); + } + } - const SearchPluginsTable = new Class({ - Extends: DynamicTable, - - initColumns: function() { + class SearchPluginsTable extends DynamicTable { + initColumns() { this.newColumn("fullName", "", "QBT_TR(Name)QBT_TR[CONTEXT=SearchPluginsTable]", 175, true); this.newColumn("version", "", "QBT_TR(Version)QBT_TR[CONTEXT=SearchPluginsTable]", 100, true); this.newColumn("url", "", "QBT_TR(Url)QBT_TR[CONTEXT=SearchPluginsTable]", 175, true); this.newColumn("enabled", "", "QBT_TR(Enabled)QBT_TR[CONTEXT=SearchPluginsTable]", 100, true); this.initColumnsFunctions(); - }, + } - initColumnsFunctions: function() { + initColumnsFunctions() { this.columns["enabled"].updateTd = function(td, row) { const value = this.getRowValue(row); if (value) { @@ -2095,13 +2082,11 @@ window.qBittorrent.DynamicTable ??= (() => { td.closest("tr").classList.remove("green"); } }; - }, - }); + } + } - const TorrentTrackersTable = new Class({ - Extends: DynamicTable, - - initColumns: function() { + class TorrentTrackersTable extends DynamicTable { + initColumns() { this.newColumn("tier", "", "QBT_TR(Tier)QBT_TR[CONTEXT=TrackerListWidget]", 35, true); this.newColumn("url", "", "QBT_TR(URL)QBT_TR[CONTEXT=TrackerListWidget]", 250, true); this.newColumn("status", "", "QBT_TR(Status)QBT_TR[CONTEXT=TrackerListWidget]", 125, true); @@ -2112,9 +2097,9 @@ window.qBittorrent.DynamicTable ??= (() => { this.newColumn("message", "", "QBT_TR(Message)QBT_TR[CONTEXT=TrackerListWidget]", 250, true); this.initColumnsFunctions(); - }, + } - initColumnsFunctions: function() { + initColumnsFunctions() { const naturalSort = function(row1, row2) { if (!row1.full_data._sortable || !row2.full_data._sortable) return 0; @@ -2191,33 +2176,30 @@ window.qBittorrent.DynamicTable ??= (() => { td.title = status; }; } - }); + } - const BulkRenameTorrentFilesTable = new Class({ - Extends: DynamicTable, - - filterTerms: [], - prevFilterTerms: [], - prevRowsString: null, - prevFilteredRows: [], - prevSortedColumn: null, - prevReverseSort: null, - fileTree: new window.qBittorrent.FileTree.FileTree(), - - setupVirtualList: function() { - this.parent(); + class BulkRenameTorrentFilesTable extends DynamicTable { + filterTerms = []; + prevFilterTerms = []; + prevRowsString = null; + prevFilteredRows = []; + prevSortedColumn = null; + prevReverseSort = null; + fileTree = new window.qBittorrent.FileTree.FileTree(); + setupVirtualList() { + super.setupVirtualList(); this.rowHeight = 29; - }, + } - populateTable: function(root) { + populateTable(root) { this.fileTree.setRoot(root); root.children.each((node) => { this._addNodeToTable(node, 0); }); - }, + } - _addNodeToTable: function(node, depth) { + _addNodeToTable(node, depth) { node.depth = depth; if (node.isFolder) { @@ -2243,28 +2225,28 @@ window.qBittorrent.DynamicTable ??= (() => { node.children.each((child) => { this._addNodeToTable(child, depth + 1); }); - }, + } - getRoot: function() { + getRoot() { return this.fileTree.getRoot(); - }, + } - getNode: function(rowId) { + getNode(rowId) { return this.fileTree.getNode(rowId); - }, + } - getRow: function(node) { + getRow(node) { const rowId = this.fileTree.getRowId(node).toString(); return this.rows.get(rowId); - }, + } - getSelectedRows: function() { + getSelectedRows() { const nodes = this.fileTree.toArray(); return nodes.filter(x => x.checked === 0); - }, + } - initColumns: function() { + initColumns() { // Blocks saving header width (because window width isn't saved) LocalPreferences.remove(`column_checked_width_${this.dynamicTableDivId}`); LocalPreferences.remove(`column_original_width_${this.dynamicTableDivId}`); @@ -2274,12 +2256,12 @@ window.qBittorrent.DynamicTable ??= (() => { this.newColumn("renamed", "", "QBT_TR(Renamed)QBT_TR[CONTEXT=TrackerListWidget]", 220, true); this.initColumnsFunctions(); - }, + } /** * Toggles the global checkbox and all checkboxes underneath */ - toggleGlobalCheckbox: function() { + toggleGlobalCheckbox() { const checkbox = document.getElementById("rootMultiRename_cb"); const checkboxes = document.querySelectorAll("input.RenamingCB"); @@ -2305,9 +2287,9 @@ window.qBittorrent.DynamicTable ??= (() => { } this.updateGlobalCheckbox(); - }, + } - toggleNodeTreeCheckbox: function(rowId, checkState) { + toggleNodeTreeCheckbox(rowId, checkState) { const node = this.getNode(rowId); node.checked = checkState; node.full_data.checked = checkState; @@ -2317,9 +2299,9 @@ window.qBittorrent.DynamicTable ??= (() => { for (let i = 0; i < node.children.length; ++i) this.toggleNodeTreeCheckbox(node.children[i].rowId, checkState); - }, + } - updateGlobalCheckbox: function() { + updateGlobalCheckbox() { const checkbox = document.getElementById("rootMultiRename_cb"); const nodes = this.fileTree.toArray(); const isAllChecked = nodes.every((node) => node.checked === 0); @@ -2339,9 +2321,9 @@ window.qBittorrent.DynamicTable ??= (() => { checkbox.indeterminate = true; checkbox.checked = false; } - }, + } - initColumnsFunctions: function() { + initColumnsFunctions() { const that = this; // checked @@ -2426,15 +2408,13 @@ window.qBittorrent.DynamicTable ??= (() => { span.id = fileNameRenamedId; span.textContent = node.renamed; }; - }, + } - onRowSelectionChange: (row) => {}, + onRowSelectionChange(row) {} - selectRow: () => { - return; - }, + selectRow() {} - reselectRows: function(rowIds) { + reselectRows(rowIds) { this.deselectAll(); for (const tr of this.getTrs()) { if (rowIds.includes(tr.rowId)) { @@ -2449,9 +2429,9 @@ window.qBittorrent.DynamicTable ??= (() => { } } this.updateGlobalCheckbox(); - }, + } - _sortNodesByColumn: function(nodes, column) { + _sortNodesByColumn(nodes, column) { nodes.sort((row1, row2) => { // list folders before files when sorting by name if (column.name === "original") { @@ -2471,9 +2451,9 @@ window.qBittorrent.DynamicTable ??= (() => { if (node.children.length > 0) this._sortNodesByColumn(node.children, column); }); - }, + } - _filterNodes: function(node, filterTerms, filteredRows) { + _filterNodes(node, filterTerms, filteredRows) { if (node.isFolder) { const childAdded = node.children.reduce((acc, child) => { // we must execute the function before ORing w/ acc or we'll stop checking child nodes after the first successful match @@ -2494,17 +2474,17 @@ window.qBittorrent.DynamicTable ??= (() => { } return false; - }, + } - setFilter: function(text) { + setFilter(text) { const filterTerms = text.trim().toLowerCase().split(" "); if ((filterTerms.length === 1) && (filterTerms[0] === "")) this.filterTerms = []; else this.filterTerms = filterTerms; - }, + } - getFilteredAndSortedRows: function() { + getFilteredAndSortedRows() { if (this.getRoot() === null) return []; @@ -2560,17 +2540,17 @@ window.qBittorrent.DynamicTable ??= (() => { this.prevSortedColumn = this.sortedColumn; this.prevReverseSort = this.reverseSort; return filteredRows; - }, + } - setIgnored: function(rowId, ignore) { + setIgnored(rowId, ignore) { const row = this.rows.get(rowId); if (ignore) row.full_data.remaining = 0; else row.full_data.remaining = (row.full_data.size * (1.0 - (row.full_data.progress / 100))); - }, + } - setupCommonEvents: function() { + setupCommonEvents() { const headerDiv = document.getElementById("bulkRenameFilesTableFixedHeaderDiv"); this.dynamicTableDiv.addEventListener("scroll", (e) => { headerDiv.scrollLeft = this.dynamicTableDiv.scrollLeft; @@ -2579,64 +2559,59 @@ window.qBittorrent.DynamicTable ??= (() => { this.rerender(); }); } - }); + } - const TorrentFilesTable = new Class({ - Extends: DynamicTable, + class TorrentFilesTable extends DynamicTable { + filterTerms = []; + prevFilterTerms = []; + prevRowsString = null; + prevFilteredRows = []; + prevSortedColumn = null; + prevReverseSort = null; + fileTree = new window.qBittorrent.FileTree.FileTree(); + collapseState = new Map(); - filterTerms: [], - prevFilterTerms: [], - prevRowsString: null, - prevFilteredRows: [], - prevSortedColumn: null, - prevReverseSort: null, - fileTree: new window.qBittorrent.FileTree.FileTree(), - - initialize: function() { - this.collapseState = new Map(); - }, - - isCollapsed: function(id) { + isCollapsed(id) { return this.collapseState.get(id)?.collapsed ?? false; - }, + } - expandNode: function(id) { + expandNode(id) { const state = this.collapseState.get(id); if (state !== undefined) state.collapsed = false; this._updateNodeState(id, false); - }, + } - collapseNode: function(id) { + collapseNode(id) { const state = this.collapseState.get(id); if (state !== undefined) state.collapsed = true; this._updateNodeState(id, true); - }, + } - expandAllNodes: function() { + expandAllNodes() { for (const [key, _] of this.collapseState) this.expandNode(key); - }, + } - collapseAllNodes: function() { + collapseAllNodes() { for (const [key, state] of this.collapseState) { // collapse all nodes except root if (state.depth >= 1) this.collapseNode(key); } - }, + } - _updateNodeVisibility: (node, shouldHide) => { + _updateNodeVisibility(node, shouldHide) { const span = document.getElementById(`filesTablefileName${node.rowId}`); // span won't exist if row has been filtered out if (span === null) return; const tr = span.parentElement.parentElement; tr.classList.toggle("invisible", shouldHide); - }, + } - _updateNodeCollapseIcon: (node, isCollapsed) => { + _updateNodeCollapseIcon(node, isCollapsed) { const span = document.getElementById(`filesTablefileName${node.rowId}`); // span won't exist if row has been filtered out if (span === null) @@ -2646,9 +2621,9 @@ window.qBittorrent.DynamicTable ??= (() => { // rotate the collapse icon const collapseIcon = td.firstElementChild; collapseIcon.classList.toggle("rotate", isCollapsed); - }, + } - _updateNodeState: function(id, shouldCollapse) { + _updateNodeState(id, shouldCollapse) { // collapsed rows will be filtered out when using virtual list if (this.useVirtualList) return; @@ -2659,9 +2634,9 @@ window.qBittorrent.DynamicTable ??= (() => { this._updateNodeCollapseIcon(node, shouldCollapse); this._updateNodeChildVisibility(node, shouldCollapse); - }, + } - _updateNodeChildVisibility: function(root, shouldHide) { + _updateNodeChildVisibility(root, shouldHide) { const stack = [...root.children]; while (stack.length > 0) { const node = stack.pop(); @@ -2670,48 +2645,46 @@ window.qBittorrent.DynamicTable ??= (() => { stack.push(...node.children); } - }, - - clear: function() { - this.parent(); + } + clear() { + super.clear(); this.collapseState.clear(); - }, - - setupVirtualList: function() { - this.parent(); + } + setupVirtualList() { + super.setupVirtualList(); this.rowHeight = 29.5; - }, + } - expandFolder: function(id) { + expandFolder(id) { const node = this.getNode(id); if (node.isFolder) this.expandNode(node); - }, + } - collapseFolder: function(id) { + collapseFolder(id) { const node = this.getNode(id); if (node.isFolder) this.collapseNode(node); - }, + } - isAllCheckboxesChecked: function() { + isAllCheckboxesChecked() { return this.fileTree.toArray().every((node) => node.checked === 1); - }, + } - isAllCheckboxesUnchecked: function() { + isAllCheckboxesUnchecked() { return this.fileTree.toArray().every((node) => node.checked !== 1); - }, + } - populateTable: function(root) { + populateTable(root) { this.fileTree.setRoot(root); root.children.each((node) => { this._addNodeToTable(node, 0); }); - }, + } - _addNodeToTable: function(node, depth) { + _addNodeToTable(node, depth) { node.depth = depth; if (node.isFolder) { @@ -2742,27 +2715,27 @@ window.qBittorrent.DynamicTable ??= (() => { node.children.each((child) => { this._addNodeToTable(child, depth + 1); }); - }, + } - getRoot: function() { + getRoot() { return this.fileTree.getRoot(); - }, + } - getNode: function(rowId) { + getNode(rowId) { return this.fileTree.getNode(rowId); - }, + } - getRow: function(node) { + getRow(node) { const rowId = this.fileTree.getRowId(node).toString(); return this.rows.get(rowId); - }, + } - getRowFileId: function(rowId) { + getRowFileId(rowId) { const row = this.rows.get(rowId); return row?.full_data.fileId; - }, + } - initColumns: function() { + initColumns() { this.newColumn("checked", "", "", 50, true); this.newColumn("name", "", "QBT_TR(Name)QBT_TR[CONTEXT=TrackerListWidget]", 300, true); this.newColumn("size", "", "QBT_TR(Total Size)QBT_TR[CONTEXT=TrackerListWidget]", 75, true); @@ -2772,9 +2745,9 @@ window.qBittorrent.DynamicTable ??= (() => { this.newColumn("availability", "", "QBT_TR(Availability)QBT_TR[CONTEXT=TrackerListWidget]", 75, true); this.initColumnsFunctions(); - }, + } - initColumnsFunctions: function() { + initColumnsFunctions() { const that = this; const displaySize = function(td, row) { const size = window.qBittorrent.Misc.friendlyUnit(this.getRowValue(row), false); @@ -2906,9 +2879,9 @@ window.qBittorrent.DynamicTable ??= (() => { // remaining, availability this.columns["remaining"].updateTd = displaySize; this.columns["availability"].updateTd = displayPercentage; - }, + } - _sortNodesByColumn: function(nodes, column) { + _sortNodesByColumn(nodes, column) { nodes.sort((row1, row2) => { // list folders before files when sorting by name if (column.name === "name") { @@ -2928,9 +2901,9 @@ window.qBittorrent.DynamicTable ??= (() => { if (node.children.length > 0) this._sortNodesByColumn(node.children, column); }); - }, + } - _filterNodes: function(node, filterTerms, filteredRows) { + _filterNodes(node, filterTerms, filteredRows) { if (node.isFolder && (!this.useVirtualList || !this.isCollapsed(node.rowId))) { const childAdded = node.children.toReversed().reduce((acc, child) => { // we must execute the function before ORing w/ acc or we'll stop checking child nodes after the first successful match @@ -2951,17 +2924,17 @@ window.qBittorrent.DynamicTable ??= (() => { } return false; - }, + } - setFilter: function(text) { + setFilter(text) { const filterTerms = text.trim().toLowerCase().split(" "); if ((filterTerms.length === 1) && (filterTerms[0] === "")) this.filterTerms = []; else this.filterTerms = filterTerms; - }, + } - getFilteredAndSortedRows: function() { + getFilteredAndSortedRows() { if (this.getRoot() === null) return []; @@ -3009,18 +2982,18 @@ window.qBittorrent.DynamicTable ??= (() => { this.prevSortedColumn = this.sortedColumn; this.prevReverseSort = this.reverseSort; return filteredRows; - }, + } - setIgnored: function(rowId, ignore) { + setIgnored(rowId, ignore) { const row = this.rows.get(rowId.toString()); if (ignore) row.full_data.remaining = 0; else row.full_data.remaining = (row.full_data.size * (1.0 - (row.full_data.progress / 100))); - }, + } - setupCommonEvents: function() { - this.parent(); + setupCommonEvents() { + super.setupCommonEvents(); this.dynamicTableDiv.addEventListener("keydown", (e) => { const tr = e.target.closest("tr"); if (!tr) @@ -3038,11 +3011,10 @@ window.qBittorrent.DynamicTable ??= (() => { } }); } - }); + } - const RssFeedTable = new Class({ - Extends: DynamicTable, - initColumns: function() { + class RssFeedTable extends DynamicTable { + initColumns() { this.newColumn("state_icon", "", "", 30, true); this.newColumn("name", "", "QBT_TR(RSS feeds)QBT_TR[CONTEXT=FeedListWidget]", -1, true); @@ -3057,13 +3029,13 @@ window.qBittorrent.DynamicTable ??= (() => { td.textContent = value; td.title = value; }; - }, - setupHeaderMenu: () => {}, - setupHeaderEvents: () => {}, - getFilteredAndSortedRows: function() { + } + setupHeaderMenu() {} + setupHeaderEvents() {} + getFilteredAndSortedRows() { return [...this.getRowValues()]; - }, - selectRow: function(rowId) { + } + selectRow(rowId) { this.selectedRows.push(rowId); this.setRowClass(); this.onSelectedRowChanged(); @@ -3076,9 +3048,9 @@ window.qBittorrent.DynamicTable ??= (() => { } } window.qBittorrent.Rss.showRssFeed(path); - }, - setupCommonEvents: function() { - this.parent(); + } + setupCommonEvents() { + super.setupCommonEvents(); this.dynamicTableDiv.addEventListener("dblclick", (e) => { const tr = e.target.closest("tr"); if (!tr || (tr.rowId === "0")) @@ -3086,8 +3058,8 @@ window.qBittorrent.DynamicTable ??= (() => { window.qBittorrent.Rss.moveItem(this.getRow(tr.rowId).full_data.dataPath); }); - }, - updateRow: function(tr, fullUpdate) { + } + updateRow(tr, fullUpdate) { const row = this.rows.get(tr.rowId); const data = row[fullUpdate ? "full_data" : "data"]; @@ -3101,8 +3073,8 @@ window.qBittorrent.DynamicTable ??= (() => { const indentation = row.full_data.indentation; tds[0].style.paddingLeft = `${indentation * 32 + 4}px`; tds[1].style.paddingLeft = `${indentation * 32 + 4}px`; - }, - updateIcons: function() { + } + updateIcons() { // state_icon for (const row of this.getRowValues()) { let img_path; @@ -3146,8 +3118,8 @@ window.qBittorrent.DynamicTable ??= (() => { td.append(img); } } - }, - newColumn: function(name, style, caption, defaultWidth, defaultVisible) { + } + newColumn(name, style, caption, defaultWidth, defaultVisible) { const column = {}; column["name"] = name; column["title"] = name; @@ -3183,19 +3155,18 @@ window.qBittorrent.DynamicTable ??= (() => { this.hiddenTableHeader.append(document.createElement("th")); this.fixedTableHeader.append(document.createElement("th")); } - }); + } - const RssArticleTable = new Class({ - Extends: DynamicTable, - initColumns: function() { + class RssArticleTable extends DynamicTable { + initColumns() { this.newColumn("name", "", "QBT_TR(Torrents: (double-click to download))QBT_TR[CONTEXT=RSSWidget]", -1, true); - }, - setupHeaderMenu: () => {}, - setupHeaderEvents: () => {}, - getFilteredAndSortedRows: function() { + } + setupHeaderMenu() {} + setupHeaderEvents() {} + getFilteredAndSortedRows() { return [...this.getRowValues()]; - }, - selectRow: function(rowId) { + } + selectRow(rowId) { this.selectedRows.push(rowId); this.setRowClass(); this.onSelectedRowChanged(); @@ -3211,10 +3182,10 @@ window.qBittorrent.DynamicTable ??= (() => { } } window.qBittorrent.Rss.showDetails(feedUid, articleId); - }, + } - setupCommonEvents: function() { - this.parent(); + setupCommonEvents() { + super.setupCommonEvents(); this.dynamicTableDiv.addEventListener("dblclick", (e) => { const tr = e.target.closest("tr"); if (!tr) @@ -3222,8 +3193,8 @@ window.qBittorrent.DynamicTable ??= (() => { showDownloadPage([this.getRow(tr.rowId).full_data.torrentURL]); }); - }, - updateRow: function(tr, fullUpdate) { + } + updateRow(tr, fullUpdate) { const row = this.rows.get(tr.rowId); const data = row[fullUpdate ? "full_data" : "data"]; tr.classList.toggle("unreadArticle", !row.full_data.isRead); @@ -3234,8 +3205,8 @@ window.qBittorrent.DynamicTable ??= (() => { this.columns[i].updateTd(tds[i], row); } row["data"] = {}; - }, - newColumn: function(name, style, caption, defaultWidth, defaultVisible) { + } + newColumn(name, style, caption, defaultWidth, defaultVisible) { const column = {}; column["name"] = name; column["title"] = name; @@ -3271,11 +3242,10 @@ window.qBittorrent.DynamicTable ??= (() => { this.hiddenTableHeader.append(document.createElement("th")); this.fixedTableHeader.append(document.createElement("th")); } - }); + } - const RssDownloaderRulesTable = new Class({ - Extends: DynamicTable, - initColumns: function() { + class RssDownloaderRulesTable extends DynamicTable { + initColumns() { this.newColumn("checked", "", "", 30, true); this.newColumn("name", "", "", -1, true); @@ -3302,15 +3272,15 @@ window.qBittorrent.DynamicTable ??= (() => { } }; this.columns["checked"].staticWidth = 50; - }, - setupHeaderMenu: () => {}, - setupHeaderEvents: () => {}, - getFilteredAndSortedRows: function() { + } + setupHeaderMenu() {} + setupHeaderEvents() {} + getFilteredAndSortedRows() { return [...this.getRowValues()]; - }, + } - setupCommonEvents: function() { - this.parent(); + setupCommonEvents() { + super.setupCommonEvents(); this.dynamicTableDiv.addEventListener("dblclick", (e) => { const tr = e.target.closest("tr"); if (!tr) @@ -3318,8 +3288,8 @@ window.qBittorrent.DynamicTable ??= (() => { window.qBittorrent.RssDownloader.renameRule(this.getRow(tr.rowId).full_data.name); }); - }, - newColumn: function(name, style, caption, defaultWidth, defaultVisible) { + } + newColumn(name, style, caption, defaultWidth, defaultVisible) { const column = {}; column["name"] = name; column["title"] = name; @@ -3354,8 +3324,8 @@ window.qBittorrent.DynamicTable ??= (() => { this.hiddenTableHeader.append(document.createElement("th")); this.fixedTableHeader.append(document.createElement("th")); - }, - selectRow: function(rowId) { + } + selectRow(rowId) { this.selectedRows.push(rowId); this.setRowClass(); this.onSelectedRowChanged(); @@ -3369,11 +3339,10 @@ window.qBittorrent.DynamicTable ??= (() => { } window.qBittorrent.RssDownloader.showRule(name); } - }); + } - const RssDownloaderFeedSelectionTable = new Class({ - Extends: DynamicTable, - initColumns: function() { + class RssDownloaderFeedSelectionTable extends DynamicTable { + initColumns() { this.newColumn("checked", "", "", 30, true); this.newColumn("name", "", "", -1, true); @@ -3399,13 +3368,13 @@ window.qBittorrent.DynamicTable ??= (() => { } }; this.columns["checked"].staticWidth = 50; - }, - setupHeaderMenu: () => {}, - setupHeaderEvents: () => {}, - getFilteredAndSortedRows: function() { + } + setupHeaderMenu() {} + setupHeaderEvents() {} + getFilteredAndSortedRows() { return [...this.getRowValues()]; - }, - newColumn: function(name, style, caption, defaultWidth, defaultVisible) { + } + newColumn(name, style, caption, defaultWidth, defaultVisible) { const column = {}; column["name"] = name; column["title"] = name; @@ -3440,21 +3409,20 @@ window.qBittorrent.DynamicTable ??= (() => { this.hiddenTableHeader.append(document.createElement("th")); this.fixedTableHeader.append(document.createElement("th")); - }, - selectRow: () => {} - }); + } + selectRow() {} + } - const RssDownloaderArticlesTable = new Class({ - Extends: DynamicTable, - initColumns: function() { + class RssDownloaderArticlesTable extends DynamicTable { + initColumns() { this.newColumn("name", "", "", -1, true); - }, - setupHeaderMenu: () => {}, - setupHeaderEvents: () => {}, - getFilteredAndSortedRows: function() { + } + setupHeaderMenu() {} + setupHeaderEvents() {} + getFilteredAndSortedRows() { return [...this.getRowValues()]; - }, - newColumn: function(name, style, caption, defaultWidth, defaultVisible) { + } + newColumn(name, style, caption, defaultWidth, defaultVisible) { const column = {}; column["name"] = name; column["title"] = name; @@ -3489,9 +3457,9 @@ window.qBittorrent.DynamicTable ??= (() => { this.hiddenTableHeader.append(document.createElement("th")); this.fixedTableHeader.append(document.createElement("th")); - }, - selectRow: () => {}, - updateRow: function(tr, fullUpdate) { + } + selectRow() {} + updateRow(tr, fullUpdate) { const row = this.rows.get(tr.rowId); const data = row[fullUpdate ? "full_data" : "data"]; @@ -3511,22 +3479,20 @@ window.qBittorrent.DynamicTable ??= (() => { } row["data"] = {}; } - }); + } - const LogMessageTable = new Class({ - Extends: DynamicTable, + class LogMessageTable extends DynamicTable { + filterText = ""; - filterText: "", - - initColumns: function() { + initColumns() { this.newColumn("rowId", "", "QBT_TR(ID)QBT_TR[CONTEXT=ExecutionLogWidget]", 50, true); this.newColumn("message", "", "QBT_TR(Message)QBT_TR[CONTEXT=ExecutionLogWidget]", 350, true); this.newColumn("timestamp", "", "QBT_TR(Timestamp)QBT_TR[CONTEXT=ExecutionLogWidget]", 150, true); this.newColumn("type", "", "QBT_TR(Log Type)QBT_TR[CONTEXT=ExecutionLogWidget]", 100, true); this.initColumnsFunctions(); - }, + } - initColumnsFunctions: function() { + initColumnsFunctions() { this.columns["timestamp"].updateTd = function(td, row) { const date = new Date(this.getRowValue(row) * 1000).toLocaleString(); td.textContent = date; @@ -3562,9 +3528,9 @@ window.qBittorrent.DynamicTable ??= (() => { td.title = logLevel; td.closest("tr").classList.add(`logTableRow${addClass}`); }; - }, + } - getFilteredAndSortedRows: function() { + getFilteredAndSortedRows() { let filteredRows = []; this.filterText = window.qBittorrent.Log.getFilterText(); const filterTerms = (this.filterText.length > 0) ? this.filterText.toLowerCase().split(" ") : []; @@ -3593,13 +3559,11 @@ window.qBittorrent.DynamicTable ??= (() => { this.filteredLength = filteredRows.length; return filteredRows; - }, - }); + } + } - const LogPeerTable = new Class({ - Extends: LogMessageTable, - - initColumns: function() { + class LogPeerTable extends LogMessageTable { + initColumns() { this.newColumn("rowId", "", "QBT_TR(ID)QBT_TR[CONTEXT=ExecutionLogWidget]", 50, true); this.newColumn("ip", "", "QBT_TR(IP)QBT_TR[CONTEXT=ExecutionLogWidget]", 150, true); this.newColumn("timestamp", "", "QBT_TR(Timestamp)QBT_TR[CONTEXT=ExecutionLogWidget]", 150, true); @@ -3626,9 +3590,9 @@ window.qBittorrent.DynamicTable ??= (() => { td.title = status; td.closest("tr").classList.add(`logTableRow${addClass}`); }; - }, + } - getFilteredAndSortedRows: function() { + getFilteredAndSortedRows() { let filteredRows = []; this.filterText = window.qBittorrent.Log.getFilterText(); const filterTerms = (this.filterText.length > 0) ? this.filterText.toLowerCase().split(" ") : []; @@ -3652,20 +3616,16 @@ window.qBittorrent.DynamicTable ??= (() => { return filteredRows; } - }); + } - const TorrentWebseedsTable = new Class({ - Extends: DynamicTable, - - initColumns: function() { + class TorrentWebseedsTable extends DynamicTable { + initColumns() { this.newColumn("url", "", "QBT_TR(URL)QBT_TR[CONTEXT=HttpServer]", 500, true); - }, - }); + } + } - const TorrentCreationTasksTable = new Class({ - Extends: DynamicTable, - - initColumns: function() { + class TorrentCreationTasksTable extends DynamicTable { + initColumns() { this.newColumn("state_icon", "", "QBT_TR(Status Icon)QBT_TR[CONTEXT=TorrentCreator]", 30, false); this.newColumn("source_path", "", "QBT_TR(Source Path)QBT_TR[CONTEXT=TorrentCreator]", 200, true); this.newColumn("progress", "", "QBT_TR(Progress)QBT_TR[CONTEXT=TorrentCreator]", 85, true); @@ -3686,9 +3646,9 @@ window.qBittorrent.DynamicTable ??= (() => { this.columns["source_path"].dataProperties.push("status"); this.initColumnsFunctions(); - }, + } - initColumnsFunctions: function() { + initColumnsFunctions() { const getStateIconClasses = (state) => { let stateClass = "stateUnknown"; // normalize states @@ -3864,10 +3824,10 @@ window.qBittorrent.DynamicTable ??= (() => { this.columns["added_on"].updateTd = displayDate; this.columns["start_on"].updateTd = displayDate; this.columns["completion_on"].updateTd = displayDate; - }, + } - setupCommonEvents: function() { - this.parent(); + setupCommonEvents() { + super.setupCommonEvents(); this.dynamicTableDiv.addEventListener("dblclick", (e) => { const tr = e.target.closest("tr"); if (!tr) @@ -3878,8 +3838,8 @@ window.qBittorrent.DynamicTable ??= (() => { window.qBittorrent.TorrentCreator.exportTorrents(); }); - }, - }); + } + } return exports(); })(); From bb68a39b530e81858478b801c24a75914964d4a5 Mon Sep 17 00:00:00 2001 From: skomerko <168652295+skomerko@users.noreply.github.com> Date: Tue, 29 Apr 2025 19:58:23 +0200 Subject: [PATCH 12/45] WebUI: Prefix private properties with # in dynamic table classes --- src/webui/www/private/scripts/dynamicTable.js | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index c23606140..fdbbca346 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -293,7 +293,7 @@ window.qBittorrent.DynamicTable ??= (() => { if (width < 16) width = 16; - this._setColumnWidth(this.resizeTh.columnName, width); + this.#setColumnWidth(this.resizeTh.columnName, width); } }.bind(this); @@ -393,7 +393,7 @@ window.qBittorrent.DynamicTable ??= (() => { this.columns[columnName].onVisibilityChange?.(columnName); } - _calculateColumnBodyWidth(column) { + #calculateColumnBodyWidth(column) { const columnIndex = this.getColumnPos(column.name); const bodyColumn = document.getElementById(this.dynamicTableDivId).querySelectorAll("tr>th")[columnIndex]; const canvas = document.createElement("canvas"); @@ -417,7 +417,7 @@ window.qBittorrent.DynamicTable ??= (() => { return longestTd.width + 10; } - _setColumnWidth(columnName, width) { + #setColumnWidth(columnName, width) { const column = this.columns[columnName]; column.width = width; @@ -438,7 +438,7 @@ window.qBittorrent.DynamicTable ??= (() => { let width = column.staticWidth ?? 0; if (column.staticWidth === null) { // check required min body width - const bodyTextWidth = this._calculateColumnBodyWidth(column); + const bodyTextWidth = this.#calculateColumnBodyWidth(column); // check required min header width const columnIndex = this.getColumnPos(column.name); @@ -453,7 +453,7 @@ window.qBittorrent.DynamicTable ??= (() => { width = Math.max(headTextWidth, bodyTextWidth); } - this._setColumnWidth(column.name, width); + this.#setColumnWidth(column.name, width); this.saveColumnWidth(column.name); } @@ -2195,11 +2195,11 @@ window.qBittorrent.DynamicTable ??= (() => { populateTable(root) { this.fileTree.setRoot(root); root.children.each((node) => { - this._addNodeToTable(node, 0); + this.#addNodeToTable(node, 0); }); } - _addNodeToTable(node, depth) { + #addNodeToTable(node, depth) { node.depth = depth; if (node.isFolder) { @@ -2223,7 +2223,7 @@ window.qBittorrent.DynamicTable ??= (() => { } node.children.each((child) => { - this._addNodeToTable(child, depth + 1); + this.#addNodeToTable(child, depth + 1); }); } @@ -2431,7 +2431,7 @@ window.qBittorrent.DynamicTable ??= (() => { this.updateGlobalCheckbox(); } - _sortNodesByColumn(nodes, column) { + #sortNodesByColumn(nodes, column) { nodes.sort((row1, row2) => { // list folders before files when sorting by name if (column.name === "original") { @@ -2449,15 +2449,15 @@ window.qBittorrent.DynamicTable ??= (() => { nodes.each((node) => { if (node.children.length > 0) - this._sortNodesByColumn(node.children, column); + this.#sortNodesByColumn(node.children, column); }); } - _filterNodes(node, filterTerms, filteredRows) { + #filterNodes(node, filterTerms, filteredRows) { if (node.isFolder) { const childAdded = node.children.reduce((acc, child) => { // we must execute the function before ORing w/ acc or we'll stop checking child nodes after the first successful match - return (this._filterNodes(child, filterTerms, filteredRows) || acc); + return (this.#filterNodes(child, filterTerms, filteredRows) || acc); }, false); if (childAdded) { @@ -2506,7 +2506,7 @@ window.qBittorrent.DynamicTable ??= (() => { const filteredRows = []; this.getRoot().children.each((child) => { - this._filterNodes(child, this.filterTerms, filteredRows); + this.#filterNodes(child, this.filterTerms, filteredRows); }); filteredRows.reverse(); return filteredRows; @@ -2531,7 +2531,7 @@ window.qBittorrent.DynamicTable ??= (() => { // sort, then filter const column = this.columns[this.sortedColumn]; - this._sortNodesByColumn(this.getRoot().children, column); + this.#sortNodesByColumn(this.getRoot().children, column); const filteredRows = getFilteredRows(); this.prevFilterTerms = this.filterTerms; @@ -2579,14 +2579,14 @@ window.qBittorrent.DynamicTable ??= (() => { const state = this.collapseState.get(id); if (state !== undefined) state.collapsed = false; - this._updateNodeState(id, false); + this.#updateNodeState(id, false); } collapseNode(id) { const state = this.collapseState.get(id); if (state !== undefined) state.collapsed = true; - this._updateNodeState(id, true); + this.#updateNodeState(id, true); } expandAllNodes() { @@ -2602,7 +2602,7 @@ window.qBittorrent.DynamicTable ??= (() => { } } - _updateNodeVisibility(node, shouldHide) { + #updateNodeVisibility(node, shouldHide) { const span = document.getElementById(`filesTablefileName${node.rowId}`); // span won't exist if row has been filtered out if (span === null) @@ -2611,7 +2611,7 @@ window.qBittorrent.DynamicTable ??= (() => { tr.classList.toggle("invisible", shouldHide); } - _updateNodeCollapseIcon(node, isCollapsed) { + #updateNodeCollapseIcon(node, isCollapsed) { const span = document.getElementById(`filesTablefileName${node.rowId}`); // span won't exist if row has been filtered out if (span === null) @@ -2623,7 +2623,7 @@ window.qBittorrent.DynamicTable ??= (() => { collapseIcon.classList.toggle("rotate", isCollapsed); } - _updateNodeState(id, shouldCollapse) { + #updateNodeState(id, shouldCollapse) { // collapsed rows will be filtered out when using virtual list if (this.useVirtualList) return; @@ -2631,17 +2631,17 @@ window.qBittorrent.DynamicTable ??= (() => { if (!node.isFolder) return; - this._updateNodeCollapseIcon(node, shouldCollapse); + this.#updateNodeCollapseIcon(node, shouldCollapse); - this._updateNodeChildVisibility(node, shouldCollapse); + this.#updateNodeChildVisibility(node, shouldCollapse); } - _updateNodeChildVisibility(root, shouldHide) { + #updateNodeChildVisibility(root, shouldHide) { const stack = [...root.children]; while (stack.length > 0) { const node = stack.pop(); - this._updateNodeVisibility(node, (shouldHide ? shouldHide : this.isCollapsed(node.root.rowId))); + this.#updateNodeVisibility(node, (shouldHide ? shouldHide : this.isCollapsed(node.root.rowId))); stack.push(...node.children); } @@ -2680,11 +2680,11 @@ window.qBittorrent.DynamicTable ??= (() => { populateTable(root) { this.fileTree.setRoot(root); root.children.each((node) => { - this._addNodeToTable(node, 0); + this.#addNodeToTable(node, 0); }); } - _addNodeToTable(node, depth) { + #addNodeToTable(node, depth) { node.depth = depth; if (node.isFolder) { @@ -2713,7 +2713,7 @@ window.qBittorrent.DynamicTable ??= (() => { } node.children.each((child) => { - this._addNodeToTable(child, depth + 1); + this.#addNodeToTable(child, depth + 1); }); } @@ -2881,7 +2881,7 @@ window.qBittorrent.DynamicTable ??= (() => { this.columns["availability"].updateTd = displayPercentage; } - _sortNodesByColumn(nodes, column) { + #sortNodesByColumn(nodes, column) { nodes.sort((row1, row2) => { // list folders before files when sorting by name if (column.name === "name") { @@ -2899,15 +2899,15 @@ window.qBittorrent.DynamicTable ??= (() => { nodes.each((node) => { if (node.children.length > 0) - this._sortNodesByColumn(node.children, column); + this.#sortNodesByColumn(node.children, column); }); } - _filterNodes(node, filterTerms, filteredRows) { + #filterNodes(node, filterTerms, filteredRows) { if (node.isFolder && (!this.useVirtualList || !this.isCollapsed(node.rowId))) { const childAdded = node.children.toReversed().reduce((acc, child) => { // we must execute the function before ORing w/ acc or we'll stop checking child nodes after the first successful match - return (this._filterNodes(child, filterTerms, filteredRows) || acc); + return (this.#filterNodes(child, filterTerms, filteredRows) || acc); }, false); if (childAdded) { @@ -2948,7 +2948,7 @@ window.qBittorrent.DynamicTable ??= (() => { const getFilteredRows = function() { const filteredRows = []; this.getRoot().children.each((child) => { - this._filterNodes(child, this.filterTerms, filteredRows); + this.#filterNodes(child, this.filterTerms, filteredRows); }); filteredRows.reverse(); return filteredRows; @@ -2973,7 +2973,7 @@ window.qBittorrent.DynamicTable ??= (() => { // sort, then filter const column = this.columns[this.sortedColumn]; - this._sortNodesByColumn(this.getRoot().children, column); + this.#sortNodesByColumn(this.getRoot().children, column); const filteredRows = getFilteredRows(); this.prevFilterTerms = this.filterTerms; From e7dee969e1fb2e7dfa2965ea6562702ce2f47070 Mon Sep 17 00:00:00 2001 From: Vladimir Golovnev Date: Thu, 1 May 2025 08:57:10 +0300 Subject: [PATCH 13/45] Remove dubious seeding time max value PR #22624. --- src/base/bittorrent/sessionimpl.cpp | 18 +++++++++--------- src/base/bittorrent/torrent.cpp | 2 -- src/base/bittorrent/torrent.h | 2 -- src/base/bittorrent/torrentimpl.cpp | 4 ---- src/webui/www/private/shareratio.html | 4 ++-- src/webui/www/private/views/preferences.html | 8 ++++---- 6 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/base/bittorrent/sessionimpl.cpp b/src/base/bittorrent/sessionimpl.cpp index f3d68cf5f..a6bf947f8 100644 --- a/src/base/bittorrent/sessionimpl.cpp +++ b/src/base/bittorrent/sessionimpl.cpp @@ -472,11 +472,11 @@ SessionImpl::SessionImpl(QObject *parent) , m_additionalTrackers(BITTORRENT_SESSION_KEY(u"AdditionalTrackers"_s)) , m_isAddTrackersFromURLEnabled(BITTORRENT_SESSION_KEY(u"AddTrackersFromURLEnabled"_s), false) , m_additionalTrackersURL(BITTORRENT_SESSION_KEY(u"AdditionalTrackersURL"_s)) - , m_globalMaxRatio(BITTORRENT_SESSION_KEY(u"GlobalMaxRatio"_s), -1, [](qreal r) { return r < 0 ? -1. : r;}) - , m_globalMaxSeedingMinutes(BITTORRENT_SESSION_KEY(u"GlobalMaxSeedingMinutes"_s), Torrent::NO_SEEDING_TIME_LIMIT - , clampValue(Torrent::NO_SEEDING_TIME_LIMIT, Torrent::MAX_SEEDING_TIME)) - , m_globalMaxInactiveSeedingMinutes(BITTORRENT_SESSION_KEY(u"GlobalMaxInactiveSeedingMinutes"_s), Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT - , clampValue(Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT, Torrent::MAX_INACTIVE_SEEDING_TIME)) + , m_globalMaxRatio(BITTORRENT_SESSION_KEY(u"GlobalMaxRatio"_s), -1, [](qreal r) { return r < 0 ? -1. : r; }) + , m_globalMaxSeedingMinutes(BITTORRENT_SESSION_KEY(u"GlobalMaxSeedingMinutes"_s) + , Torrent::NO_SEEDING_TIME_LIMIT, lowerLimited(Torrent::NO_SEEDING_TIME_LIMIT)) + , m_globalMaxInactiveSeedingMinutes(BITTORRENT_SESSION_KEY(u"GlobalMaxInactiveSeedingMinutes"_s) + , Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT, lowerLimited(Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT)) , m_isAddTorrentToQueueTop(BITTORRENT_SESSION_KEY(u"AddTorrentToTopOfQueue"_s), false) , m_isAddTorrentStopped(BITTORRENT_SESSION_KEY(u"AddTorrentStopped"_s), false) , m_torrentStopCondition(BITTORRENT_SESSION_KEY(u"TorrentStopCondition"_s), Torrent::StopCondition::None) @@ -1258,7 +1258,7 @@ int SessionImpl::globalMaxSeedingMinutes() const void SessionImpl::setGlobalMaxSeedingMinutes(int minutes) { - minutes = std::clamp(minutes, Torrent::NO_SEEDING_TIME_LIMIT, Torrent::MAX_SEEDING_TIME); + minutes = std::max(minutes, Torrent::NO_SEEDING_TIME_LIMIT); if (minutes != globalMaxSeedingMinutes()) { @@ -1274,7 +1274,7 @@ int SessionImpl::globalMaxInactiveSeedingMinutes() const void SessionImpl::setGlobalMaxInactiveSeedingMinutes(int minutes) { - minutes = std::clamp(minutes, Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT, Torrent::MAX_INACTIVE_SEEDING_TIME); + minutes = std::max(minutes, Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT); if (minutes != globalMaxInactiveSeedingMinutes()) { @@ -2337,13 +2337,13 @@ void SessionImpl::processTorrentShareLimits(TorrentImpl *torrent) description = tr("Torrent reached the share ratio limit."); } else if (const qlonglong seedingTimeInMinutes = torrent->finishedTime() / 60; - (seedingTimeLimit >= 0) && (seedingTimeInMinutes <= Torrent::MAX_SEEDING_TIME) && (seedingTimeInMinutes >= seedingTimeLimit)) + (seedingTimeLimit >= 0) && (seedingTimeInMinutes >= seedingTimeLimit)) { reached = true; description = tr("Torrent reached the seeding time limit."); } else if (const qlonglong inactiveSeedingTimeInMinutes = torrent->timeSinceActivity() / 60; - (inactiveSeedingTimeLimit >= 0) && (inactiveSeedingTimeInMinutes <= Torrent::MAX_INACTIVE_SEEDING_TIME) && (inactiveSeedingTimeInMinutes >= inactiveSeedingTimeLimit)) + (inactiveSeedingTimeLimit >= 0) && (inactiveSeedingTimeInMinutes >= inactiveSeedingTimeLimit)) { reached = true; description = tr("Torrent reached the inactive seeding time limit."); diff --git a/src/base/bittorrent/torrent.cpp b/src/base/bittorrent/torrent.cpp index c92fb9aea..1fdf52f61 100644 --- a/src/base/bittorrent/torrent.cpp +++ b/src/base/bittorrent/torrent.cpp @@ -52,8 +52,6 @@ namespace BitTorrent const int Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT = -1; const qreal Torrent::MAX_RATIO = 9999; - const int Torrent::MAX_SEEDING_TIME = 525600; - const int Torrent::MAX_INACTIVE_SEEDING_TIME = 525600; TorrentID Torrent::id() const { diff --git a/src/base/bittorrent/torrent.h b/src/base/bittorrent/torrent.h index fc817b86c..644af158b 100644 --- a/src/base/bittorrent/torrent.h +++ b/src/base/bittorrent/torrent.h @@ -134,8 +134,6 @@ namespace BitTorrent static const int NO_INACTIVE_SEEDING_TIME_LIMIT; static const qreal MAX_RATIO; - static const int MAX_SEEDING_TIME; - static const int MAX_INACTIVE_SEEDING_TIME; using TorrentContentHandler::TorrentContentHandler; diff --git a/src/base/bittorrent/torrentimpl.cpp b/src/base/bittorrent/torrentimpl.cpp index f4ae0e0fa..fb27c44dc 100644 --- a/src/base/bittorrent/torrentimpl.cpp +++ b/src/base/bittorrent/torrentimpl.cpp @@ -2692,8 +2692,6 @@ void TorrentImpl::setSeedingTimeLimit(int limit) { if (limit < USE_GLOBAL_SEEDING_TIME) limit = NO_SEEDING_TIME_LIMIT; - else if (limit > MAX_SEEDING_TIME) - limit = MAX_SEEDING_TIME; if (m_seedingTimeLimit != limit) { @@ -2707,8 +2705,6 @@ void TorrentImpl::setInactiveSeedingTimeLimit(int limit) { if (limit < USE_GLOBAL_INACTIVE_SEEDING_TIME) limit = NO_INACTIVE_SEEDING_TIME_LIMIT; - else if (limit > MAX_INACTIVE_SEEDING_TIME) - limit = MAX_SEEDING_TIME; if (m_inactiveSeedingTimeLimit != limit) { diff --git a/src/webui/www/private/shareratio.html b/src/webui/www/private/shareratio.html index 9205b7f76..56b70f25d 100644 --- a/src/webui/www/private/shareratio.html +++ b/src/webui/www/private/shareratio.html @@ -177,12 +177,12 @@
- +
- +
diff --git a/src/webui/www/private/views/preferences.html b/src/webui/www/private/views/preferences.html index ec27db3a3..c8ef9de78 100644 --- a/src/webui/www/private/views/preferences.html +++ b/src/webui/www/private/views/preferences.html @@ -2923,8 +2923,8 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD let maxSeedingTime = -1; if (document.getElementById("maxSeedingTimeCheckbox").checked) { maxSeedingTime = Number(document.getElementById("maxSeedingTimeValue").value); - if (Number.isNaN(maxSeedingTime) || (maxSeedingTime < 0) || (maxSeedingTime > 525600)) { - alert("QBT_TR(Seeding time limit must be between 0 and 525600 minutes.)QBT_TR[CONTEXT=HttpServer]"); + if (Number.isNaN(maxSeedingTime) || (maxSeedingTime < 0)) { + alert("QBT_TR(Seeding time limit must not have a negative value.)QBT_TR[CONTEXT=HttpServer]"); return; } } @@ -2934,8 +2934,8 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD let maxInactiveSeedingTime = -1; if (document.getElementById("maxInactiveSeedingTimeCheckbox").checked) { maxInactiveSeedingTime = Number(document.getElementById("maxInactiveSeedingTimeValue").value); - if (Number.isNaN(maxInactiveSeedingTime) || (maxInactiveSeedingTime < 0) || (maxInactiveSeedingTime > 525600)) { - alert("QBT_TR(Seeding time limit must be between 0 and 525600 minutes.)QBT_TR[CONTEXT=HttpServer]"); + if (Number.isNaN(maxInactiveSeedingTime) || (maxInactiveSeedingTime < 0)) { + alert("QBT_TR(Seeding time limit must not have a negative value.)QBT_TR[CONTEXT=HttpServer]"); return; } } From 6cd6267c26a7a7bf4575621603dc839a7cd19227 Mon Sep 17 00:00:00 2001 From: Vladimir Golovnev Date: Thu, 1 May 2025 14:18:18 +0300 Subject: [PATCH 14/45] Fix ratio handling PR #22638. --- src/base/bittorrent/sessionimpl.cpp | 4 ++-- src/base/bittorrent/torrent.cpp | 4 +++- src/base/bittorrent/torrentimpl.cpp | 5 ++--- src/gui/optionsdialog.ui | 3 --- src/gui/properties/propertieswidget.cpp | 4 ++-- src/gui/torrentsharelimitswidget.ui | 3 --- src/gui/transferlistmodel.cpp | 2 +- src/webui/api/serialize/serialize_torrent.cpp | 2 +- src/webui/api/torrentscontroller.cpp | 4 ++-- src/webui/www/private/shareratio.html | 2 +- src/webui/www/private/views/preferences.html | 4 ++-- 11 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src/base/bittorrent/sessionimpl.cpp b/src/base/bittorrent/sessionimpl.cpp index a6bf947f8..bc3fca77e 100644 --- a/src/base/bittorrent/sessionimpl.cpp +++ b/src/base/bittorrent/sessionimpl.cpp @@ -1242,7 +1242,7 @@ qreal SessionImpl::globalMaxRatio() const void SessionImpl::setGlobalMaxRatio(qreal ratio) { if (ratio < 0) - ratio = -1.; + ratio = Torrent::NO_RATIO_LIMIT; if (ratio != globalMaxRatio()) { @@ -2331,7 +2331,7 @@ void SessionImpl::processTorrentShareLimits(TorrentImpl *torrent) QString description; if (const qreal ratio = torrent->realRatio(); - (ratioLimit >= 0) && (ratio <= Torrent::MAX_RATIO) && (ratio >= ratioLimit)) + (ratioLimit >= 0) && (ratio >= ratioLimit)) { reached = true; description = tr("Torrent reached the share ratio limit."); diff --git a/src/base/bittorrent/torrent.cpp b/src/base/bittorrent/torrent.cpp index 1fdf52f61..b8098d77f 100644 --- a/src/base/bittorrent/torrent.cpp +++ b/src/base/bittorrent/torrent.cpp @@ -29,6 +29,8 @@ #include "torrent.h" +#include + #include #include "infohash.h" @@ -51,7 +53,7 @@ namespace BitTorrent const int Torrent::USE_GLOBAL_INACTIVE_SEEDING_TIME = -2; const int Torrent::NO_INACTIVE_SEEDING_TIME_LIMIT = -1; - const qreal Torrent::MAX_RATIO = 9999; + const qreal Torrent::MAX_RATIO = std::numeric_limits::infinity(); TorrentID Torrent::id() const { diff --git a/src/base/bittorrent/torrentimpl.cpp b/src/base/bittorrent/torrentimpl.cpp index fb27c44dc..03ca62eca 100644 --- a/src/base/bittorrent/torrentimpl.cpp +++ b/src/base/bittorrent/torrentimpl.cpp @@ -1515,7 +1515,8 @@ qreal TorrentImpl::realRatio() const const qreal ratio = upload / static_cast(download); Q_ASSERT(ratio >= 0); - return (ratio > MAX_RATIO) ? MAX_RATIO : ratio; + + return ratio; } int TorrentImpl::uploadPayloadRate() const @@ -2677,8 +2678,6 @@ void TorrentImpl::setRatioLimit(qreal limit) { if (limit < USE_GLOBAL_RATIO) limit = NO_RATIO_LIMIT; - else if (limit > MAX_RATIO) - limit = MAX_RATIO; if (m_ratioLimit != limit) { diff --git a/src/gui/optionsdialog.ui b/src/gui/optionsdialog.ui index 263c2bf91..e87aa65ff 100644 --- a/src/gui/optionsdialog.ui +++ b/src/gui/optionsdialog.ui @@ -3028,9 +3028,6 @@ Disable encryption: Only connect to peers without protocol encryption false - - 9998.000000000000000 - 0.050000000000000 diff --git a/src/gui/properties/propertieswidget.cpp b/src/gui/properties/propertieswidget.cpp index 303043a80..8a76e4663 100644 --- a/src/gui/properties/propertieswidget.cpp +++ b/src/gui/properties/propertieswidget.cpp @@ -441,10 +441,10 @@ void PropertiesWidget::loadDynamicData() // Update ratio info const qreal ratio = m_torrent->realRatio(); - m_ui->labelShareRatioVal->setText(ratio > BitTorrent::Torrent::MAX_RATIO ? C_INFINITY : Utils::String::fromDouble(ratio, 2)); + m_ui->labelShareRatioVal->setText(ratio >= BitTorrent::Torrent::MAX_RATIO ? C_INFINITY : Utils::String::fromDouble(ratio, 2)); const qreal popularity = m_torrent->popularity(); - m_ui->labelPopularityVal->setText(popularity > BitTorrent::Torrent::MAX_RATIO ? C_INFINITY : Utils::String::fromDouble(popularity, 2)); + m_ui->labelPopularityVal->setText(popularity >= BitTorrent::Torrent::MAX_RATIO ? C_INFINITY : Utils::String::fromDouble(popularity, 2)); m_ui->labelSeedsVal->setText(tr("%1 (%2 total)", "%1 and %2 are numbers, e.g. 3 (10 total)") .arg(QString::number(m_torrent->seedsCount()) diff --git a/src/gui/torrentsharelimitswidget.ui b/src/gui/torrentsharelimitswidget.ui index 9ada9ed67..13fbfe0a2 100644 --- a/src/gui/torrentsharelimitswidget.ui +++ b/src/gui/torrentsharelimitswidget.ui @@ -47,9 +47,6 @@ false - - 9998.000000000000000 - 0.050000000000000 diff --git a/src/gui/transferlistmodel.cpp b/src/gui/transferlistmodel.cpp index 7c827c1a6..0298db047 100644 --- a/src/gui/transferlistmodel.cpp +++ b/src/gui/transferlistmodel.cpp @@ -293,7 +293,7 @@ QString TransferListModel::displayValue(const BitTorrent::Torrent *torrent, cons if (hideValues && (value <= 0)) return {}; - return ((static_cast(value) == -1) || (value > BitTorrent::Torrent::MAX_RATIO)) + return ((static_cast(value) == -1) || (value >= BitTorrent::Torrent::MAX_RATIO)) ? C_INFINITY : Utils::String::fromDouble(value, 2); }; diff --git a/src/webui/api/serialize/serialize_torrent.cpp b/src/webui/api/serialize/serialize_torrent.cpp index bc75a7698..1543170d4 100644 --- a/src/webui/api/serialize/serialize_torrent.cpp +++ b/src/webui/api/serialize/serialize_torrent.cpp @@ -96,7 +96,7 @@ QVariantMap serialize(const BitTorrent::Torrent &torrent) const auto adjustRatio = [](const qreal ratio) -> qreal { - return (ratio > BitTorrent::Torrent::MAX_RATIO) ? -1 : ratio; + return (ratio >= BitTorrent::Torrent::MAX_RATIO) ? -1 : ratio; }; const auto getLastActivityTime = [&torrent]() -> qlonglong diff --git a/src/webui/api/torrentscontroller.cpp b/src/webui/api/torrentscontroller.cpp index c877fd5db..83459a892 100644 --- a/src/webui/api/torrentscontroller.cpp +++ b/src/webui/api/torrentscontroller.cpp @@ -523,8 +523,8 @@ void TorrentsController::propertiesAction() {KEY_PROP_SEEDS_TOTAL, torrent->totalSeedsCount()}, {KEY_PROP_PEERS, torrent->leechsCount()}, {KEY_PROP_PEERS_TOTAL, torrent->totalLeechersCount()}, - {KEY_PROP_RATIO, ((ratio > BitTorrent::Torrent::MAX_RATIO) ? -1 : ratio)}, - {KEY_PROP_POPULARITY, ((popularity > BitTorrent::Torrent::MAX_RATIO) ? -1 : popularity)}, + {KEY_PROP_RATIO, ((ratio >= BitTorrent::Torrent::MAX_RATIO) ? -1 : ratio)}, + {KEY_PROP_POPULARITY, ((popularity >= BitTorrent::Torrent::MAX_RATIO) ? -1 : popularity)}, {KEY_PROP_REANNOUNCE, torrent->nextAnnounce()}, {KEY_PROP_TOTAL_SIZE, torrent->totalSize()}, {KEY_PROP_PIECES_NUM, torrent->piecesCount()}, diff --git a/src/webui/www/private/shareratio.html b/src/webui/www/private/shareratio.html index 56b70f25d..8586f50cc 100644 --- a/src/webui/www/private/shareratio.html +++ b/src/webui/www/private/shareratio.html @@ -172,7 +172,7 @@
- +
diff --git a/src/webui/www/private/views/preferences.html b/src/webui/www/private/views/preferences.html index c8ef9de78..ed3c4bcb9 100644 --- a/src/webui/www/private/views/preferences.html +++ b/src/webui/www/private/views/preferences.html @@ -2912,8 +2912,8 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD let maxRatio = -1; if (document.getElementById("maxRatioCheckbox").checked) { maxRatio = Number(document.getElementById("maxRatioValue").value); - if (isNaN(maxRatio) || (maxRatio < 0) || (maxRatio > 9998)) { - alert("QBT_TR(Share ratio limit must be between 0 and 9998.)QBT_TR[CONTEXT=HttpServer]"); + if (isNaN(maxRatio) || (maxRatio < 0)) { + alert("QBT_TR(Share ratio limit must not have a negative value.)QBT_TR[CONTEXT=HttpServer]"); return; } } From 380b25e22f6dc53e42deb198d52a3de69502a889 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Wed, 23 Apr 2025 00:56:31 +0800 Subject: [PATCH 15/45] WebUI: migrate 'file tree' class to JS native class --- src/webui/www/private/scripts/file-tree.js | 99 ++++++++++------------ 1 file changed, 47 insertions(+), 52 deletions(-) diff --git a/src/webui/www/private/scripts/file-tree.js b/src/webui/www/private/scripts/file-tree.js index 328806988..b7fdf93b2 100644 --- a/src/webui/www/private/scripts/file-tree.js +++ b/src/webui/www/private/scripts/file-tree.js @@ -56,51 +56,51 @@ window.qBittorrent.FileTree ??= (() => { }; Object.freeze(TriState); - const FileTree = new Class({ - root: null, - nodeMap: {}, + class FileTree { + #root = null; + #nodeMap = {}; - setRoot: function(root) { - this.root = root; - this.generateNodeMap(root); + setRoot(root) { + this.#root = root; + this.#generateNodeMap(root); - if (this.root.isFolder) - this.root.calculateSize(); - }, + if (this.#root.isFolder) + this.#root.calculateSize(); + } - getRoot: function() { - return this.root; - }, + getRoot() { + return this.#root; + } - generateNodeMap: function(root) { + #generateNodeMap(root) { const stack = [root]; while (stack.length > 0) { const node = stack.pop(); // don't store root node in map if (node.root !== null) - this.nodeMap[node.rowId] = node; + this.#nodeMap[node.rowId] = node; stack.push(...node.children); } - }, + } - getNode: function(rowId) { - return (this.nodeMap[rowId] === undefined) + getNode(rowId) { + return (this.#nodeMap[rowId] === undefined) ? null - : this.nodeMap[rowId]; - }, + : this.#nodeMap[rowId]; + } - getRowId: (node) => { + getRowId(node) { return node.rowId; - }, + } /** * Returns the nodes in DFS in-order */ - toArray: function() { + toArray() { const ret = []; - const stack = this.root.children.toReversed(); + const stack = this.#root.children.toReversed(); while (stack.length > 0) { const node = stack.pop(); ret.push(node); @@ -108,45 +108,40 @@ window.qBittorrent.FileTree ??= (() => { } return ret; } - }); + } - const FileNode = new Class({ - name: "", - path: "", - rowId: null, - size: 0, - checked: TriState.Unchecked, - remaining: 0, - progress: 0, - priority: FilePriority.Normal, - availability: 0, - depth: 0, - root: null, - data: null, - isFolder: false, - children: [], - }); - - const FolderNode = new Class({ - Extends: FileNode, + class FileNode { + name = ""; + path = ""; + rowId = null; + size = 0; + checked = TriState.Unchecked; + remaining = 0; + progress = 0; + priority = FilePriority.Normal; + availability = 0; + depth = 0; + root = null; + data = null; + isFolder = false; + children = []; + } + class FolderNode extends FileNode { /** * Will automatically tick the checkbox for a folder if all subfolders and files are also ticked */ - autoCheckFolders: true, + autoCheckFolders = true; + isFolder = true; - initialize: function() { - this.isFolder = true; - }, - - addChild: function(node) { + addChild(node) { this.children.push(node); - }, + } /** * Calculate size of node and its children */ - calculateSize: function() { + calculateSize() { const stack = [this]; const visited = []; @@ -202,7 +197,7 @@ window.qBittorrent.FileTree ??= (() => { stack.pop(); } } - }); + } return exports(); })(); From 559f47ab0c93a5a30739e2d35a8999cf3fd77728 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Wed, 23 Apr 2025 07:11:37 +0800 Subject: [PATCH 16/45] WebUI: avoid double lookup --- src/webui/www/private/scripts/file-tree.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/webui/www/private/scripts/file-tree.js b/src/webui/www/private/scripts/file-tree.js index b7fdf93b2..c56ddeaef 100644 --- a/src/webui/www/private/scripts/file-tree.js +++ b/src/webui/www/private/scripts/file-tree.js @@ -58,7 +58,7 @@ window.qBittorrent.FileTree ??= (() => { class FileTree { #root = null; - #nodeMap = {}; + #nodeMap = {}; // Object with Number as keys is faster than anything setRoot(root) { this.#root = root; @@ -86,9 +86,9 @@ window.qBittorrent.FileTree ??= (() => { } getNode(rowId) { - return (this.#nodeMap[rowId] === undefined) - ? null - : this.#nodeMap[rowId]; + // TODO: enforce caller sites to pass `rowId` as number and not string + const value = this.#nodeMap[Number(rowId)]; + return (value !== undefined) ? value : null; } getRowId(node) { From c494314a29b339a1bd7436623167583560b68e81 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Sat, 3 May 2025 23:04:55 +0800 Subject: [PATCH 17/45] Use short format for displaying RSS entry date The long format is too verbose and hard to read. PR #22646. --- src/gui/rss/rsswidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/rss/rsswidget.cpp b/src/gui/rss/rsswidget.cpp index 98c272014..2c3fe7572 100644 --- a/src/gui/rss/rsswidget.cpp +++ b/src/gui/rss/rsswidget.cpp @@ -631,7 +631,7 @@ void RSSWidget::renderArticle(const RSS::Article *article) const u"
" + u"
%3
"_s.arg(highlightedBaseColor, highlightedBaseTextColor, article->title()); if (article->date().isValid()) - html += u"
%2%3
"_s.arg(alternateBaseColor, tr("Date: "), QLocale::system().toString(article->date().toLocalTime())); + html += u"
%2%3
"_s.arg(alternateBaseColor, tr("Date: "), QLocale::system().toString(article->date().toLocalTime(), QLocale::ShortFormat)); if (m_ui->feedListWidget->currentItem() == m_ui->feedListWidget->stickyUnreadItem()) html += u"
%2%3
"_s.arg(alternateBaseColor, tr("Feed: "), article->feed()->title()); if (!article->author().isEmpty()) From f1b7c4572b3d4b44568470662cc61c5ffb934cac Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Mon, 5 May 2025 15:38:12 +0800 Subject: [PATCH 18/45] Revise labels for 'duplicate torrent' actions PR #22645. --- src/gui/optionsdialog.ui | 4 ++-- src/webui/www/private/views/preferences.html | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/optionsdialog.ui b/src/gui/optionsdialog.ui index e87aa65ff..a21f7af04 100644 --- a/src/gui/optionsdialog.ui +++ b/src/gui/optionsdialog.ui @@ -1031,7 +1031,7 @@ - When duplicate torrent is being added + When adding a duplicate torrent @@ -1047,7 +1047,7 @@ - Ask for merging trackers when torrent is being added manually + Ask to merge trackers for manually added torrent true diff --git a/src/webui/www/private/views/preferences.html b/src/webui/www/private/views/preferences.html index ed3c4bcb9..b6ec95f76 100644 --- a/src/webui/www/private/views/preferences.html +++ b/src/webui/www/private/views/preferences.html @@ -141,7 +141,7 @@
- QBT_TR(When duplicate torrent is being added)QBT_TR[CONTEXT=OptionsDialog] + QBT_TR(When adding a duplicate torrent)QBT_TR[CONTEXT=OptionsDialog]
From 76bb4e5f98a077ba8a7d80fabbefe0c06a78063e Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (Glassez)" Date: Fri, 2 May 2025 17:11:17 +0300 Subject: [PATCH 19/45] Add helpers to get InfoHash from libtorrent classes --- src/base/bittorrent/sessionimpl.cpp | 152 +++++++++++++--------------- src/base/bittorrent/sessionimpl.h | 1 + 2 files changed, 74 insertions(+), 79 deletions(-) diff --git a/src/base/bittorrent/sessionimpl.cpp b/src/base/bittorrent/sessionimpl.cpp index a6bf947f8..0e7c8adbb 100644 --- a/src/base/bittorrent/sessionimpl.cpp +++ b/src/base/bittorrent/sessionimpl.cpp @@ -30,6 +30,7 @@ #include "sessionimpl.h" #include +#include #include #include #include @@ -315,6 +316,44 @@ namespace break; } } + +#ifdef QBT_USES_LIBTORRENT2 + template + concept HasInfoHashMember = requires (T t) { { t.info_hashes } -> std::convertible_to; }; + + template + concept HasInfoHashMemberFn = requires (T t) { { t.info_hashes() } -> std::convertible_to; }; + + template + InfoHash getInfoHash(const T &t) { return t.info_hashes; } + + template + InfoHash getInfoHash(const T &t) { return t.info_hashes(); } + + InfoHash getInfoHash(const lt::add_torrent_params &addTorrentParams) + { + const bool hasMetadata = (addTorrentParams.ti && addTorrentParams.ti->is_valid()); + return hasMetadata ? getInfoHash(*addTorrentParams.ti) : InfoHash(addTorrentParams.info_hashes); + } + #else + template + concept HasInfoHashMember = requires (T t) { { t.info_hash } -> std::convertible_to; }; + + template + concept HasInfoHashMemberFn = requires (T t) { { t.info_hash() } -> std::convertible_to; }; + + template + InfoHash getInfoHash(const T &t) { return t.info_hash; } + + template + InfoHash getInfoHash(const T &t) { return t.info_hash(); } + + InfoHash getInfoHash(const lt::add_torrent_params &addTorrentParams) + { + const bool hasMetadata = (addTorrentParams.ti && addTorrentParams.ti->is_valid()); + return hasMetadata ? getInfoHash(*addTorrentParams.ti) : InfoHash(addTorrentParams.info_hash); + } + #endif } struct BitTorrent::SessionImpl::ResumeSessionContext final : public QObject @@ -1443,10 +1482,8 @@ void SessionImpl::processNextResumeData(ResumeSessionContext *context) LoadTorrentParams resumeData = *loadResumeDataResult; bool needStore = false; + const InfoHash infoHash = getInfoHash(resumeData.ltAddTorrentParams); #ifdef QBT_USES_LIBTORRENT2 - const InfoHash infoHash {(resumeData.ltAddTorrentParams.ti - ? resumeData.ltAddTorrentParams.ti->info_hashes() - : resumeData.ltAddTorrentParams.info_hashes)}; const bool isHybrid = infoHash.isHybrid(); const auto torrentIDv2 = TorrentID::fromInfoHash(infoHash); const auto torrentIDv1 = TorrentID::fromSHA1Hash(infoHash.v1()); @@ -1494,9 +1531,6 @@ void SessionImpl::processNextResumeData(ResumeSessionContext *context) return; } #else - const lt::sha1_hash infoHash = (resumeData.ltAddTorrentParams.ti - ? resumeData.ltAddTorrentParams.ti->info_hash() - : resumeData.ltAddTorrentParams.info_hash); if (torrentID != TorrentID::fromInfoHash(infoHash)) { LogMsg(tr("Failed to resume torrent: inconsistent torrent ID is detected. Torrent: \"%1\"") @@ -2398,7 +2432,7 @@ Torrent *SessionImpl::getTorrent(const TorrentID &id) const Torrent *SessionImpl::findTorrent(const InfoHash &infoHash) const { const auto id = TorrentID::fromInfoHash(infoHash); - if (Torrent *torrent = m_torrents.value(id); torrent) + if (Torrent *torrent = m_torrents.value(id)) return torrent; if (!infoHash.isHybrid()) @@ -2515,7 +2549,7 @@ bool SessionImpl::cancelDownloadMetadata(const TorrentID &id) return true; #ifdef QBT_USES_LIBTORRENT2 - const InfoHash infoHash {nativeHandle.info_hashes()}; + const InfoHash infoHash = getInfoHash(nativeHandle); if (infoHash.isHybrid()) { // if magnet link was hybrid initially then it is indexed also by v1 info hash @@ -5417,13 +5451,8 @@ bool SessionImpl::addMoveTorrentStorageJob(TorrentImpl *torrent, const Path &new void SessionImpl::moveTorrentStorage(const MoveStorageJob &job) const { -#ifdef QBT_USES_LIBTORRENT2 - const auto id = TorrentID::fromInfoHash(job.torrentHandle.info_hashes()); -#else - const auto id = TorrentID::fromInfoHash(job.torrentHandle.info_hash()); -#endif - const TorrentImpl *torrent = m_torrents.value(id); - const QString torrentName = (torrent ? torrent->name() : id.toString()); + const TorrentImpl *torrent = getTorrent(job.torrentHandle); + const QString torrentName = (torrent ? torrent->name() : getInfoHash(job.torrentHandle).toTorrentID().toString()); LogMsg(tr("Start moving torrent. Torrent: \"%1\". Destination: \"%2\"").arg(torrentName, job.path.toString())); job.torrentHandle.move_storage(job.path.toString().toStdString(), toNative(job.mode)); @@ -5443,7 +5472,7 @@ void SessionImpl::handleMoveTorrentStorageJobFinished(const Path &newPath) const bool torrentHasOutstandingJob = (iter != m_moveStorageQueue.cend()); - TorrentImpl *torrent = m_torrents.value(finishedJob.torrentHandle.info_hash()); + TorrentImpl *torrent = getTorrent(finishedJob.torrentHandle); if (torrent) { torrent->handleMoveStorageJobFinished(newPath, finishedJob.context, torrentHasOutstandingJob); @@ -5451,8 +5480,9 @@ void SessionImpl::handleMoveTorrentStorageJobFinished(const Path &newPath) else if (!torrentHasOutstandingJob) { // Last job is completed for torrent that being removing, so actually remove it - const lt::torrent_handle nativeHandle {finishedJob.torrentHandle}; - const RemovingTorrentData &removingTorrentData = m_removingTorrents[nativeHandle.info_hash()]; + const lt::torrent_handle nativeHandle = finishedJob.torrentHandle; + const TorrentID torrentID = getInfoHash(nativeHandle).toTorrentID(); + const RemovingTorrentData &removingTorrentData = m_removingTorrents[torrentID]; if (removingTorrentData.removeOption == TorrentRemoveOption::KeepContent) m_nativeSession->remove_torrent(nativeHandle, lt::session::delete_partfile); } @@ -5749,15 +5779,10 @@ void SessionImpl::handleAddTorrentAlert(const lt::add_torrent_alert *alert) LogMsg(tr("Failed to load torrent. Reason: \"%1\"").arg(msg), Log::WARNING); emit loadTorrentFailed(msg); - const lt::add_torrent_params ¶ms = alert->params; - const bool hasMetadata = (params.ti && params.ti->is_valid()); - + const InfoHash infoHash = getInfoHash(alert->params); #ifdef QBT_USES_LIBTORRENT2 - const InfoHash infoHash {(hasMetadata ? params.ti->info_hashes() : params.info_hashes)}; if (infoHash.isHybrid()) m_hybridTorrentsByAltID.remove(TorrentID::fromSHA1Hash(infoHash.v1())); -#else - const InfoHash infoHash {(hasMetadata ? params.ti->info_hash() : params.info_hash)}; #endif if (const auto loadingTorrentsIter = m_loadingTorrents.constFind(TorrentID::fromInfoHash(infoHash)) ; loadingTorrentsIter != m_loadingTorrents.cend()) @@ -5782,11 +5807,7 @@ void SessionImpl::handleAddTorrentAlert(const lt::add_torrent_alert *alert) return; } -#ifdef QBT_USES_LIBTORRENT2 - const InfoHash infoHash {alert->handle.info_hashes()}; -#else - const InfoHash infoHash {alert->handle.info_hash()}; -#endif + const InfoHash infoHash = getInfoHash(alert->handle); const auto torrentID = TorrentID::fromInfoHash(infoHash); if (const auto loadingTorrentsIter = m_loadingTorrents.constFind(torrentID) @@ -5930,12 +5951,11 @@ void SessionImpl::dispatchTorrentAlert(const lt::torrent_alert *alert) --m_numResumeData; } - const TorrentID torrentID {alert->handle.info_hash()}; - TorrentImpl *torrent = m_torrents.value(torrentID); + TorrentImpl *torrent = getTorrent(alert->handle); #ifdef QBT_USES_LIBTORRENT2 if (!torrent && (alert->type() == lt::metadata_received_alert::alert_type)) { - const InfoHash infoHash {alert->handle.info_hashes()}; + const InfoHash infoHash = getInfoHash(alert->handle); if (infoHash.isHybrid()) torrent = m_torrents.value(TorrentID::fromSHA1Hash(infoHash.v1())); } @@ -6000,6 +6020,11 @@ TorrentImpl *SessionImpl::createTorrent(const lt::torrent_handle &nativeHandle, return torrent; } +TorrentImpl *SessionImpl::getTorrent(const lt::torrent_handle &nativeHandle) const +{ + return m_torrents.value(getInfoHash(nativeHandle).toTorrentID()); +} + void SessionImpl::handleTorrentRemovedAlert(const lt::torrent_removed_alert */*alert*/) { // We cannot consider `torrent_removed_alert` as a starting point for removing content, @@ -6009,34 +6034,19 @@ void SessionImpl::handleTorrentRemovedAlert(const lt::torrent_removed_alert */*a void SessionImpl::handleTorrentDeletedAlert(const lt::torrent_deleted_alert *alert) { -#ifdef QBT_USES_LIBTORRENT2 - const auto torrentID = TorrentID::fromInfoHash(alert->info_hashes); -#else - const auto torrentID = TorrentID::fromInfoHash(alert->info_hash); -#endif - handleRemovedTorrent(torrentID); + handleRemovedTorrent(getInfoHash(*alert).toTorrentID()); } void SessionImpl::handleTorrentDeleteFailedAlert(const lt::torrent_delete_failed_alert *alert) { -#ifdef QBT_USES_LIBTORRENT2 - const auto torrentID = TorrentID::fromInfoHash(alert->info_hashes); -#else - const auto torrentID = TorrentID::fromInfoHash(alert->info_hash); -#endif + const TorrentID torrentID = getInfoHash(*alert).toTorrentID(); const auto errorMessage = alert->error ? Utils::String::fromLocal8Bit(alert->error.message()) : QString(); handleRemovedTorrent(torrentID, errorMessage); } void SessionImpl::handleTorrentNeedCertAlert(const lt::torrent_need_cert_alert *alert) { -#ifdef QBT_USES_LIBTORRENT2 - const InfoHash infoHash {alert->handle.info_hashes()}; -#else - const InfoHash infoHash {alert->handle.info_hash()}; -#endif - const auto torrentID = TorrentID::fromInfoHash(infoHash); - + const TorrentID torrentID = getInfoHash(alert->handle).toTorrentID(); TorrentImpl *const torrent = m_torrents.value(torrentID); if (!torrent) [[unlikely]] return; @@ -6050,7 +6060,8 @@ void SessionImpl::handleTorrentNeedCertAlert(const lt::torrent_need_cert_alert * void SessionImpl::handleMetadataReceivedAlert(const lt::metadata_received_alert *alert) { - const TorrentID torrentID {alert->handle.info_hash()}; + const InfoHash infoHash = getInfoHash(alert->handle); + const TorrentID torrentID = infoHash.toTorrentID(); bool found = false; if (const auto iter = m_downloadedMetadata.constFind(torrentID); iter != m_downloadedMetadata.cend()) @@ -6059,7 +6070,6 @@ void SessionImpl::handleMetadataReceivedAlert(const lt::metadata_received_alert m_downloadedMetadata.erase(iter); } #ifdef QBT_USES_LIBTORRENT2 - const InfoHash infoHash {alert->handle.info_hashes()}; if (infoHash.isHybrid()) { const auto altID = TorrentID::fromSHA1Hash(infoHash.v1()); @@ -6081,7 +6091,7 @@ void SessionImpl::handleMetadataReceivedAlert(const lt::metadata_received_alert void SessionImpl::handleFileErrorAlert(const lt::file_error_alert *alert) { - TorrentImpl *const torrent = m_torrents.value(alert->handle.info_hash()); + TorrentImpl *const torrent = getTorrent(alert->handle); if (!torrent) return; @@ -6152,7 +6162,7 @@ void SessionImpl::handlePeerBanAlert(const lt::peer_ban_alert *alert) void SessionImpl::handleUrlSeedAlert(const lt::url_seed_alert *alert) { - const TorrentImpl *torrent = m_torrents.value(alert->handle.info_hash()); + const TorrentImpl *torrent = getTorrent(alert->handle); if (!torrent) return; @@ -6331,14 +6341,8 @@ void SessionImpl::handleStorageMovedAlert(const lt::storage_moved_alert *alert) const Path newPath {QString::fromUtf8(alert->storage_path())}; Q_ASSERT(newPath == currentJob.path); -#ifdef QBT_USES_LIBTORRENT2 - const auto id = TorrentID::fromInfoHash(currentJob.torrentHandle.info_hashes()); -#else - const auto id = TorrentID::fromInfoHash(currentJob.torrentHandle.info_hash()); -#endif - - TorrentImpl *torrent = m_torrents.value(id); - const QString torrentName = (torrent ? torrent->name() : id.toString()); + TorrentImpl *torrent = getTorrent(currentJob.torrentHandle); + const QString torrentName = (torrent ? torrent->name() : getInfoHash(currentJob.torrentHandle).toTorrentID().toString()); LogMsg(tr("Moved torrent successfully. Torrent: \"%1\". Destination: \"%2\"").arg(torrentName, newPath.toString())); handleMoveTorrentStorageJobFinished(newPath); @@ -6351,14 +6355,8 @@ void SessionImpl::handleStorageMovedFailedAlert(const lt::storage_moved_failed_a const MoveStorageJob ¤tJob = m_moveStorageQueue.constFirst(); Q_ASSERT(currentJob.torrentHandle == alert->handle); -#ifdef QBT_USES_LIBTORRENT2 - const auto id = TorrentID::fromInfoHash(currentJob.torrentHandle.info_hashes()); -#else - const auto id = TorrentID::fromInfoHash(currentJob.torrentHandle.info_hash()); -#endif - - TorrentImpl *torrent = m_torrents.value(id); - const QString torrentName = (torrent ? torrent->name() : id.toString()); + TorrentImpl *torrent = getTorrent(currentJob.torrentHandle); + const QString torrentName = (torrent ? torrent->name() : getInfoHash(currentJob.torrentHandle).toTorrentID().toString()); const Path currentLocation = (torrent ? torrent->actualStorageLocation() : Path(alert->handle.status(lt::torrent_handle::query_save_path).save_path)); const QString errorMessage = QString::fromStdString(alert->message()); @@ -6375,12 +6373,7 @@ void SessionImpl::handleStateUpdateAlert(const lt::state_update_alert *alert) for (const lt::torrent_status &status : alert->status) { -#ifdef QBT_USES_LIBTORRENT2 - const auto id = TorrentID::fromInfoHash(status.info_hashes); -#else - const auto id = TorrentID::fromInfoHash(status.info_hash); -#endif - TorrentImpl *const torrent = m_torrents.value(id); + TorrentImpl *const torrent = getTorrent(status.handle); if (!torrent) continue; @@ -6424,7 +6417,7 @@ void SessionImpl::handleI2PAlert(const lt::i2p_alert *alert) const void SessionImpl::handleTrackerAlert(const lt::tracker_alert *alert) { - TorrentImpl *torrent = m_torrents.value(alert->handle.info_hash()); + TorrentImpl *torrent = getTorrent(alert->handle); if (!torrent) return; @@ -6450,8 +6443,9 @@ void SessionImpl::handleTrackerAlert(const lt::tracker_alert *alert) #ifdef QBT_USES_LIBTORRENT2 void SessionImpl::handleTorrentConflictAlert(const lt::torrent_conflict_alert *alert) { - const auto torrentIDv1 = TorrentID::fromSHA1Hash(alert->metadata->info_hashes().v1); - const auto torrentIDv2 = TorrentID::fromSHA256Hash(alert->metadata->info_hashes().v2); + const InfoHash infoHash = getInfoHash(*alert->metadata); + const auto torrentIDv1 = TorrentID::fromSHA1Hash(infoHash.v1()); + const auto torrentIDv2 = TorrentID::fromSHA256Hash(infoHash.v2()); TorrentImpl *torrent1 = m_torrents.value(torrentIDv1); TorrentImpl *torrent2 = m_torrents.value(torrentIDv2); if (torrent2) diff --git a/src/base/bittorrent/sessionimpl.h b/src/base/bittorrent/sessionimpl.h index e878cf4a6..7b6f6aab7 100644 --- a/src/base/bittorrent/sessionimpl.h +++ b/src/base/bittorrent/sessionimpl.h @@ -606,6 +606,7 @@ namespace BitTorrent #endif TorrentImpl *createTorrent(const lt::torrent_handle &nativeHandle, const LoadTorrentParams ¶ms); + TorrentImpl *getTorrent(const lt::torrent_handle &nativeHandle) const; void saveResumeData(); void saveTorrentsQueue(); From 3691eb948e131406353434d857e6268e77c9e90a Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (Glassez)" Date: Fri, 2 May 2025 14:05:26 +0300 Subject: [PATCH 20/45] Join the similar code paths --- src/base/bittorrent/sessionimpl.cpp | 50 +++++++++++++---------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/src/base/bittorrent/sessionimpl.cpp b/src/base/bittorrent/sessionimpl.cpp index 0e7c8adbb..d4b3467bb 100644 --- a/src/base/bittorrent/sessionimpl.cpp +++ b/src/base/bittorrent/sessionimpl.cpp @@ -2903,14 +2903,7 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr } if (!loadTorrentParams.hasFinishedStatus) - { needFindIncompleteFiles = true; - } - else - { - for (int index = 0; index < filePaths.size(); ++index) - p.renamed_files[nativeIndexes[index]] = filePaths.at(index).toString().toStdString(); - } const int internalFilesCount = torrentInfo.nativeInfo()->files().num_files(); // including .pad files // Use qBittorrent default priority rather than libtorrent's (4) @@ -2930,8 +2923,6 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr loadTorrentParams.name = QString::fromStdString(p.name); } - p.save_path = actualSavePath.toString().toStdString(); - if (isAddTrackersEnabled() && !(hasMetadata && p.ti->priv())) { const auto maxTierIter = std::max_element(p.tracker_tiers.cbegin(), p.tracker_tiers.cend()); @@ -3006,34 +2997,37 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr if (infoHash.isHybrid()) m_hybridTorrentsByAltID.insert(altID, nullptr); - if (needFindIncompleteFiles) + const auto resolveFileNames = [&, this] { - const Path actualDownloadPath = useAutoTMM + if (!needFindIncompleteFiles) + return QtFuture::makeReadyValueFuture(FileSearchResult {.savePath = actualSavePath, .fileNames = filePaths}); + + const Path actualDownloadPath = loadTorrentParams.useAutoTMM ? categoryDownloadPath(loadTorrentParams.category) : loadTorrentParams.downloadPath; - findIncompleteFiles(actualSavePath, actualDownloadPath, filePaths).then(this - , [this, id](const FileSearchResult &result) + return findIncompleteFiles(actualSavePath, actualDownloadPath, filePaths); + }; + + resolveFileNames().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 ¶ms = loadingTorrentsIter.value(); + lt::add_torrent_params &p = params.ltAddTorrentParams; + + p.save_path = result.savePath.toString().toStdString(); + if (p.ti) { - const auto loadingTorrentsIter = m_loadingTorrents.find(id); - Q_ASSERT(loadingTorrentsIter != m_loadingTorrents.end()); - if (loadingTorrentsIter == m_loadingTorrents.end()) [[unlikely]] - return; - - LoadTorrentParams ¶ms = loadingTorrentsIter.value(); - lt::add_torrent_params &p = params.ltAddTorrentParams; - - p.save_path = result.savePath.toString().toStdString(); const TorrentInfo torrentInfo {*p.ti}; const auto nativeIndexes = torrentInfo.nativeIndexes(); for (int i = 0; i < result.fileNames.size(); ++i) p.renamed_files[nativeIndexes[i]] = result.fileNames[i].toString().toStdString(); + } - m_nativeSession->async_add_torrent(p); - }); - } - else - { m_nativeSession->async_add_torrent(p); - } + }); return true; } From 582dc99cae678efbb7932711092072bb8c5322c9 Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (Glassez)" Date: Mon, 5 May 2025 13:57:53 +0300 Subject: [PATCH 21/45] Don't access libtorrent session directly from TorrentImpl --- src/base/bittorrent/sessionimpl.cpp | 15 ++++++++++++++- src/base/bittorrent/sessionimpl.h | 2 ++ src/base/bittorrent/torrentimpl.cpp | 30 ++++++++++------------------- src/base/bittorrent/torrentimpl.h | 4 +--- 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/base/bittorrent/sessionimpl.cpp b/src/base/bittorrent/sessionimpl.cpp index d4b3467bb..a9d6715b4 100644 --- a/src/base/bittorrent/sessionimpl.cpp +++ b/src/base/bittorrent/sessionimpl.cpp @@ -5443,6 +5443,19 @@ bool SessionImpl::addMoveTorrentStorageJob(TorrentImpl *torrent, const Path &new return true; } +lt::torrent_handle SessionImpl::reloadTorrent(const lt::torrent_handle ¤tHandle, lt::add_torrent_params params) +{ + m_nativeSession->remove_torrent(currentHandle, lt::session::delete_partfile); + + auto *const extensionData = new ExtensionData; + params.userdata = LTClientData(extensionData); +#ifndef QBT_USES_LIBTORRENT2 + params.storage = customStorageConstructor; +#endif + + return m_nativeSession->add_torrent(std::move(params)); +} + void SessionImpl::moveTorrentStorage(const MoveStorageJob &job) const { const TorrentImpl *torrent = getTorrent(job.torrentHandle); @@ -5971,7 +5984,7 @@ void SessionImpl::dispatchTorrentAlert(const lt::torrent_alert *alert) TorrentImpl *SessionImpl::createTorrent(const lt::torrent_handle &nativeHandle, const LoadTorrentParams ¶ms) { - auto *const torrent = new TorrentImpl(this, m_nativeSession, nativeHandle, params); + auto *const torrent = new TorrentImpl(this, nativeHandle, params); m_torrents.insert(torrent->id(), torrent); if (const InfoHash infoHash = torrent->infoHash(); infoHash.isHybrid()) m_hybridTorrentsByAltID.insert(TorrentID::fromSHA1Hash(infoHash.v1()), torrent); diff --git a/src/base/bittorrent/sessionimpl.h b/src/base/bittorrent/sessionimpl.h index 7b6f6aab7..7b1a8ae39 100644 --- a/src/base/bittorrent/sessionimpl.h +++ b/src/base/bittorrent/sessionimpl.h @@ -482,6 +482,8 @@ namespace BitTorrent bool addMoveTorrentStorageJob(TorrentImpl *torrent, const Path &newPath, MoveStorageMode mode, MoveStorageContext context); + lt::torrent_handle reloadTorrent(const lt::torrent_handle ¤tHandle, lt::add_torrent_params params); + QFuture findIncompleteFiles(const Path &savePath, const Path &downloadPath, const PathList &filePaths = {}) const; void enablePortMapping(); diff --git a/src/base/bittorrent/torrentimpl.cpp b/src/base/bittorrent/torrentimpl.cpp index fb27c44dc..a2188724c 100644 --- a/src/base/bittorrent/torrentimpl.cpp +++ b/src/base/bittorrent/torrentimpl.cpp @@ -290,11 +290,9 @@ namespace // TorrentImpl -TorrentImpl::TorrentImpl(SessionImpl *session, lt::session *nativeSession - , const lt::torrent_handle &nativeHandle, const LoadTorrentParams ¶ms) +TorrentImpl::TorrentImpl(SessionImpl *session, const lt::torrent_handle &nativeHandle, const LoadTorrentParams ¶ms) : Torrent(session) , m_session(session) - , m_nativeSession(nativeSession) , m_nativeHandle(nativeHandle) #ifdef QBT_USES_LIBTORRENT2 , m_infoHash(m_nativeHandle.info_hashes()) @@ -1836,16 +1834,6 @@ void TorrentImpl::reload() { try { - m_completedFiles.fill(false); - m_filesProgress.fill(0); - m_pieces.fill(false); - m_nativeStatus.pieces.clear_all(); - m_nativeStatus.num_pieces = 0; - - const auto queuePos = m_nativeHandle.queue_position(); - - m_nativeSession->remove_torrent(m_nativeHandle, lt::session::delete_partfile); - lt::add_torrent_params p = m_ltAddTorrentParams; p.flags |= lt::torrent_flags::update_subscribe | lt::torrent_flags::override_trackers @@ -1865,19 +1853,21 @@ void TorrentImpl::reload() p.flags &= ~(lt::torrent_flags::auto_managed | lt::torrent_flags::paused); } - auto *const extensionData = new ExtensionData; - p.userdata = LTClientData(extensionData); -#ifndef QBT_USES_LIBTORRENT2 - p.storage = customStorageConstructor; -#endif - m_nativeHandle = m_nativeSession->add_torrent(p); + const auto queuePos = m_nativeHandle.queue_position(); - m_nativeStatus = extensionData->status; + m_nativeHandle = m_session->reloadTorrent(m_nativeHandle, std::move(p)); + m_nativeStatus = static_cast(m_nativeHandle.userdata())->status; if (queuePos >= lt::queue_position_t {}) m_nativeHandle.queue_position_set(queuePos); m_nativeStatus.queue_position = queuePos; + m_completedFiles.fill(false); + m_filesProgress.fill(0); + m_pieces.fill(false); + m_nativeStatus.pieces.clear_all(); + m_nativeStatus.num_pieces = 0; + updateState(); } catch (const lt::system_error &err) diff --git a/src/base/bittorrent/torrentimpl.h b/src/base/bittorrent/torrentimpl.h index 87137cd73..1875ba11c 100644 --- a/src/base/bittorrent/torrentimpl.h +++ b/src/base/bittorrent/torrentimpl.h @@ -94,8 +94,7 @@ namespace BitTorrent Q_DISABLE_COPY_MOVE(TorrentImpl) public: - TorrentImpl(SessionImpl *session, lt::session *nativeSession - , const lt::torrent_handle &nativeHandle, const LoadTorrentParams ¶ms); + TorrentImpl(SessionImpl *session, const lt::torrent_handle &nativeHandle, const LoadTorrentParams ¶ms); ~TorrentImpl() override; bool isValid() const; @@ -325,7 +324,6 @@ namespace BitTorrent QFuture> invokeAsync(Func &&func) const; SessionImpl *const m_session = nullptr; - lt::session *m_nativeSession = nullptr; lt::torrent_handle m_nativeHandle; mutable lt::torrent_status m_nativeStatus; TorrentState m_state = TorrentState::Unknown; From 9afbd47b5239c35f3952472315cf8c55e4ac21f3 Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (Glassez)" Date: Sun, 20 Apr 2025 20:21:04 +0300 Subject: [PATCH 22/45] Assign add_torrent_alert handler when adding torrent --- src/base/bittorrent/session.h | 1 - src/base/bittorrent/sessionimpl.cpp | 195 +++++++++++++++------------- src/base/bittorrent/sessionimpl.h | 5 + 3 files changed, 110 insertions(+), 91 deletions(-) diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index 95c7ac4be..cae03ba83 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -493,7 +493,6 @@ namespace BitTorrent void categoryOptionsChanged(const QString &categoryName); void fullDiskError(Torrent *torrent, const QString &msg); void IPFilterParsed(bool error, int ruleCount); - void loadTorrentFailed(const QString &error); void metadataDownloaded(const TorrentInfo &info); void restored(); void paused(); diff --git a/src/base/bittorrent/sessionimpl.cpp b/src/base/bittorrent/sessionimpl.cpp index a9d6715b4..c08fd616b 100644 --- a/src/base/bittorrent/sessionimpl.cpp +++ b/src/base/bittorrent/sessionimpl.cpp @@ -1621,15 +1621,33 @@ void SessionImpl::processNextResumeData(ResumeSessionContext *context) qDebug() << "Starting up torrent" << torrentID.toString() << "..."; m_loadingTorrents.insert(torrentID, resumeData); -#ifdef QBT_USES_LIBTORRENT2 - if (infoHash.isHybrid()) - { - // this allows to know the being added hybrid torrent by its v1 info hash - // without having yet another mapping table - m_hybridTorrentsByAltID.insert(torrentIDv1, nullptr); - } -#endif m_nativeSession->async_add_torrent(resumeData.ltAddTorrentParams); + m_addTorrentAlertHandlers.enqueue([this](const lt::add_torrent_alert *alert) + { + if (alert->error) + { + const QString msg = QString::fromStdString(alert->message()); + LogMsg(tr("Failed to load torrent. Reason: \"%1\"").arg(msg), Log::WARNING); + m_loadingTorrents.remove(getInfoHash(alert->params).toTorrentID()); + } + else + { + const TorrentID torrentID = getInfoHash(alert->handle).toTorrentID(); + + if (const auto loadingTorrentsIter = m_loadingTorrents.constFind(torrentID) + ; loadingTorrentsIter != m_loadingTorrents.cend()) + { + const LoadTorrentParams params = loadingTorrentsIter.value(); + m_loadingTorrents.erase(loadingTorrentsIter); + + Torrent *torrent = createTorrent(alert->handle, params); + m_loadedTorrents.append(torrent); + + LogMsg(tr("Restored torrent. Torrent: \"%1\"").arg(torrent->name())); + } + } + }); + ++context->processingResumeDataCount; } @@ -2994,8 +3012,6 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr #endif m_loadingTorrents.insert(id, loadTorrentParams); - if (infoHash.isHybrid()) - m_hybridTorrentsByAltID.insert(altID, nullptr); const auto resolveFileNames = [&, this] { @@ -3027,6 +3043,52 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr } m_nativeSession->async_add_torrent(p); + m_addTorrentAlertHandlers.enqueue([this](const lt::add_torrent_alert *alert) + { + if (alert->error) + { + const QString msg = QString::fromStdString(alert->message()); + LogMsg(tr("Failed to add torrent. Reason: \"%1\"").arg(msg), Log::WARNING); + + const InfoHash infoHash = getInfoHash(alert->params); + if (const auto loadingTorrentsIter = m_loadingTorrents.constFind(TorrentID::fromInfoHash(infoHash)) + ; loadingTorrentsIter != m_loadingTorrents.cend()) + { + const AddTorrentError::Kind errorKind = (alert->error == lt::errors::duplicate_torrent) + ? AddTorrentError::DuplicateTorrent : AddTorrentError::Other; + emit addTorrentFailed(infoHash, {errorKind, msg}); + m_loadingTorrents.erase(loadingTorrentsIter); + } + } + else + { + const TorrentID torrentID = getInfoHash(alert->handle).toTorrentID(); + if (const auto loadingTorrentsIter = m_loadingTorrents.constFind(torrentID) + ; loadingTorrentsIter != m_loadingTorrents.cend()) + { + const LoadTorrentParams params = loadingTorrentsIter.value(); + m_loadingTorrents.erase(loadingTorrentsIter); + + if (params.addToQueueTop) + alert->handle.queue_position_top(); + + TorrentImpl *torrent = createTorrent(alert->handle, params); + m_loadedTorrents.append(torrent); + + torrent->requestResumeData(lt::torrent_handle::save_info_dict); + + LogMsg(tr("Added new torrent. Torrent: \"%1\"").arg(torrent->name())); + emit torrentAdded(torrent); + + // The following is useless for newly added magnet + if (torrent->hasMetadata()) + { + if (!torrentExportDirectory().isEmpty()) + exportTorrentFile(torrent, torrentExportDirectory()); + } + } + } + }); }); return true; @@ -3181,6 +3243,33 @@ bool SessionImpl::downloadMetadata(const TorrentDescriptor &torrentDescr) // Adding torrent to libtorrent session m_nativeSession->async_add_torrent(p); m_downloadedMetadata.insert(id, {}); + m_addTorrentAlertHandlers.enqueue([this](const lt::add_torrent_alert *alert) + { + if (alert->error) + { + const QString msg = QString::fromStdString(alert->message()); + LogMsg(tr("Failed to download torrent metadata. Reason: \"%1\"").arg(msg), Log::WARNING); + + m_downloadedMetadata.remove(getInfoHash(alert->params).toTorrentID()); + } + else + { + const InfoHash infoHash = getInfoHash(alert->handle); + const auto torrentID = TorrentID::fromInfoHash(infoHash); + + if (const auto downloadedMetadataIter = m_downloadedMetadata.find(torrentID) + ; downloadedMetadataIter != m_downloadedMetadata.end()) + { + downloadedMetadataIter.value() = alert->handle; + if (infoHash.isHybrid()) + { + // index hybrid magnet links by both v1 and v2 info hashes + const auto altID = TorrentID::fromSHA1Hash(infoHash.v1()); + m_downloadedMetadata[altID] = alert->handle; + } + } + } + }); return true; } @@ -5453,6 +5542,8 @@ lt::torrent_handle SessionImpl::reloadTorrent(const lt::torrent_handle ¤tH params.storage = customStorageConstructor; #endif + // libtorrent will post an add_torrent_alert anyway, so we have to add an empty handler to ignore it. + m_addTorrentAlertHandlers.enqueue({}); return m_nativeSession->add_torrent(std::move(params)); } @@ -5780,63 +5871,12 @@ void SessionImpl::handleAddTorrentAlert(const lt::add_torrent_alert *alert) { ++m_receivedAddTorrentAlertsCount; - if (alert->error) - { - const QString msg = QString::fromStdString(alert->message()); - LogMsg(tr("Failed to load torrent. Reason: \"%1\"").arg(msg), Log::WARNING); - emit loadTorrentFailed(msg); - - const InfoHash infoHash = getInfoHash(alert->params); -#ifdef QBT_USES_LIBTORRENT2 - if (infoHash.isHybrid()) - m_hybridTorrentsByAltID.remove(TorrentID::fromSHA1Hash(infoHash.v1())); -#endif - if (const auto loadingTorrentsIter = m_loadingTorrents.constFind(TorrentID::fromInfoHash(infoHash)) - ; loadingTorrentsIter != m_loadingTorrents.cend()) - { - const AddTorrentError::Kind errorKind = (alert->error == lt::errors::duplicate_torrent) - ? AddTorrentError::DuplicateTorrent : AddTorrentError::Other; - emit addTorrentFailed(infoHash, {errorKind, msg}); - m_loadingTorrents.erase(loadingTorrentsIter); - } - else if (const auto downloadedMetadataIter = m_downloadedMetadata.constFind(TorrentID::fromInfoHash(infoHash)) - ; downloadedMetadataIter != m_downloadedMetadata.cend()) - { - m_downloadedMetadata.erase(downloadedMetadataIter); - if (infoHash.isHybrid()) - { - // index hybrid magnet links by both v1 and v2 info hashes - const auto altID = TorrentID::fromSHA1Hash(infoHash.v1()); - m_downloadedMetadata.remove(altID); - } - } - + Q_ASSERT(!m_addTorrentAlertHandlers.isEmpty()); + if (m_addTorrentAlertHandlers.isEmpty()) [[unlikely]] return; - } - const InfoHash infoHash = getInfoHash(alert->handle); - const auto torrentID = TorrentID::fromInfoHash(infoHash); - - if (const auto loadingTorrentsIter = m_loadingTorrents.constFind(torrentID) - ; loadingTorrentsIter != m_loadingTorrents.cend()) - { - const LoadTorrentParams params = loadingTorrentsIter.value(); - m_loadingTorrents.erase(loadingTorrentsIter); - - Torrent *torrent = createTorrent(alert->handle, params); - m_loadedTorrents.append(torrent); - } - else if (const auto downloadedMetadataIter = m_downloadedMetadata.find(torrentID) - ; downloadedMetadataIter != m_downloadedMetadata.end()) - { - downloadedMetadataIter.value() = alert->handle; - if (infoHash.isHybrid()) - { - // index hybrid magnet links by both v1 and v2 info hashes - const auto altID = TorrentID::fromSHA1Hash(infoHash.v1()); - m_downloadedMetadata[altID] = alert->handle; - } - } + if (const AddTorrentAlertHandler handleAlert = m_addTorrentAlertHandlers.dequeue()) + handleAlert(alert); } void SessionImpl::handleAlert(const lt::alert *alert) @@ -5989,37 +6029,12 @@ TorrentImpl *SessionImpl::createTorrent(const lt::torrent_handle &nativeHandle, if (const InfoHash infoHash = torrent->infoHash(); infoHash.isHybrid()) m_hybridTorrentsByAltID.insert(TorrentID::fromSHA1Hash(infoHash.v1()), torrent); - if (isRestored()) - { - if (params.addToQueueTop) - nativeHandle.queue_position_top(); - - torrent->requestResumeData(lt::torrent_handle::save_info_dict); - - // The following is useless for newly added magnet - if (torrent->hasMetadata()) - { - if (!torrentExportDirectory().isEmpty()) - exportTorrentFile(torrent, torrentExportDirectory()); - } - } - if (((torrent->ratioLimit() >= 0) || (torrent->seedingTimeLimit() >= 0)) && !m_seedingLimitTimer->isActive()) { m_seedingLimitTimer->start(); } - if (!isRestored()) - { - LogMsg(tr("Restored torrent. Torrent: \"%1\"").arg(torrent->name())); - } - else - { - LogMsg(tr("Added new torrent. Torrent: \"%1\"").arg(torrent->name())); - emit torrentAdded(torrent); - } - // Torrent could have error just after adding to libtorrent if (torrent->hasError()) LogMsg(tr("Torrent errored. Torrent: \"%1\". Error: \"%2\"").arg(torrent->name(), torrent->error()), Log::WARNING); diff --git a/src/base/bittorrent/sessionimpl.h b/src/base/bittorrent/sessionimpl.h index 7b1a8ae39..af8c3121d 100644 --- a/src/base/bittorrent/sessionimpl.h +++ b/src/base/bittorrent/sessionimpl.h @@ -30,6 +30,7 @@ #pragma once #include +#include #include #include @@ -44,6 +45,7 @@ #include #include #include +#include #include #include @@ -815,6 +817,9 @@ namespace BitTorrent FileSearcher *m_fileSearcher = nullptr; TorrentContentRemover *m_torrentContentRemover = nullptr; + using AddTorrentAlertHandler = std::function; + QQueue m_addTorrentAlertHandlers; + QHash m_downloadedMetadata; QHash m_torrents; From ab04064adc2a1be9e6906b0675660894487811fb Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (Glassez)" Date: Fri, 2 May 2025 19:04:02 +0300 Subject: [PATCH 23/45] Store AddTorrentParams inside alert handlers --- src/base/bittorrent/sessionimpl.cpp | 92 ++++++++--------------------- src/base/bittorrent/sessionimpl.h | 1 - 2 files changed, 25 insertions(+), 68 deletions(-) diff --git a/src/base/bittorrent/sessionimpl.cpp b/src/base/bittorrent/sessionimpl.cpp index c08fd616b..278e10d88 100644 --- a/src/base/bittorrent/sessionimpl.cpp +++ b/src/base/bittorrent/sessionimpl.cpp @@ -1620,31 +1620,20 @@ void SessionImpl::processNextResumeData(ResumeSessionContext *context) #endif qDebug() << "Starting up torrent" << torrentID.toString() << "..."; - m_loadingTorrents.insert(torrentID, resumeData); m_nativeSession->async_add_torrent(resumeData.ltAddTorrentParams); - m_addTorrentAlertHandlers.enqueue([this](const lt::add_torrent_alert *alert) + m_addTorrentAlertHandlers.enqueue([this, resumeData = std::move(resumeData)](const lt::add_torrent_alert *alert) { if (alert->error) { const QString msg = QString::fromStdString(alert->message()); LogMsg(tr("Failed to load torrent. Reason: \"%1\"").arg(msg), Log::WARNING); - m_loadingTorrents.remove(getInfoHash(alert->params).toTorrentID()); } else { - const TorrentID torrentID = getInfoHash(alert->handle).toTorrentID(); + Torrent *torrent = createTorrent(alert->handle, resumeData); + m_loadedTorrents.append(torrent); - if (const auto loadingTorrentsIter = m_loadingTorrents.constFind(torrentID) - ; loadingTorrentsIter != m_loadingTorrents.cend()) - { - const LoadTorrentParams params = loadingTorrentsIter.value(); - m_loadingTorrents.erase(loadingTorrentsIter); - - Torrent *torrent = createTorrent(alert->handle, params); - m_loadedTorrents.append(torrent); - - LogMsg(tr("Restored torrent. Torrent: \"%1\"").arg(torrent->name())); - } + LogMsg(tr("Restored torrent. Torrent: \"%1\"").arg(torrent->name())); } }); @@ -2796,14 +2785,6 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr // alternative ID can be useful to find existing torrent in case if hybrid torrent was added by v1 info hash const auto altID = (infoHash.isHybrid() ? TorrentID::fromSHA1Hash(infoHash.v1()) : TorrentID()); - // We should not add the torrent if it is already - // processed or is pending to add to session - if (m_loadingTorrents.contains(id) || (infoHash.isHybrid() && m_loadingTorrents.contains(altID))) - { - emit addTorrentFailed(infoHash, {AddTorrentError::DuplicateTorrent, tr("Duplicate torrent")}); - return false; - } - if (Torrent *torrent = findTorrent(infoHash)) { // a duplicate torrent is being added @@ -3011,8 +2992,6 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr p.storage = customStorageConstructor; #endif - m_loadingTorrents.insert(id, loadTorrentParams); - const auto resolveFileNames = [&, this] { if (!needFindIncompleteFiles) @@ -3023,15 +3002,9 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr return findIncompleteFiles(actualSavePath, actualDownloadPath, filePaths); }; - resolveFileNames().then(this, [this, id](const FileSearchResult &result) + resolveFileNames().then(this, [this, id, loadTorrentParams = std::move(loadTorrentParams)](const FileSearchResult &result) mutable { - const auto loadingTorrentsIter = m_loadingTorrents.find(id); - Q_ASSERT(loadingTorrentsIter != m_loadingTorrents.end()); - if (loadingTorrentsIter == m_loadingTorrents.end()) [[unlikely]] - return; - - LoadTorrentParams ¶ms = loadingTorrentsIter.value(); - lt::add_torrent_params &p = params.ltAddTorrentParams; + lt::add_torrent_params &p = loadTorrentParams.ltAddTorrentParams; p.save_path = result.savePath.toString().toStdString(); if (p.ti) @@ -3043,7 +3016,7 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr } m_nativeSession->async_add_torrent(p); - m_addTorrentAlertHandlers.enqueue([this](const lt::add_torrent_alert *alert) + m_addTorrentAlertHandlers.enqueue([this, loadTorrentParams = std::move(loadTorrentParams)](const lt::add_torrent_alert *alert) { if (alert->error) { @@ -3051,41 +3024,28 @@ bool SessionImpl::addTorrent_impl(const TorrentDescriptor &source, const AddTorr LogMsg(tr("Failed to add torrent. Reason: \"%1\"").arg(msg), Log::WARNING); const InfoHash infoHash = getInfoHash(alert->params); - if (const auto loadingTorrentsIter = m_loadingTorrents.constFind(TorrentID::fromInfoHash(infoHash)) - ; loadingTorrentsIter != m_loadingTorrents.cend()) - { - const AddTorrentError::Kind errorKind = (alert->error == lt::errors::duplicate_torrent) - ? AddTorrentError::DuplicateTorrent : AddTorrentError::Other; - emit addTorrentFailed(infoHash, {errorKind, msg}); - m_loadingTorrents.erase(loadingTorrentsIter); - } + const AddTorrentError::Kind errorKind = (alert->error == lt::errors::duplicate_torrent) + ? AddTorrentError::DuplicateTorrent : AddTorrentError::Other; + emit addTorrentFailed(infoHash, {errorKind, msg}); } else { - const TorrentID torrentID = getInfoHash(alert->handle).toTorrentID(); - if (const auto loadingTorrentsIter = m_loadingTorrents.constFind(torrentID) - ; loadingTorrentsIter != m_loadingTorrents.cend()) + if (loadTorrentParams.addToQueueTop) + alert->handle.queue_position_top(); + + TorrentImpl *torrent = createTorrent(alert->handle, loadTorrentParams); + m_loadedTorrents.append(torrent); + + torrent->requestResumeData(lt::torrent_handle::save_info_dict); + + LogMsg(tr("Added new torrent. Torrent: \"%1\"").arg(torrent->name())); + emit torrentAdded(torrent); + + // The following is useless for newly added magnet + if (torrent->hasMetadata()) { - const LoadTorrentParams params = loadingTorrentsIter.value(); - m_loadingTorrents.erase(loadingTorrentsIter); - - if (params.addToQueueTop) - alert->handle.queue_position_top(); - - TorrentImpl *torrent = createTorrent(alert->handle, params); - m_loadedTorrents.append(torrent); - - torrent->requestResumeData(lt::torrent_handle::save_info_dict); - - LogMsg(tr("Added new torrent. Torrent: \"%1\"").arg(torrent->name())); - emit torrentAdded(torrent); - - // The following is useless for newly added magnet - if (torrent->hasMetadata()) - { - if (!torrentExportDirectory().isEmpty()) - exportTorrentFile(torrent, torrentExportDirectory()); - } + if (!torrentExportDirectory().isEmpty()) + exportTorrentFile(torrent, torrentExportDirectory()); } } }); @@ -5318,8 +5278,6 @@ bool SessionImpl::isKnownTorrent(const InfoHash &infoHash) const // in case if hybrid torrent was added by v1 info hash const auto altID = (isHybrid ? TorrentID::fromSHA1Hash(infoHash.v1()) : TorrentID()); - if (m_loadingTorrents.contains(id) || (isHybrid && m_loadingTorrents.contains(altID))) - return true; if (m_downloadedMetadata.contains(id) || (isHybrid && m_downloadedMetadata.contains(altID))) return true; return findTorrent(infoHash); diff --git a/src/base/bittorrent/sessionimpl.h b/src/base/bittorrent/sessionimpl.h index af8c3121d..aec79c4ea 100644 --- a/src/base/bittorrent/sessionimpl.h +++ b/src/base/bittorrent/sessionimpl.h @@ -824,7 +824,6 @@ namespace BitTorrent QHash m_torrents; QHash m_hybridTorrentsByAltID; - QHash m_loadingTorrents; QHash m_removingTorrents; QHash m_changedTorrentIDs; QMap m_categories; From dcaf4b6d8066cb0113489fef5c5ed346e98e2562 Mon Sep 17 00:00:00 2001 From: Vladimir Golovnev Date: Sat, 10 May 2025 10:17:35 +0300 Subject: [PATCH 24/45] Fix async result handlers PR #22669. Closes #22644. --- src/gui/properties/peerlistwidget.cpp | 5 ++++- src/gui/properties/propertieswidget.cpp | 14 +++++++++----- src/gui/torrentcontentmodel.cpp | 9 ++------- src/gui/trackerlist/trackerlistmodel.cpp | 12 ++++++------ 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/gui/properties/peerlistwidget.cpp b/src/gui/properties/peerlistwidget.cpp index a6c44d106..4c27d4eb4 100644 --- a/src/gui/properties/peerlistwidget.cpp +++ b/src/gui/properties/peerlistwidget.cpp @@ -409,8 +409,11 @@ void PeerListWidget::loadPeers(const BitTorrent::Torrent *torrent) using TorrentPtr = QPointer; torrent->fetchPeerInfo().then(this, [this, torrent = TorrentPtr(torrent)](const QList &peers) { - if (torrent != m_properties->getCurrentTorrent()) + if (const BitTorrent::Torrent *currentTorrent = m_properties->getCurrentTorrent(); + !currentTorrent || (currentTorrent != torrent)) + { return; + } // Remove I2P peers since they will be completely reloaded. for (const QStandardItem *item : asConst(m_I2PPeerItems)) diff --git a/src/gui/properties/propertieswidget.cpp b/src/gui/properties/propertieswidget.cpp index 8a76e4663..d86f5a074 100644 --- a/src/gui/properties/propertieswidget.cpp +++ b/src/gui/properties/propertieswidget.cpp @@ -480,9 +480,10 @@ void PropertiesWidget::loadDynamicData() showPiecesAvailability(true); using TorrentPtr = QPointer; - m_torrent->fetchPieceAvailability().then(this, [this, torrent = TorrentPtr(m_torrent)](const QList &pieceAvailability) + m_torrent->fetchPieceAvailability().then(this + , [this, torrent = TorrentPtr(m_torrent)](const QList &pieceAvailability) { - if (torrent == m_torrent) + if (m_torrent && (m_torrent == torrent)) m_piecesAvailability->setAvailability(pieceAvailability); }); @@ -497,9 +498,12 @@ void PropertiesWidget::loadDynamicData() qreal progress = m_torrent->progress() * 100.; m_ui->labelProgressVal->setText(Utils::String::fromDouble(progress, 1) + u'%'); - m_torrent->fetchDownloadingPieces().then(this, [this](const QBitArray &downloadingPieces) + using TorrentPtr = QPointer; + m_torrent->fetchDownloadingPieces().then(this + , [this, torrent = TorrentPtr(m_torrent)](const QBitArray &downloadingPieces) { - m_downloadedPieces->setProgress(m_torrent->pieces(), downloadingPieces); + if (m_torrent && (m_torrent == torrent)) + m_downloadedPieces->setProgress(m_torrent->pieces(), downloadingPieces); }); } else @@ -527,7 +531,7 @@ void PropertiesWidget::loadUrlSeeds() using TorrentPtr = QPointer; m_torrent->fetchURLSeeds().then(this, [this, torrent = TorrentPtr(m_torrent)](const QList &urlSeeds) { - if (torrent != m_torrent) + if (!m_torrent || (m_torrent != torrent)) return; m_ui->listWebSeeds->clear(); diff --git a/src/gui/torrentcontentmodel.cpp b/src/gui/torrentcontentmodel.cpp index 32e44c16f..2df7b8176 100644 --- a/src/gui/torrentcontentmodel.cpp +++ b/src/gui/torrentcontentmodel.cpp @@ -223,16 +223,11 @@ void TorrentContentModel::updateFilesAvailability() m_contentHandler->fetchAvailableFileFractions().then(this , [this, handler = HandlerPtr(m_contentHandler)](const QList &availableFileFractions) { - if (handler != m_contentHandler) - return; - - Q_ASSERT(m_filesIndex.size() == availableFileFractions.size()); - // XXX: Why is this necessary? - if (m_filesIndex.size() != availableFileFractions.size()) [[unlikely]] + if (!m_contentHandler || (m_contentHandler != handler)) return; for (int i = 0; i < m_filesIndex.size(); ++i) - m_filesIndex[i]->setAvailability(availableFileFractions[i]); + m_filesIndex[i]->setAvailability(availableFileFractions.value(i, 0)); // Update folders progress in the tree m_rootItem->recalculateProgress(); }); diff --git a/src/gui/trackerlist/trackerlistmodel.cpp b/src/gui/trackerlist/trackerlistmodel.cpp index b13b067b6..4c90e0a6a 100644 --- a/src/gui/trackerlist/trackerlistmodel.cpp +++ b/src/gui/trackerlist/trackerlistmodel.cpp @@ -312,14 +312,14 @@ void TrackerListModel::populate() using TorrentPtr = QPointer; m_torrent->fetchPeerInfo().then(this, [this, torrent = TorrentPtr(m_torrent)](const QList &peers) { - if (torrent != m_torrent) + if (!m_torrent || (m_torrent != torrent)) return; - // XXX: libtorrent should provide this info... - // Count peers from DHT, PeX, LSD - uint seedsDHT = 0, seedsPeX = 0, seedsLSD = 0, peersDHT = 0, peersPeX = 0, peersLSD = 0; - for (const BitTorrent::PeerInfo &peer : peers) - { + // XXX: libtorrent should provide this info... + // Count peers from DHT, PeX, LSD + uint seedsDHT = 0, seedsPeX = 0, seedsLSD = 0, peersDHT = 0, peersPeX = 0, peersLSD = 0; + for (const BitTorrent::PeerInfo &peer : peers) + { if (peer.isConnecting()) continue; From 86e4b662ce6af926e0d1d3d00266efcdae8aebc0 Mon Sep 17 00:00:00 2001 From: justusaac <72957314+justusaac@users.noreply.github.com> Date: Sat, 10 May 2025 03:08:19 -0500 Subject: [PATCH 25/45] WebUI: Select multiple files to rename with Shift Convenience feature in the "Rename Files" menu in the WebUI. If you click one file's checkbox, and then click another with Shift held, all the checkboxes between those two will be selected/unselected based on the state of the first checkbox. It's based on what the Windows file explorer does when holding Ctrl and Shift Closes #22455. PR #22610. --- src/webui/www/private/scripts/dynamicTable.js | 41 ++++++++++++++++--- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/src/webui/www/private/scripts/dynamicTable.js b/src/webui/www/private/scripts/dynamicTable.js index fdbbca346..ac38ee42a 100644 --- a/src/webui/www/private/scripts/dynamicTable.js +++ b/src/webui/www/private/scripts/dynamicTable.js @@ -2185,6 +2185,7 @@ window.qBittorrent.DynamicTable ??= (() => { prevFilteredRows = []; prevSortedColumn = null; prevReverseSort = null; + prevCheckboxNum = null; fileTree = new window.qBittorrent.FileTree.FileTree(); setupVirtualList() { @@ -2344,13 +2345,41 @@ window.qBittorrent.DynamicTable ??= (() => { checkbox.type = "checkbox"; checkbox.className = "RenamingCB"; checkbox.addEventListener("click", (e) => { - const id = e.target.dataset.id; - const node = that.getNode(id); - node.checked = e.target.checked ? 0 : 1; - node.full_data.checked = node.checked; - that.updateGlobalCheckbox(); - that.onRowSelectionChange(node); e.stopPropagation(); + const targetId = e.target.dataset.id; + const ids = []; + // when holding shift, set all files between the previously selected one and the clicked one + if (e.shiftKey && (that.prevCheckboxNum !== null) && (targetId !== that.prevCheckboxNum)) { + const targetState = that.tableBody.querySelector(`.RenamingCB[data-id="${that.prevCheckboxNum}"]`).checked; + const checkboxes = that.tableBody.getElementsByClassName("RenamingCB"); + let started = false; + for (const cb of checkboxes) { + const currId = cb.dataset.id; + if ((currId === targetId) || (currId === that.prevCheckboxNum)) { + if (started) { + ids.push(currId); + cb.checked = targetState; + break; + } + started = true; + } + if (started) { + ids.push(currId); + cb.checked = targetState; + } + } + } + else { + ids.push(targetId); + } + for (const id of ids) { + const node = that.getNode(id); + node.checked = e.target.checked ? 0 : 1; + node.full_data.checked = node.checked; + } + that.updateGlobalCheckbox(); + that.onRowSelectionChange(that.getNode(targetId)); + that.prevCheckboxNum = targetId; }); checkbox.indeterminate = false; td.append(checkbox); From 13f9c20a69bf89baa750a05c9697fddc2cc2e19d Mon Sep 17 00:00:00 2001 From: dezza <402927+dezza@users.noreply.github.com> Date: Sat, 10 May 2025 10:48:05 +0200 Subject: [PATCH 26/45] WebUI: Remove `unselectable` from General tab Making General-tab text `unselectable` is not an improvement. It begs to add a new `Copy -> Save path` feature, because using `Set location` to copy save path (*which requires a request*) is not faster than simply copying it from the `General` tab by double-left clicking and pressing `CTRL+C`. I don't see a reason why its necessary to software-restrict people from copying details from the `General`-tab - there are several reasons why you would - incl. the above mentioned usecase for quickly copying save-path, but other than that its counterproductive to limit people from copying the details displayed. PR #22663. --- src/webui/www/private/views/properties.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webui/www/private/views/properties.html b/src/webui/www/private/views/properties.html index e3cb42b1b..fbcaa1d53 100644 --- a/src/webui/www/private/views/properties.html +++ b/src/webui/www/private/views/properties.html @@ -1,4 +1,4 @@ -