mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-08-20 13:23:34 -07:00
WebUI: Store durable settings in client data API
This commit is contained in:
parent
95e6ac1550
commit
f6d09f4583
13 changed files with 261 additions and 75 deletions
|
@ -29,6 +29,7 @@
|
||||||
<script defer src="scripts/monkeypatch.js?v=${CACHEID}"></script>
|
<script defer src="scripts/monkeypatch.js?v=${CACHEID}"></script>
|
||||||
<script defer src="scripts/cache.js?v=${CACHEID}"></script>
|
<script defer src="scripts/cache.js?v=${CACHEID}"></script>
|
||||||
<script defer src="scripts/localpreferences.js?v=${CACHEID}"></script>
|
<script defer src="scripts/localpreferences.js?v=${CACHEID}"></script>
|
||||||
|
<script defer src="scripts/client-data.js?v=${CACHEID}"></script>
|
||||||
<script defer src="scripts/color-scheme.js?v=${CACHEID}"></script>
|
<script defer src="scripts/color-scheme.js?v=${CACHEID}"></script>
|
||||||
<script defer src="scripts/mocha-init.js?locale=${LANG}&v=${CACHEID}"></script>
|
<script defer src="scripts/mocha-init.js?locale=${LANG}&v=${CACHEID}"></script>
|
||||||
<script defer src="scripts/lib/clipboard-copy.js"></script>
|
<script defer src="scripts/lib/clipboard-copy.js"></script>
|
||||||
|
|
|
@ -44,9 +44,10 @@ window.qBittorrent.AddTorrent ??= (() => {
|
||||||
let source = "";
|
let source = "";
|
||||||
|
|
||||||
const LocalPreferences = new window.qBittorrent.LocalPreferences.LocalPreferences();
|
const LocalPreferences = new window.qBittorrent.LocalPreferences.LocalPreferences();
|
||||||
|
const clientData = window.parent.qBittorrent.ClientData;
|
||||||
|
|
||||||
const getCategories = () => {
|
const getCategories = () => {
|
||||||
const defaultCategory = LocalPreferences.get("add_torrent_default_category", "");
|
const defaultCategory = clientData.getCached("add_torrent_default_category") ?? "";
|
||||||
const categorySelect = document.getElementById("categorySelect");
|
const categorySelect = document.getElementById("categorySelect");
|
||||||
for (const name of window.parent.qBittorrent.Client.categoryMap.keys()) {
|
for (const name of window.parent.qBittorrent.Client.categoryMap.keys()) {
|
||||||
const option = document.createElement("option");
|
const option = document.createElement("option");
|
||||||
|
@ -311,10 +312,7 @@ window.qBittorrent.AddTorrent ??= (() => {
|
||||||
|
|
||||||
if (document.getElementById("setDefaultCategory").checked) {
|
if (document.getElementById("setDefaultCategory").checked) {
|
||||||
const category = document.getElementById("category").value.trim();
|
const category = document.getElementById("category").value.trim();
|
||||||
if (category.length === 0)
|
clientData.set({ add_torrent_default_category: category.length > 0 ? category : null });
|
||||||
LocalPreferences.remove("add_torrent_default_category");
|
|
||||||
else
|
|
||||||
LocalPreferences.set("add_torrent_default_category", category);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
128
src/webui/www/private/scripts/client-data.js
Normal file
128
src/webui/www/private/scripts/client-data.js
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
|
* Copyright (C) 2025 Thomas Piccirello <thomas@piccirello.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the copyright holders give permission to
|
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with
|
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library),
|
||||||
|
* and distribute the linked executables. You must obey the GNU General Public
|
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you
|
||||||
|
* modify file(s), you may extend this exception to your version of the file(s),
|
||||||
|
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||||
|
* exception statement from your version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
window.qBittorrent ??= {};
|
||||||
|
window.qBittorrent.ClientData ??= (() => {
|
||||||
|
const exports = () => {
|
||||||
|
return {
|
||||||
|
getCached: (...args) => instance.getCached(...args),
|
||||||
|
get: (...args) => instance.get(...args),
|
||||||
|
set: (...args) => instance.set(...args),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// this is exposed as a singleton
|
||||||
|
class ClientData {
|
||||||
|
/**
|
||||||
|
* @type Map<string, any>
|
||||||
|
*/
|
||||||
|
#cache = new Map();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string[]} keys
|
||||||
|
* @returns {Record<string, any>}
|
||||||
|
*/
|
||||||
|
async #fetch(keys) {
|
||||||
|
return await fetch("api/v2/app/clientData", {
|
||||||
|
method: "POST",
|
||||||
|
body: new URLSearchParams({
|
||||||
|
keys: JSON.stringify(keys)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then(async (response) => {
|
||||||
|
if (!response.ok)
|
||||||
|
return;
|
||||||
|
|
||||||
|
return await response.json();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Record<string, any>} data
|
||||||
|
*/
|
||||||
|
async #set(data) {
|
||||||
|
await fetch("api/v2/app/setClientData", {
|
||||||
|
method: "POST",
|
||||||
|
body: new URLSearchParams({
|
||||||
|
data: JSON.stringify(data)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (!response.ok)
|
||||||
|
throw new Error("Failed to store client data");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} key
|
||||||
|
* @returns {any}
|
||||||
|
*/
|
||||||
|
getCached(key) {
|
||||||
|
return this.#cache.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string[]} keys
|
||||||
|
* @returns {Record<string, any>}
|
||||||
|
*/
|
||||||
|
async get(keys = []) {
|
||||||
|
const keysToFetch = keys.filter((key) => !this.#cache.has(key));
|
||||||
|
if (keysToFetch.length > 0) {
|
||||||
|
const fetchedData = await this.#fetch(keysToFetch);
|
||||||
|
for (const [key, value] of Object.entries(fetchedData))
|
||||||
|
this.#cache.set(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.fromEntries(keys.map((key) => ([key, this.#cache.get(key)])));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Record<string, any>} data
|
||||||
|
*/
|
||||||
|
async set(data) {
|
||||||
|
try {
|
||||||
|
await this.#set(data);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update cache
|
||||||
|
for (const [key, value] of Object.entries(data))
|
||||||
|
this.#cache.set(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const instance = new ClientData();
|
||||||
|
|
||||||
|
return exports();
|
||||||
|
})();
|
||||||
|
Object.freeze(window.qBittorrent.ClientData);
|
|
@ -31,6 +31,7 @@ window.qBittorrent.Client ??= (() => {
|
||||||
return {
|
return {
|
||||||
setup: setup,
|
setup: setup,
|
||||||
initializeCaches: initializeCaches,
|
initializeCaches: initializeCaches,
|
||||||
|
initializeClientData: initializeClientData,
|
||||||
closeWindow: closeWindow,
|
closeWindow: closeWindow,
|
||||||
closeFrameWindow: closeFrameWindow,
|
closeFrameWindow: closeFrameWindow,
|
||||||
getSyncMainDataInterval: getSyncMainDataInterval,
|
getSyncMainDataInterval: getSyncMainDataInterval,
|
||||||
|
@ -56,15 +57,47 @@ window.qBittorrent.Client ??= (() => {
|
||||||
const tagMap = new Map();
|
const tagMap = new Map();
|
||||||
|
|
||||||
let cacheAllSettled;
|
let cacheAllSettled;
|
||||||
|
let clientDataPromise;
|
||||||
const setup = () => {
|
const setup = () => {
|
||||||
// fetch various data and store it in memory
|
// fetch various data and store it in memory
|
||||||
|
clientDataPromise = window.qBittorrent.ClientData.get([
|
||||||
|
"show_search_engine",
|
||||||
|
"show_rss_reader",
|
||||||
|
"show_log_viewer",
|
||||||
|
"speed_in_browser_title_bar",
|
||||||
|
"show_top_toolbar",
|
||||||
|
"show_status_bar",
|
||||||
|
"show_filters_sidebar",
|
||||||
|
"hide_zero_status_filters",
|
||||||
|
"color_scheme",
|
||||||
|
"full_url_tracker_column",
|
||||||
|
"use_alt_row_colors",
|
||||||
|
"use_virtual_list",
|
||||||
|
"dblclick_complete",
|
||||||
|
"dblclick_download",
|
||||||
|
"dblclick_filter",
|
||||||
|
"search_in_filter",
|
||||||
|
"qbt_selected_log_levels",
|
||||||
|
"add_torrent_default_category",
|
||||||
|
]);
|
||||||
|
|
||||||
cacheAllSettled = Promise.allSettled([
|
cacheAllSettled = Promise.allSettled([
|
||||||
window.qBittorrent.Cache.buildInfo.init(),
|
window.qBittorrent.Cache.buildInfo.init(),
|
||||||
window.qBittorrent.Cache.preferences.init(),
|
window.qBittorrent.Cache.preferences.init(),
|
||||||
window.qBittorrent.Cache.qbtVersion.init()
|
window.qBittorrent.Cache.qbtVersion.init(),
|
||||||
|
clientDataPromise,
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const initializeClientData = async () => {
|
||||||
|
try {
|
||||||
|
await clientDataPromise;
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error(`Failed to initialize client data. Reason: "${error}".`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const initializeCaches = async () => {
|
const initializeCaches = async () => {
|
||||||
const results = await cacheAllSettled;
|
const results = await cacheAllSettled;
|
||||||
for (const [idx, result] of results.entries()) {
|
for (const [idx, result] of results.entries()) {
|
||||||
|
@ -224,8 +257,8 @@ let queueing_enabled = true;
|
||||||
let serverSyncMainDataInterval = 1500;
|
let serverSyncMainDataInterval = 1500;
|
||||||
let customSyncMainDataInterval = null;
|
let customSyncMainDataInterval = null;
|
||||||
let useSubcategories = true;
|
let useSubcategories = true;
|
||||||
const useAutoHideZeroStatusFilters = LocalPreferences.get("hide_zero_status_filters", "false") === "true";
|
let useAutoHideZeroStatusFilters = false;
|
||||||
const displayFullURLTrackerColumn = LocalPreferences.get("full_url_tracker_column", "false") === "true";
|
let displayFullURLTrackerColumn = false;
|
||||||
|
|
||||||
/* Categories filter */
|
/* Categories filter */
|
||||||
const CATEGORIES_ALL = "b4af0e4c-e76d-4bac-a392-46cbc18d9655";
|
const CATEGORIES_ALL = "b4af0e4c-e76d-4bac-a392-46cbc18d9655";
|
||||||
|
@ -251,6 +284,8 @@ const TRACKERS_WARNING = "82a702c5-210c-412b-829f-97632d7557e9";
|
||||||
// Map<trackerHost: String, Map<trackerURL: String, torrents: Set>>
|
// Map<trackerHost: String, Map<trackerURL: String, torrents: Set>>
|
||||||
const trackerMap = new Map();
|
const trackerMap = new Map();
|
||||||
|
|
||||||
|
const clientData = window.qBittorrent.ClientData;
|
||||||
|
|
||||||
let selectedTracker = LocalPreferences.get("selected_tracker", TRACKERS_ALL);
|
let selectedTracker = LocalPreferences.get("selected_tracker", TRACKERS_ALL);
|
||||||
let setTrackerFilter = () => {};
|
let setTrackerFilter = () => {};
|
||||||
|
|
||||||
|
@ -259,7 +294,13 @@ let selectedStatus = LocalPreferences.get("selected_filter", "all");
|
||||||
let setStatusFilter = () => {};
|
let setStatusFilter = () => {};
|
||||||
let toggleFilterDisplay = () => {};
|
let toggleFilterDisplay = () => {};
|
||||||
|
|
||||||
window.addEventListener("DOMContentLoaded", (event) => {
|
window.addEventListener("DOMContentLoaded", async (event) => {
|
||||||
|
await window.qBittorrent.Client.initializeClientData();
|
||||||
|
window.qBittorrent.ColorScheme.update();
|
||||||
|
|
||||||
|
useAutoHideZeroStatusFilters = clientData.getCached("hide_zero_status_filters") === true;
|
||||||
|
displayFullURLTrackerColumn = clientData.getCached("full_url_tracker_column") === true;
|
||||||
|
|
||||||
window.qBittorrent.LocalPreferences.upgrade();
|
window.qBittorrent.LocalPreferences.upgrade();
|
||||||
|
|
||||||
let isSearchPanelLoaded = false;
|
let isSearchPanelLoaded = false;
|
||||||
|
@ -406,6 +447,13 @@ window.addEventListener("DOMContentLoaded", (event) => {
|
||||||
LocalPreferences.set(`filter_${filterListID.replace("FilterList", "")}_collapsed`, filterList.classList.toggle("invisible").toString());
|
LocalPreferences.set(`filter_${filterListID.replace("FilterList", "")}_collapsed`, filterList.classList.toggle("invisible").toString());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const highlightSelectedStatus = () => {
|
||||||
|
const statusFilter = document.getElementById("statusFilterList");
|
||||||
|
const filterID = `${selectedStatus}_filter`;
|
||||||
|
for (const status of statusFilter.children)
|
||||||
|
status.classList.toggle("selectedFilter", (status.id === filterID));
|
||||||
|
};
|
||||||
|
|
||||||
new MochaUI.Panel({
|
new MochaUI.Panel({
|
||||||
id: "Filters",
|
id: "Filters",
|
||||||
title: "Panel",
|
title: "Panel",
|
||||||
|
@ -427,35 +475,35 @@ window.addEventListener("DOMContentLoaded", (event) => {
|
||||||
initializeWindows();
|
initializeWindows();
|
||||||
|
|
||||||
// Show Top Toolbar is enabled by default
|
// Show Top Toolbar is enabled by default
|
||||||
let showTopToolbar = LocalPreferences.get("show_top_toolbar", "true") === "true";
|
let showTopToolbar = clientData.getCached("show_top_toolbar") !== false;
|
||||||
if (!showTopToolbar) {
|
if (!showTopToolbar) {
|
||||||
document.getElementById("showTopToolbarLink").firstElementChild.style.opacity = "0";
|
document.getElementById("showTopToolbarLink").firstElementChild.style.opacity = "0";
|
||||||
document.getElementById("mochaToolbar").classList.add("invisible");
|
document.getElementById("mochaToolbar").classList.add("invisible");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show Status Bar is enabled by default
|
// Show Status Bar is enabled by default
|
||||||
let showStatusBar = LocalPreferences.get("show_status_bar", "true") === "true";
|
let showStatusBar = clientData.getCached("show_status_bar") !== false;
|
||||||
if (!showStatusBar) {
|
if (!showStatusBar) {
|
||||||
document.getElementById("showStatusBarLink").firstElementChild.style.opacity = "0";
|
document.getElementById("showStatusBarLink").firstElementChild.style.opacity = "0";
|
||||||
document.getElementById("desktopFooterWrapper").classList.add("invisible");
|
document.getElementById("desktopFooterWrapper").classList.add("invisible");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show Filters Sidebar is enabled by default
|
// Show Filters Sidebar is enabled by default
|
||||||
let showFiltersSidebar = LocalPreferences.get("show_filters_sidebar", "true") === "true";
|
let showFiltersSidebar = clientData.getCached("show_filters_sidebar") !== false;
|
||||||
if (!showFiltersSidebar) {
|
if (!showFiltersSidebar) {
|
||||||
document.getElementById("showFiltersSidebarLink").firstElementChild.style.opacity = "0";
|
document.getElementById("showFiltersSidebarLink").firstElementChild.style.opacity = "0";
|
||||||
document.getElementById("filtersColumn").classList.add("invisible");
|
document.getElementById("filtersColumn").classList.add("invisible");
|
||||||
document.getElementById("filtersColumn_handle").classList.add("invisible");
|
document.getElementById("filtersColumn_handle").classList.add("invisible");
|
||||||
}
|
}
|
||||||
|
|
||||||
let speedInTitle = LocalPreferences.get("speed_in_browser_title_bar") === "true";
|
let speedInTitle = clientData.getCached("speed_in_browser_title_bar") === true;
|
||||||
if (!speedInTitle)
|
if (!speedInTitle)
|
||||||
document.getElementById("speedInBrowserTitleBarLink").firstElementChild.style.opacity = "0";
|
document.getElementById("speedInBrowserTitleBarLink").firstElementChild.style.opacity = "0";
|
||||||
|
|
||||||
// After showing/hiding the toolbar + status bar
|
// After showing/hiding the toolbar + status bar
|
||||||
window.qBittorrent.Client.showSearchEngine(LocalPreferences.get("show_search_engine") !== "false");
|
window.qBittorrent.Client.showSearchEngine(clientData.getCached("show_search_engine") !== false);
|
||||||
window.qBittorrent.Client.showRssReader(LocalPreferences.get("show_rss_reader") !== "false");
|
window.qBittorrent.Client.showRssReader(clientData.getCached("show_rss_reader") !== false);
|
||||||
window.qBittorrent.Client.showLogViewer(LocalPreferences.get("show_log_viewer") === "true");
|
window.qBittorrent.Client.showLogViewer(clientData.getCached("show_log_viewer") === true);
|
||||||
|
|
||||||
// After Show Top Toolbar
|
// After Show Top Toolbar
|
||||||
MochaUI.Desktop.setDesktopSize();
|
MochaUI.Desktop.setDesktopSize();
|
||||||
|
@ -572,13 +620,6 @@ window.addEventListener("DOMContentLoaded", (event) => {
|
||||||
window.qBittorrent.Filters.clearStatusFilter();
|
window.qBittorrent.Filters.clearStatusFilter();
|
||||||
};
|
};
|
||||||
|
|
||||||
const highlightSelectedStatus = () => {
|
|
||||||
const statusFilter = document.getElementById("statusFilterList");
|
|
||||||
const filterID = `${selectedStatus}_filter`;
|
|
||||||
for (const status of statusFilter.children)
|
|
||||||
status.classList.toggle("selectedFilter", (status.id === filterID));
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateCategoryList = () => {
|
const updateCategoryList = () => {
|
||||||
const categoryList = document.getElementById("categoryFilterList");
|
const categoryList = document.getElementById("categoryFilterList");
|
||||||
if (!categoryList)
|
if (!categoryList)
|
||||||
|
@ -1221,7 +1262,7 @@ window.addEventListener("DOMContentLoaded", (event) => {
|
||||||
|
|
||||||
document.getElementById("showTopToolbarLink").addEventListener("click", (e) => {
|
document.getElementById("showTopToolbarLink").addEventListener("click", (e) => {
|
||||||
showTopToolbar = !showTopToolbar;
|
showTopToolbar = !showTopToolbar;
|
||||||
LocalPreferences.set("show_top_toolbar", showTopToolbar.toString());
|
clientData.set({ show_top_toolbar: showTopToolbar });
|
||||||
if (showTopToolbar) {
|
if (showTopToolbar) {
|
||||||
document.getElementById("showTopToolbarLink").firstElementChild.style.opacity = "1";
|
document.getElementById("showTopToolbarLink").firstElementChild.style.opacity = "1";
|
||||||
document.getElementById("mochaToolbar").classList.remove("invisible");
|
document.getElementById("mochaToolbar").classList.remove("invisible");
|
||||||
|
@ -1235,7 +1276,7 @@ window.addEventListener("DOMContentLoaded", (event) => {
|
||||||
|
|
||||||
document.getElementById("showStatusBarLink").addEventListener("click", (e) => {
|
document.getElementById("showStatusBarLink").addEventListener("click", (e) => {
|
||||||
showStatusBar = !showStatusBar;
|
showStatusBar = !showStatusBar;
|
||||||
LocalPreferences.set("show_status_bar", showStatusBar.toString());
|
clientData.set({ show_status_bar: showStatusBar });
|
||||||
if (showStatusBar) {
|
if (showStatusBar) {
|
||||||
document.getElementById("showStatusBarLink").firstElementChild.style.opacity = "1";
|
document.getElementById("showStatusBarLink").firstElementChild.style.opacity = "1";
|
||||||
document.getElementById("desktopFooterWrapper").classList.remove("invisible");
|
document.getElementById("desktopFooterWrapper").classList.remove("invisible");
|
||||||
|
@ -1272,7 +1313,7 @@ window.addEventListener("DOMContentLoaded", (event) => {
|
||||||
|
|
||||||
document.getElementById("showFiltersSidebarLink").addEventListener("click", (e) => {
|
document.getElementById("showFiltersSidebarLink").addEventListener("click", (e) => {
|
||||||
showFiltersSidebar = !showFiltersSidebar;
|
showFiltersSidebar = !showFiltersSidebar;
|
||||||
LocalPreferences.set("show_filters_sidebar", showFiltersSidebar.toString());
|
clientData.set({ show_filters_sidebar: showFiltersSidebar });
|
||||||
if (showFiltersSidebar) {
|
if (showFiltersSidebar) {
|
||||||
document.getElementById("showFiltersSidebarLink").firstElementChild.style.opacity = "1";
|
document.getElementById("showFiltersSidebarLink").firstElementChild.style.opacity = "1";
|
||||||
document.getElementById("filtersColumn").classList.remove("invisible");
|
document.getElementById("filtersColumn").classList.remove("invisible");
|
||||||
|
@ -1288,7 +1329,7 @@ window.addEventListener("DOMContentLoaded", (event) => {
|
||||||
|
|
||||||
document.getElementById("speedInBrowserTitleBarLink").addEventListener("click", (e) => {
|
document.getElementById("speedInBrowserTitleBarLink").addEventListener("click", (e) => {
|
||||||
speedInTitle = !speedInTitle;
|
speedInTitle = !speedInTitle;
|
||||||
LocalPreferences.set("speed_in_browser_title_bar", speedInTitle.toString());
|
LocalPreferences.set("speed_in_browser_title_bar", speedInTitle);
|
||||||
if (speedInTitle)
|
if (speedInTitle)
|
||||||
document.getElementById("speedInBrowserTitleBarLink").firstElementChild.style.opacity = "1";
|
document.getElementById("speedInBrowserTitleBarLink").firstElementChild.style.opacity = "1";
|
||||||
else
|
else
|
||||||
|
@ -1298,19 +1339,19 @@ window.addEventListener("DOMContentLoaded", (event) => {
|
||||||
|
|
||||||
document.getElementById("showSearchEngineLink").addEventListener("click", (e) => {
|
document.getElementById("showSearchEngineLink").addEventListener("click", (e) => {
|
||||||
window.qBittorrent.Client.showSearchEngine(!window.qBittorrent.Client.isShowSearchEngine());
|
window.qBittorrent.Client.showSearchEngine(!window.qBittorrent.Client.isShowSearchEngine());
|
||||||
LocalPreferences.set("show_search_engine", window.qBittorrent.Client.isShowSearchEngine().toString());
|
clientData.set({ show_search_engine: window.qBittorrent.Client.isShowSearchEngine() });
|
||||||
updateTabDisplay();
|
updateTabDisplay();
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById("showRssReaderLink").addEventListener("click", (e) => {
|
document.getElementById("showRssReaderLink").addEventListener("click", (e) => {
|
||||||
window.qBittorrent.Client.showRssReader(!window.qBittorrent.Client.isShowRssReader());
|
window.qBittorrent.Client.showRssReader(!window.qBittorrent.Client.isShowRssReader());
|
||||||
LocalPreferences.set("show_rss_reader", window.qBittorrent.Client.isShowRssReader().toString());
|
clientData.set({ show_rss_reader: window.qBittorrent.Client.isShowRssReader() });
|
||||||
updateTabDisplay();
|
updateTabDisplay();
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById("showLogViewerLink").addEventListener("click", (e) => {
|
document.getElementById("showLogViewerLink").addEventListener("click", (e) => {
|
||||||
window.qBittorrent.Client.showLogViewer(!window.qBittorrent.Client.isShowLogViewer());
|
window.qBittorrent.Client.showLogViewer(!window.qBittorrent.Client.isShowLogViewer());
|
||||||
LocalPreferences.set("show_log_viewer", window.qBittorrent.Client.isShowLogViewer().toString());
|
clientData.set({ show_log_viewer: window.qBittorrent.Client.isShowLogViewer() });
|
||||||
updateTabDisplay();
|
updateTabDisplay();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1367,7 +1408,7 @@ window.addEventListener("DOMContentLoaded", (event) => {
|
||||||
// main window tabs
|
// main window tabs
|
||||||
|
|
||||||
const showTransfersTab = () => {
|
const showTransfersTab = () => {
|
||||||
const showFiltersSidebar = LocalPreferences.get("show_filters_sidebar", "true") === "true";
|
const showFiltersSidebar = clientData.getCached("show_filters_sidebar") !== false;
|
||||||
if (showFiltersSidebar) {
|
if (showFiltersSidebar) {
|
||||||
document.getElementById("filtersColumn").classList.remove("invisible");
|
document.getElementById("filtersColumn").classList.remove("invisible");
|
||||||
document.getElementById("filtersColumn_handle").classList.remove("invisible");
|
document.getElementById("filtersColumn_handle").classList.remove("invisible");
|
||||||
|
|
|
@ -36,12 +36,12 @@ window.qBittorrent.ColorScheme ??= (() => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const LocalPreferences = new window.qBittorrent.LocalPreferences.LocalPreferences();
|
|
||||||
const colorSchemeQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
const colorSchemeQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
||||||
|
const clientData = window.parent.qBittorrent.ClientData;
|
||||||
|
|
||||||
const update = () => {
|
const update = () => {
|
||||||
const root = document.documentElement;
|
const root = document.documentElement;
|
||||||
const colorScheme = LocalPreferences.get("color_scheme");
|
const colorScheme = clientData.getCached("color_scheme");
|
||||||
const validScheme = (colorScheme === "light") || (colorScheme === "dark");
|
const validScheme = (colorScheme === "light") || (colorScheme === "dark");
|
||||||
const isDark = colorSchemeQuery.matches;
|
const isDark = colorSchemeQuery.matches;
|
||||||
root.classList.toggle("dark", ((!validScheme && isDark) || (colorScheme === "dark")));
|
root.classList.toggle("dark", ((!validScheme && isDark) || (colorScheme === "dark")));
|
||||||
|
@ -52,5 +52,3 @@ window.qBittorrent.ColorScheme ??= (() => {
|
||||||
return exports();
|
return exports();
|
||||||
})();
|
})();
|
||||||
Object.freeze(window.qBittorrent.ColorScheme);
|
Object.freeze(window.qBittorrent.ColorScheme);
|
||||||
|
|
||||||
window.qBittorrent.ColorScheme.update();
|
|
||||||
|
|
|
@ -65,6 +65,7 @@ window.qBittorrent.DynamicTable ??= (() => {
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const clientData = window.qBittorrent.ClientData ?? window.parent.qBittorrent.ClientData;
|
||||||
let DynamicTableHeaderContextMenuClass = null;
|
let DynamicTableHeaderContextMenuClass = null;
|
||||||
|
|
||||||
if (typeof LocalPreferences === "undefined")
|
if (typeof LocalPreferences === "undefined")
|
||||||
|
@ -75,7 +76,7 @@ window.qBittorrent.DynamicTable ??= (() => {
|
||||||
this.dynamicTableDivId = dynamicTableDivId;
|
this.dynamicTableDivId = dynamicTableDivId;
|
||||||
this.dynamicTableFixedHeaderDivId = dynamicTableFixedHeaderDivId;
|
this.dynamicTableFixedHeaderDivId = dynamicTableFixedHeaderDivId;
|
||||||
this.dynamicTableDiv = document.getElementById(dynamicTableDivId);
|
this.dynamicTableDiv = document.getElementById(dynamicTableDivId);
|
||||||
this.useVirtualList = useVirtualList && (LocalPreferences.get("use_virtual_list", "false") === "true");
|
this.useVirtualList = useVirtualList && (clientData.getCached("use_virtual_list") === true);
|
||||||
this.fixedTableHeader = document.querySelector(`#${dynamicTableFixedHeaderDivId} thead tr`);
|
this.fixedTableHeader = document.querySelector(`#${dynamicTableFixedHeaderDivId} thead tr`);
|
||||||
this.hiddenTableHeader = this.dynamicTableDiv.querySelector("thead tr");
|
this.hiddenTableHeader = this.dynamicTableDiv.querySelector("thead tr");
|
||||||
this.table = this.dynamicTableDiv.querySelector("table");
|
this.table = this.dynamicTableDiv.querySelector("table");
|
||||||
|
@ -730,7 +731,7 @@ window.qBittorrent.DynamicTable ??= (() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
setupAltRow() {
|
setupAltRow() {
|
||||||
const useAltRowColors = (LocalPreferences.get("use_alt_row_colors", "true") === "true");
|
const useAltRowColors = clientData.getCached("use_alt_row_colors") !== false;
|
||||||
if (useAltRowColors)
|
if (useAltRowColors)
|
||||||
document.getElementById(this.dynamicTableDivId).classList.add("altRowColors");
|
document.getElementById(this.dynamicTableDivId).classList.add("altRowColors");
|
||||||
}
|
}
|
||||||
|
@ -1805,7 +1806,7 @@ window.qBittorrent.DynamicTable ??= (() => {
|
||||||
? "dblclick_download"
|
? "dblclick_download"
|
||||||
: "dblclick_complete";
|
: "dblclick_complete";
|
||||||
|
|
||||||
if (LocalPreferences.get(prefKey, "1") !== "1")
|
if (clientData.getCached(prefKey) === "0")
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (state.includes("stopped"))
|
if (state.includes("stopped"))
|
||||||
|
|
|
@ -107,8 +107,7 @@ window.qBittorrent.Search ??= (() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const init = () => {
|
const init = () => {
|
||||||
// load "Search in" preference from local storage
|
document.getElementById("searchInTorrentName").value = (window.qBittorrent.ClientData.getCached("search_in_filter") === "names") ? "names" : "everywhere";
|
||||||
document.getElementById("searchInTorrentName").value = (LocalPreferences.get("search_in_filter") === "names") ? "names" : "everywhere";
|
|
||||||
const searchResultsTableContextMenu = new window.qBittorrent.ContextMenu.ContextMenu({
|
const searchResultsTableContextMenu = new window.qBittorrent.ContextMenu.ContextMenu({
|
||||||
targets: "#searchResultsTableDiv tbody tr",
|
targets: "#searchResultsTableDiv tbody tr",
|
||||||
menu: "searchResultsTableMenu",
|
menu: "searchResultsTableMenu",
|
||||||
|
@ -804,7 +803,8 @@ window.qBittorrent.Search ??= (() => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const searchInTorrentName = () => {
|
const searchInTorrentName = () => {
|
||||||
LocalPreferences.set("search_in_filter", getSearchInTorrentName());
|
// don't await this
|
||||||
|
window.qBittorrent.ClientData.set({ search_in_filter: getSearchInTorrentName() });
|
||||||
searchFilterChanged();
|
searchFilterChanged();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -138,7 +138,7 @@
|
||||||
return option;
|
return option;
|
||||||
};
|
};
|
||||||
|
|
||||||
const init = () => {
|
const init = async () => {
|
||||||
const pieceSizeSelect = document.getElementById("pieceSize");
|
const pieceSizeSelect = document.getElementById("pieceSize");
|
||||||
pieceSizeSelect.appendChild(createSizeOption(0));
|
pieceSizeSelect.appendChild(createSizeOption(0));
|
||||||
for (let i = 4; i <= 17; ++i)
|
for (let i = 4; i <= 17; ++i)
|
||||||
|
@ -163,7 +163,7 @@
|
||||||
submit();
|
submit();
|
||||||
});
|
});
|
||||||
|
|
||||||
loadPreference();
|
await loadPreference();
|
||||||
window.qBittorrent.pathAutofill.attachPathAutofill();
|
window.qBittorrent.pathAutofill.attachPathAutofill();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -207,11 +207,13 @@
|
||||||
comments: document.getElementById("comments").value,
|
comments: document.getElementById("comments").value,
|
||||||
source: document.getElementById("source").value,
|
source: document.getElementById("source").value,
|
||||||
};
|
};
|
||||||
LocalPreferences.set("torrent_creator", JSON.stringify(preference));
|
window.parent.qBittorrent.ClientData.set({ torrent_creator: preference });
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadPreference = () => {
|
const loadPreference = async () => {
|
||||||
const preference = JSON.parse(LocalPreferences.get("torrent_creator") ?? "{}");
|
const clientData = await window.parent.qBittorrent.ClientData.get(["torrent_creator"]);
|
||||||
|
const preference = clientData.torrent_creator ?? {};
|
||||||
|
|
||||||
document.getElementById("sourcePath").value = preference.sourcePath ?? "";
|
document.getElementById("sourcePath").value = preference.sourcePath ?? "";
|
||||||
document.getElementById("torrentFormat").value = preference.torrentFormat ?? "hybrid";
|
document.getElementById("torrentFormat").value = preference.torrentFormat ?? "hybrid";
|
||||||
document.getElementById("pieceSize").value = preference.pieceSize ?? 0;
|
document.getElementById("pieceSize").value = preference.pieceSize ?? 0;
|
||||||
|
|
|
@ -261,7 +261,7 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById("Filters_pad").addEventListener("dblclick", (event) => {
|
document.getElementById("Filters_pad").addEventListener("dblclick", (event) => {
|
||||||
if (LocalPreferences.get("dblclick_filter", "1") !== "1")
|
if (window.qBittorrent.ClientData.getCached("dblclick_filter") === "0")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const filterItem = event.target.closest("li");
|
const filterItem = event.target.closest("li");
|
||||||
|
|
|
@ -185,7 +185,7 @@
|
||||||
let logFilterTimer = -1;
|
let logFilterTimer = -1;
|
||||||
let inputtedFilterText = "";
|
let inputtedFilterText = "";
|
||||||
let selectBox;
|
let selectBox;
|
||||||
let selectedLogLevels = JSON.parse(LocalPreferences.get("qbt_selected_log_levels")) || ["1", "2", "4", "8"];
|
let selectedLogLevels = window.qBittorrent.ClientData.getCached("qbt_selected_log_levels") ?? ["1", "2", "4", "8"];
|
||||||
|
|
||||||
const init = () => {
|
const init = () => {
|
||||||
for (const option of document.getElementById("logLevelSelect").options)
|
for (const option of document.getElementById("logLevelSelect").options)
|
||||||
|
@ -276,7 +276,8 @@
|
||||||
if (selectedLogLevels !== value) {
|
if (selectedLogLevels !== value) {
|
||||||
tableInfo[currentSelectedTab].last_id = -1;
|
tableInfo[currentSelectedTab].last_id = -1;
|
||||||
selectedLogLevels = value;
|
selectedLogLevels = value;
|
||||||
LocalPreferences.set("qbt_selected_log_levels", JSON.stringify(selectedLogLevels));
|
// don't await this
|
||||||
|
window.qBittorrent.ClientData.set({ qbt_selected_log_levels: selectedLogLevels });
|
||||||
logFilterChanged();
|
logFilterChanged();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -2215,10 +2215,8 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD
|
||||||
document.getElementById("locale_select").value = selected;
|
document.getElementById("locale_select").value = selected;
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateColoSchemeSelect = () => {
|
const updateColoSchemeSelect = (colorScheme) => {
|
||||||
const combobox = document.getElementById("colorSchemeSelect");
|
const combobox = document.getElementById("colorSchemeSelect");
|
||||||
const colorScheme = LocalPreferences.get("color_scheme");
|
|
||||||
|
|
||||||
if (colorScheme === "light")
|
if (colorScheme === "light")
|
||||||
combobox.options[1].selected = true;
|
combobox.options[1].selected = true;
|
||||||
else if (colorScheme === "dark")
|
else if (colorScheme === "dark")
|
||||||
|
@ -2230,20 +2228,31 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD
|
||||||
const loadPreferences = () => {
|
const loadPreferences = () => {
|
||||||
window.parent.qBittorrent.Cache.preferences.init()
|
window.parent.qBittorrent.Cache.preferences.init()
|
||||||
.then((pref) => {
|
.then((pref) => {
|
||||||
|
const clientData = window.parent.qBittorrent.ClientData;
|
||||||
|
const colorScheme = clientData.getCached("color_scheme");
|
||||||
|
const fullUrlTrackerColumn = clientData.getCached("full_url_tracker_column");
|
||||||
|
const useVirtualList = clientData.getCached("use_virtual_list");
|
||||||
|
const hideZeroStatusFilters = clientData.getCached("hide_zero_status_filters");
|
||||||
|
const dblclickDownload = clientData.getCached("dblclick_download");
|
||||||
|
const dblclickComplete = clientData.getCached("dblclick_complete");
|
||||||
|
const dblclickFilter = clientData.getCached("dblclick_filter");
|
||||||
|
const useAltRowColors = clientData.getCached("use_alt_row_colors");
|
||||||
|
|
||||||
// Behavior tab
|
// Behavior tab
|
||||||
// Language
|
// Language
|
||||||
updateWebuiLocaleSelect(pref.locale);
|
updateWebuiLocaleSelect(pref.locale);
|
||||||
updateColoSchemeSelect();
|
updateColoSchemeSelect(colorScheme);
|
||||||
|
|
||||||
document.getElementById("statusBarExternalIP").checked = pref.status_bar_external_ip;
|
document.getElementById("statusBarExternalIP").checked = pref.status_bar_external_ip;
|
||||||
document.getElementById("performanceWarning").checked = pref.performance_warning;
|
document.getElementById("performanceWarning").checked = pref.performance_warning;
|
||||||
document.getElementById("displayFullURLTrackerColumn").checked = (LocalPreferences.get("full_url_tracker_column", "false") === "true");
|
document.getElementById("displayFullURLTrackerColumn").checked = fullUrlTrackerColumn === true;
|
||||||
document.getElementById("useVirtualList").checked = (LocalPreferences.get("use_virtual_list", "false") === "true");
|
document.getElementById("useVirtualList").checked = useVirtualList === true;
|
||||||
document.getElementById("hideZeroFiltersCheckbox").checked = (LocalPreferences.get("hide_zero_status_filters", "false") === "true");
|
document.getElementById("hideZeroFiltersCheckbox").checked = hideZeroStatusFilters === true;
|
||||||
document.getElementById("dblclickDownloadSelect").value = LocalPreferences.get("dblclick_download", "1");
|
document.getElementById("dblclickDownloadSelect").value = dblclickDownload ?? "1";
|
||||||
document.getElementById("dblclickCompleteSelect").value = LocalPreferences.get("dblclick_complete", "1");
|
document.getElementById("dblclickCompleteSelect").value = dblclickComplete ?? "1";
|
||||||
document.getElementById("dblclickFiltersSelect").value = LocalPreferences.get("dblclick_filter", "1");
|
document.getElementById("dblclickFiltersSelect").value = dblclickFilter ?? "1";
|
||||||
document.getElementById("confirmTorrentDeletion").checked = pref.confirm_torrent_deletion;
|
document.getElementById("confirmTorrentDeletion").checked = pref.confirm_torrent_deletion;
|
||||||
document.getElementById("useAltRowColorsInput").checked = (LocalPreferences.get("use_alt_row_colors", "true") === "true");
|
document.getElementById("useAltRowColorsInput").checked = useAltRowColors !== false;
|
||||||
document.getElementById("filelog_checkbox").checked = pref.file_log_enabled;
|
document.getElementById("filelog_checkbox").checked = pref.file_log_enabled;
|
||||||
document.getElementById("filelog_save_path_input").value = pref.file_log_path;
|
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_backup_checkbox").checked = pref.file_log_backup_enabled;
|
||||||
|
@ -2658,6 +2667,7 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD
|
||||||
|
|
||||||
const applyPreferences = () => {
|
const applyPreferences = () => {
|
||||||
const settings = {};
|
const settings = {};
|
||||||
|
const clientData = {};
|
||||||
// Validate form data
|
// Validate form data
|
||||||
|
|
||||||
// Behavior tab
|
// Behavior tab
|
||||||
|
@ -2665,21 +2675,21 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD
|
||||||
settings["locale"] = document.getElementById("locale_select").value;
|
settings["locale"] = document.getElementById("locale_select").value;
|
||||||
const colorScheme = Number(document.getElementById("colorSchemeSelect").value);
|
const colorScheme = Number(document.getElementById("colorSchemeSelect").value);
|
||||||
if (colorScheme === 0)
|
if (colorScheme === 0)
|
||||||
LocalPreferences.remove("color_scheme");
|
clientData.color_scheme = null;
|
||||||
else if (colorScheme === 1)
|
else if (colorScheme === 1)
|
||||||
LocalPreferences.set("color_scheme", "light");
|
clientData.color_scheme = "light";
|
||||||
else
|
else
|
||||||
LocalPreferences.set("color_scheme", "dark");
|
clientData.color_scheme = "dark";
|
||||||
settings["status_bar_external_ip"] = document.getElementById("statusBarExternalIP").checked;
|
settings["status_bar_external_ip"] = document.getElementById("statusBarExternalIP").checked;
|
||||||
settings["performance_warning"] = document.getElementById("performanceWarning").checked;
|
settings["performance_warning"] = document.getElementById("performanceWarning").checked;
|
||||||
LocalPreferences.set("full_url_tracker_column", document.getElementById("displayFullURLTrackerColumn").checked.toString());
|
clientData.full_url_tracker_column = document.getElementById("displayFullURLTrackerColumn").checked;
|
||||||
LocalPreferences.set("use_virtual_list", document.getElementById("useVirtualList").checked.toString());
|
clientData.use_virtual_list = document.getElementById("useVirtualList").checked;
|
||||||
LocalPreferences.set("hide_zero_status_filters", document.getElementById("hideZeroFiltersCheckbox").checked.toString());
|
clientData.hide_zero_status_filters = document.getElementById("hideZeroFiltersCheckbox").checked;
|
||||||
LocalPreferences.set("dblclick_download", document.getElementById("dblclickDownloadSelect").value);
|
clientData.dblclick_download = document.getElementById("dblclickDownloadSelect").value;
|
||||||
LocalPreferences.set("dblclick_complete", document.getElementById("dblclickCompleteSelect").value);
|
clientData.dblclick_complete = document.getElementById("dblclickCompleteSelect").value;
|
||||||
LocalPreferences.set("dblclick_filter", document.getElementById("dblclickFiltersSelect").value);
|
clientData.dblclick_filter = document.getElementById("dblclickFiltersSelect").value;
|
||||||
settings["confirm_torrent_deletion"] = document.getElementById("confirmTorrentDeletion").checked;
|
settings["confirm_torrent_deletion"] = document.getElementById("confirmTorrentDeletion").checked;
|
||||||
LocalPreferences.set("use_alt_row_colors", document.getElementById("useAltRowColorsInput").checked.toString());
|
clientData.use_alt_row_colors = document.getElementById("useAltRowColorsInput").checked;
|
||||||
settings["file_log_enabled"] = document.getElementById("filelog_checkbox").checked;
|
settings["file_log_enabled"] = document.getElementById("filelog_checkbox").checked;
|
||||||
settings["file_log_path"] = document.getElementById("filelog_save_path_input").value;
|
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_backup_enabled"] = document.getElementById("filelog_backup_checkbox").checked;
|
||||||
|
@ -3170,6 +3180,11 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD
|
||||||
settings["i2p_inbound_length"] = Number(document.getElementById("i2pInboundLength").value);
|
settings["i2p_inbound_length"] = Number(document.getElementById("i2pInboundLength").value);
|
||||||
settings["i2p_outbound_length"] = Number(document.getElementById("i2pOutboundLength").value);
|
settings["i2p_outbound_length"] = Number(document.getElementById("i2pOutboundLength").value);
|
||||||
|
|
||||||
|
window.parent.qBittorrent.ClientData.set(clientData)
|
||||||
|
.catch((error) => {
|
||||||
|
alert("QBT_TR(Unable to save web client preferences, qBittorrent is probably unreachable.)QBT_TR[CONTEXT=HttpServer]");
|
||||||
|
});
|
||||||
|
|
||||||
// Send it to qBT
|
// Send it to qBT
|
||||||
window.parent.qBittorrent.Cache.preferences.set(settings)
|
window.parent.qBittorrent.Cache.preferences.set(settings)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|
|
@ -390,6 +390,7 @@
|
||||||
<file>private/scripts/addtorrent.js</file>
|
<file>private/scripts/addtorrent.js</file>
|
||||||
<file>private/scripts/cache.js</file>
|
<file>private/scripts/cache.js</file>
|
||||||
<file>private/scripts/client.js</file>
|
<file>private/scripts/client.js</file>
|
||||||
|
<file>private/scripts/client-data.js</file>
|
||||||
<file>private/scripts/color-scheme.js</file>
|
<file>private/scripts/color-scheme.js</file>
|
||||||
<file>private/scripts/contextmenu.js</file>
|
<file>private/scripts/contextmenu.js</file>
|
||||||
<file>private/scripts/dynamicTable.js</file>
|
<file>private/scripts/dynamicTable.js</file>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue