2022-10-18 22:39:32 -04:00
|
|
|
/*
|
|
|
|
* MIT License
|
2024-10-03 08:37:11 -04:00
|
|
|
* Copyright (C) 2024 Mike Tzou (Chocobo1)
|
2022-10-18 22:39:32 -04:00
|
|
|
* Copyright (c) 2008 Ishan Arora <ishan@qbittorrent.org>,
|
|
|
|
* Christophe Dumez <chris@qbittorrent.org>
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
* THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
"use strict";
|
2022-10-18 22:39:32 -04:00
|
|
|
|
2024-10-01 14:25:40 -04:00
|
|
|
window.qBittorrent ??= {};
|
|
|
|
window.qBittorrent.Client ??= (() => {
|
|
|
|
const exports = () => {
|
|
|
|
return {
|
|
|
|
closeWindow: closeWindow,
|
|
|
|
closeWindows: closeWindows,
|
|
|
|
getSyncMainDataInterval: getSyncMainDataInterval,
|
|
|
|
isStopped: isStopped,
|
|
|
|
stop: stop,
|
|
|
|
mainTitle: mainTitle,
|
|
|
|
showSearchEngine: showSearchEngine,
|
|
|
|
showRssReader: showRssReader,
|
|
|
|
showLogViewer: showLogViewer,
|
|
|
|
isShowSearchEngine: isShowSearchEngine,
|
|
|
|
isShowRssReader: isShowRssReader,
|
|
|
|
isShowLogViewer: isShowLogViewer
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
const closeWindow = function(windowID) {
|
|
|
|
const window = document.getElementById(windowID);
|
|
|
|
if (!window)
|
|
|
|
return;
|
|
|
|
MochaUI.closeWindow(window);
|
|
|
|
};
|
|
|
|
|
|
|
|
const closeWindows = function() {
|
|
|
|
MochaUI.closeAll();
|
|
|
|
};
|
|
|
|
|
|
|
|
const getSyncMainDataInterval = function() {
|
|
|
|
return customSyncMainDataInterval ? customSyncMainDataInterval : serverSyncMainDataInterval;
|
|
|
|
};
|
|
|
|
|
|
|
|
let stopped = false;
|
|
|
|
const isStopped = () => {
|
|
|
|
return stopped;
|
|
|
|
};
|
|
|
|
|
|
|
|
const stop = () => {
|
|
|
|
stopped = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
const mainTitle = () => {
|
|
|
|
const emDash = "\u2014";
|
|
|
|
const qbtVersion = window.qBittorrent.Cache.qbtVersion.get();
|
|
|
|
const suffix = window.qBittorrent.Cache.preferences.get()["app_instance_name"] || "";
|
|
|
|
const title = `qBittorrent ${qbtVersion} WebUI`
|
|
|
|
+ ((suffix.length > 0) ? ` ${emDash} ${suffix}` : "");
|
|
|
|
return title;
|
|
|
|
};
|
|
|
|
|
|
|
|
let showingSearchEngine = false;
|
|
|
|
let showingRssReader = false;
|
|
|
|
let showingLogViewer = false;
|
|
|
|
|
|
|
|
const showSearchEngine = function(bool) {
|
|
|
|
showingSearchEngine = bool;
|
|
|
|
};
|
|
|
|
const showRssReader = function(bool) {
|
|
|
|
showingRssReader = bool;
|
|
|
|
};
|
|
|
|
const showLogViewer = function(bool) {
|
|
|
|
showingLogViewer = bool;
|
|
|
|
};
|
|
|
|
const isShowSearchEngine = function() {
|
|
|
|
return showingSearchEngine;
|
|
|
|
};
|
|
|
|
const isShowRssReader = function() {
|
|
|
|
return showingRssReader;
|
|
|
|
};
|
|
|
|
const isShowLogViewer = function() {
|
|
|
|
return showingLogViewer;
|
|
|
|
};
|
|
|
|
|
|
|
|
return exports();
|
|
|
|
})();
|
|
|
|
Object.freeze(window.qBittorrent.Client);
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
// TODO: move global functions/variables into some namespace/scope
|
|
|
|
|
2022-10-18 22:39:32 -04:00
|
|
|
this.torrentsTable = new window.qBittorrent.DynamicTable.TorrentsTable();
|
|
|
|
|
|
|
|
let updatePropertiesPanel = function() {};
|
|
|
|
|
|
|
|
this.updateMainData = function() {};
|
|
|
|
let alternativeSpeedLimits = false;
|
|
|
|
let queueing_enabled = true;
|
|
|
|
let serverSyncMainDataInterval = 1500;
|
|
|
|
let customSyncMainDataInterval = null;
|
2023-07-18 11:58:05 -04:00
|
|
|
let useSubcategories = true;
|
2024-10-01 14:25:40 -04:00
|
|
|
const useAutoHideZeroStatusFilters = LocalPreferences.get("hide_zero_status_filters", "false") === "true";
|
|
|
|
const displayFullURLTrackerColumn = LocalPreferences.get("full_url_tracker_column", "false") === "true";
|
|
|
|
|
2022-10-18 22:39:32 -04:00
|
|
|
/* Categories filter */
|
|
|
|
const CATEGORIES_ALL = 1;
|
|
|
|
const CATEGORIES_UNCATEGORIZED = 2;
|
|
|
|
|
2024-10-01 14:25:40 -04:00
|
|
|
const category_list = new Map();
|
2022-10-18 22:39:32 -04:00
|
|
|
|
2024-10-01 14:25:40 -04:00
|
|
|
let selectedCategory = Number(LocalPreferences.get("selected_category", CATEGORIES_ALL));
|
2022-10-18 22:39:32 -04:00
|
|
|
let setCategoryFilter = function() {};
|
|
|
|
|
|
|
|
/* Tags filter */
|
|
|
|
const TAGS_ALL = 1;
|
|
|
|
const TAGS_UNTAGGED = 2;
|
|
|
|
|
2024-10-01 14:25:40 -04:00
|
|
|
const tagList = new Map();
|
2022-10-18 22:39:32 -04:00
|
|
|
|
2024-10-01 14:25:40 -04:00
|
|
|
let selectedTag = Number(LocalPreferences.get("selected_tag", TAGS_ALL));
|
2022-10-18 22:39:32 -04:00
|
|
|
let setTagFilter = function() {};
|
|
|
|
|
|
|
|
/* Trackers filter */
|
|
|
|
const TRACKERS_ALL = 1;
|
|
|
|
const TRACKERS_TRACKERLESS = 2;
|
|
|
|
|
2024-10-01 14:25:40 -04:00
|
|
|
/** @type Map<number, {host: string, trackerTorrentMap: Map<string, string[]>}> **/
|
2022-10-18 22:39:32 -04:00
|
|
|
const trackerList = new Map();
|
|
|
|
|
2024-10-01 14:25:40 -04:00
|
|
|
let selectedTracker = Number(LocalPreferences.get("selected_tracker", TRACKERS_ALL));
|
2022-10-18 22:39:32 -04:00
|
|
|
let setTrackerFilter = function() {};
|
|
|
|
|
|
|
|
/* All filters */
|
2024-10-01 14:25:40 -04:00
|
|
|
let selectedStatus = LocalPreferences.get("selected_filter", "all");
|
|
|
|
let setStatusFilter = function() {};
|
2022-10-18 22:39:32 -04:00
|
|
|
let toggleFilterDisplay = function() {};
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
window.addEventListener("DOMContentLoaded", () => {
|
|
|
|
let isSearchPanelLoaded = false;
|
|
|
|
let isLogPanelLoaded = false;
|
2023-07-18 11:58:05 -04:00
|
|
|
|
2022-10-18 22:39:32 -04:00
|
|
|
const saveColumnSizes = function() {
|
2024-10-03 08:37:11 -04:00
|
|
|
const filters_width = $("Filters").getSize().x;
|
|
|
|
LocalPreferences.set("filters_width", filters_width);
|
|
|
|
const properties_height_rel = $("propertiesPanel").getSize().y / Window.getSize().y;
|
|
|
|
LocalPreferences.set("properties_height_rel", properties_height_rel);
|
2022-10-18 22:39:32 -04:00
|
|
|
};
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
window.addEventListener("resize", window.qBittorrent.Misc.createDebounceHandler(500, (e) => {
|
2022-10-18 22:39:32 -04:00
|
|
|
// only save sizes if the columns are visible
|
|
|
|
if (!$("mainColumn").hasClass("invisible"))
|
2024-10-03 08:37:11 -04:00
|
|
|
saveColumnSizes();
|
|
|
|
}));
|
2022-10-18 22:39:32 -04:00
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
/* MochaUI.Desktop = new MochaUI.Desktop();
|
|
|
|
MochaUI.Desktop.desktop.style.background = "#fff";
|
|
|
|
MochaUI.Desktop.desktop.style.visibility = "visible"; */
|
2023-07-18 11:58:05 -04:00
|
|
|
MochaUI.Desktop.initialize();
|
2022-10-18 22:39:32 -04:00
|
|
|
|
|
|
|
const buildTransfersTab = function() {
|
|
|
|
new MochaUI.Column({
|
2024-10-03 08:37:11 -04:00
|
|
|
id: "filtersColumn",
|
|
|
|
placement: "left",
|
|
|
|
onResize: window.qBittorrent.Misc.createDebounceHandler(500, (e) => {
|
|
|
|
saveColumnSizes();
|
|
|
|
}),
|
|
|
|
width: Number(LocalPreferences.get("filters_width", 210)),
|
|
|
|
resizeLimit: [1, 1000]
|
2022-10-18 22:39:32 -04:00
|
|
|
});
|
|
|
|
new MochaUI.Column({
|
2024-10-03 08:37:11 -04:00
|
|
|
id: "mainColumn",
|
|
|
|
placement: "main"
|
2022-10-18 22:39:32 -04:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
const buildSearchTab = function() {
|
|
|
|
new MochaUI.Column({
|
2024-10-03 08:37:11 -04:00
|
|
|
id: "searchTabColumn",
|
|
|
|
placement: "main",
|
2022-10-18 22:39:32 -04:00
|
|
|
width: null
|
|
|
|
});
|
|
|
|
|
|
|
|
// start off hidden
|
|
|
|
$("searchTabColumn").addClass("invisible");
|
|
|
|
};
|
|
|
|
|
|
|
|
const buildRssTab = function() {
|
|
|
|
new MochaUI.Column({
|
2024-10-03 08:37:11 -04:00
|
|
|
id: "rssTabColumn",
|
|
|
|
placement: "main",
|
2022-10-18 22:39:32 -04:00
|
|
|
width: null
|
|
|
|
});
|
|
|
|
|
|
|
|
// start off hidden
|
|
|
|
$("rssTabColumn").addClass("invisible");
|
|
|
|
};
|
|
|
|
|
2023-07-18 11:58:05 -04:00
|
|
|
const buildLogTab = function() {
|
|
|
|
new MochaUI.Column({
|
2024-10-03 08:37:11 -04:00
|
|
|
id: "logTabColumn",
|
|
|
|
placement: "main",
|
2023-07-18 11:58:05 -04:00
|
|
|
width: null
|
|
|
|
});
|
|
|
|
|
|
|
|
// start off hidden
|
2024-10-03 08:37:11 -04:00
|
|
|
$("logTabColumn").addClass("invisible");
|
2023-07-18 11:58:05 -04:00
|
|
|
};
|
|
|
|
|
2022-10-18 22:39:32 -04:00
|
|
|
buildTransfersTab();
|
|
|
|
buildSearchTab();
|
|
|
|
buildRssTab();
|
2023-07-18 11:58:05 -04:00
|
|
|
buildLogTab();
|
2024-10-03 08:37:11 -04:00
|
|
|
MochaUI.initializeTabs("mainWindowTabsList");
|
2022-10-18 22:39:32 -04:00
|
|
|
|
2024-10-01 14:25:40 -04:00
|
|
|
setStatusFilter = function(name) {
|
|
|
|
LocalPreferences.set("selected_filter", name);
|
|
|
|
selectedStatus = name;
|
|
|
|
highlightSelectedStatus();
|
|
|
|
updateMainData();
|
|
|
|
};
|
|
|
|
|
2022-10-18 22:39:32 -04:00
|
|
|
setCategoryFilter = function(hash) {
|
2024-10-01 14:25:40 -04:00
|
|
|
LocalPreferences.set("selected_category", hash);
|
|
|
|
selectedCategory = Number(hash);
|
2022-10-18 22:39:32 -04:00
|
|
|
highlightSelectedCategory();
|
2024-10-01 14:25:40 -04:00
|
|
|
updateMainData();
|
2022-10-18 22:39:32 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
setTagFilter = function(hash) {
|
2024-10-01 14:25:40 -04:00
|
|
|
LocalPreferences.set("selected_tag", hash);
|
|
|
|
selectedTag = Number(hash);
|
2022-10-18 22:39:32 -04:00
|
|
|
highlightSelectedTag();
|
2024-10-01 14:25:40 -04:00
|
|
|
updateMainData();
|
2022-10-18 22:39:32 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
setTrackerFilter = function(hash) {
|
2024-10-01 14:25:40 -04:00
|
|
|
LocalPreferences.set("selected_tracker", hash);
|
|
|
|
selectedTracker = Number(hash);
|
2022-10-18 22:39:32 -04:00
|
|
|
highlightSelectedTracker();
|
2024-10-01 14:25:40 -04:00
|
|
|
updateMainData();
|
|
|
|
};
|
|
|
|
|
|
|
|
toggleFilterDisplay = function(filterListID) {
|
|
|
|
const filterList = document.getElementById(filterListID);
|
|
|
|
const filterTitle = filterList.previousElementSibling;
|
|
|
|
const toggleIcon = filterTitle.firstElementChild;
|
|
|
|
toggleIcon.classList.toggle("rotate");
|
|
|
|
LocalPreferences.set(`filter_${filterListID.replace("FilterList", "")}_collapsed`, filterList.classList.toggle("invisible").toString());
|
|
|
|
};
|
|
|
|
|
2022-10-18 22:39:32 -04:00
|
|
|
new MochaUI.Panel({
|
2024-10-03 08:37:11 -04:00
|
|
|
id: "Filters",
|
|
|
|
title: "Panel",
|
2022-10-18 22:39:32 -04:00
|
|
|
header: false,
|
|
|
|
padding: {
|
|
|
|
top: 0,
|
|
|
|
right: 0,
|
|
|
|
bottom: 0,
|
|
|
|
left: 0
|
|
|
|
},
|
2024-10-03 08:37:11 -04:00
|
|
|
loadMethod: "xhr",
|
|
|
|
contentURL: "views/filters.html",
|
2022-10-18 22:39:32 -04:00
|
|
|
onContentLoaded: function() {
|
2024-10-01 14:25:40 -04:00
|
|
|
highlightSelectedStatus();
|
2022-10-18 22:39:32 -04:00
|
|
|
},
|
2024-10-03 08:37:11 -04:00
|
|
|
column: "filtersColumn",
|
2022-10-18 22:39:32 -04:00
|
|
|
height: 300
|
|
|
|
});
|
|
|
|
initializeWindows();
|
|
|
|
|
|
|
|
// Show Top Toolbar is enabled by default
|
2024-10-03 08:37:11 -04:00
|
|
|
let showTopToolbar = LocalPreferences.get("show_top_toolbar", "true") === "true";
|
2022-10-18 22:39:32 -04:00
|
|
|
if (!showTopToolbar) {
|
2024-10-03 08:37:11 -04:00
|
|
|
$("showTopToolbarLink").firstChild.style.opacity = "0";
|
|
|
|
$("mochaToolbar").addClass("invisible");
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Show Status Bar is enabled by default
|
2024-10-03 08:37:11 -04:00
|
|
|
let showStatusBar = LocalPreferences.get("show_status_bar", "true") === "true";
|
2022-10-18 22:39:32 -04:00
|
|
|
if (!showStatusBar) {
|
2024-10-03 08:37:11 -04:00
|
|
|
$("showStatusBarLink").firstChild.style.opacity = "0";
|
|
|
|
$("desktopFooterWrapper").addClass("invisible");
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
// Show Filters Sidebar is enabled by default
|
|
|
|
let showFiltersSidebar = LocalPreferences.get("show_filters_sidebar", "true") === "true";
|
2022-10-18 22:39:32 -04:00
|
|
|
if (!showFiltersSidebar) {
|
2024-10-03 08:37:11 -04:00
|
|
|
$("showFiltersSidebarLink").firstChild.style.opacity = "0";
|
|
|
|
$("filtersColumn").addClass("invisible");
|
|
|
|
$("filtersColumn_handle").addClass("invisible");
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
let speedInTitle = LocalPreferences.get("speed_in_browser_title_bar") === "true";
|
2022-10-18 22:39:32 -04:00
|
|
|
if (!speedInTitle)
|
2024-10-03 08:37:11 -04:00
|
|
|
$("speedInBrowserTitleBarLink").firstChild.style.opacity = "0";
|
2022-10-18 22:39:32 -04:00
|
|
|
|
|
|
|
// After showing/hiding the toolbar + status bar
|
2024-10-03 08:37:11 -04:00
|
|
|
window.qBittorrent.Client.showSearchEngine(LocalPreferences.get("show_search_engine") !== "false");
|
|
|
|
window.qBittorrent.Client.showRssReader(LocalPreferences.get("show_rss_reader") !== "false");
|
|
|
|
window.qBittorrent.Client.showLogViewer(LocalPreferences.get("show_log_viewer") === "true");
|
2022-10-18 22:39:32 -04:00
|
|
|
|
|
|
|
// After Show Top Toolbar
|
|
|
|
MochaUI.Desktop.setDesktopSize();
|
|
|
|
|
|
|
|
let syncMainDataLastResponseId = 0;
|
|
|
|
const serverState = {};
|
|
|
|
|
|
|
|
const removeTorrentFromCategoryList = function(hash) {
|
2024-10-03 08:37:11 -04:00
|
|
|
if (!hash)
|
2022-10-18 22:39:32 -04:00
|
|
|
return false;
|
2024-10-03 08:37:11 -04:00
|
|
|
|
2022-10-18 22:39:32 -04:00
|
|
|
let removed = false;
|
2024-10-03 08:37:11 -04:00
|
|
|
category_list.forEach((category) => {
|
|
|
|
const deleteResult = category.torrents.delete(hash);
|
|
|
|
removed ||= deleteResult;
|
2022-10-18 22:39:32 -04:00
|
|
|
});
|
2024-10-03 08:37:11 -04:00
|
|
|
|
2022-10-18 22:39:32 -04:00
|
|
|
return removed;
|
|
|
|
};
|
|
|
|
|
|
|
|
const addTorrentToCategoryList = function(torrent) {
|
2024-10-03 08:37:11 -04:00
|
|
|
const category = torrent["category"];
|
|
|
|
if (typeof category === "undefined")
|
2022-10-18 22:39:32 -04:00
|
|
|
return false;
|
2024-10-03 08:37:11 -04:00
|
|
|
|
|
|
|
const hash = torrent["hash"];
|
2022-10-18 22:39:32 -04:00
|
|
|
if (category.length === 0) { // Empty category
|
2024-10-03 08:37:11 -04:00
|
|
|
removeTorrentFromCategoryList(hash);
|
2022-10-18 22:39:32 -04:00
|
|
|
return true;
|
|
|
|
}
|
2024-10-03 08:37:11 -04:00
|
|
|
|
|
|
|
const categoryHash = window.qBittorrent.Misc.genHash(category);
|
|
|
|
if (!category_list.has(categoryHash)) { // This should not happen
|
|
|
|
category_list.set(categoryHash, {
|
2022-10-18 22:39:32 -04:00
|
|
|
name: category,
|
2024-10-03 08:37:11 -04:00
|
|
|
torrents: new Set()
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
const torrents = category_list.get(categoryHash).torrents;
|
|
|
|
if (!torrents.has(hash)) {
|
|
|
|
removeTorrentFromCategoryList(hash);
|
|
|
|
torrents.add(hash);
|
2022-10-18 22:39:32 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
|
|
|
const removeTorrentFromTagList = function(hash) {
|
2024-10-03 08:37:11 -04:00
|
|
|
if (!hash)
|
2022-10-18 22:39:32 -04:00
|
|
|
return false;
|
|
|
|
|
|
|
|
let removed = false;
|
2024-10-03 08:37:11 -04:00
|
|
|
tagList.forEach((tag) => {
|
|
|
|
const deleteResult = tag.torrents.delete(hash);
|
|
|
|
removed ||= deleteResult;
|
|
|
|
});
|
|
|
|
|
2022-10-18 22:39:32 -04:00
|
|
|
return removed;
|
|
|
|
};
|
|
|
|
|
|
|
|
const addTorrentToTagList = function(torrent) {
|
2024-10-01 14:25:40 -04:00
|
|
|
if (torrent["tags"] === undefined) // Tags haven't changed
|
2022-10-18 22:39:32 -04:00
|
|
|
return false;
|
|
|
|
|
2024-10-01 14:25:40 -04:00
|
|
|
const hash = torrent["hash"];
|
|
|
|
removeTorrentFromTagList(hash);
|
2022-10-18 22:39:32 -04:00
|
|
|
|
2024-10-01 14:25:40 -04:00
|
|
|
if (torrent["tags"].length === 0) // No tags
|
2022-10-18 22:39:32 -04:00
|
|
|
return true;
|
|
|
|
|
2024-10-01 14:25:40 -04:00
|
|
|
const tags = torrent["tags"].split(",");
|
2022-10-18 22:39:32 -04:00
|
|
|
let added = false;
|
|
|
|
for (let i = 0; i < tags.length; ++i) {
|
2024-10-01 14:25:40 -04:00
|
|
|
const tagHash = window.qBittorrent.Misc.genHash(tags[i].trim());
|
|
|
|
if (!tagList.has(tagHash)) { // This should not happen
|
|
|
|
tagList.set(tagHash, {
|
2022-10-18 22:39:32 -04:00
|
|
|
name: tags,
|
2024-10-01 14:25:40 -04:00
|
|
|
torrents: new Set()
|
|
|
|
});
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
2024-10-01 14:25:40 -04:00
|
|
|
|
|
|
|
const torrents = tagList.get(tagHash).torrents;
|
|
|
|
if (!torrents.has(hash)) {
|
|
|
|
torrents.add(hash);
|
2022-10-18 22:39:32 -04:00
|
|
|
added = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return added;
|
|
|
|
};
|
|
|
|
|
|
|
|
const updateFilter = function(filter, filterTitle) {
|
2024-10-01 14:25:40 -04:00
|
|
|
const filterEl = document.getElementById(`${filter}_filter`);
|
|
|
|
const filterTorrentCount = torrentsTable.getFilteredTorrentsNumber(filter, CATEGORIES_ALL, TAGS_ALL, TRACKERS_ALL);
|
|
|
|
if (useAutoHideZeroStatusFilters) {
|
|
|
|
const hideFilter = (filterTorrentCount === 0) && (filter !== "all");
|
|
|
|
if (filterEl.classList.toggle("invisible", hideFilter))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
filterEl.firstElementChild.lastChild.nodeValue = filterTitle.replace("%1", filterTorrentCount);
|
2022-10-18 22:39:32 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
const updateFiltersList = function() {
|
2024-10-03 08:37:11 -04:00
|
|
|
updateFilter("all", "All (%1)");
|
|
|
|
updateFilter("downloading", "Downloading (%1)");
|
|
|
|
updateFilter("seeding", "Seeding (%1)");
|
|
|
|
updateFilter("completed", "Completed (%1)");
|
2024-10-01 14:25:40 -04:00
|
|
|
updateFilter("running", "Running (%1)");
|
|
|
|
updateFilter("stopped", "Stopped (%1)");
|
2024-10-03 08:37:11 -04:00
|
|
|
updateFilter("active", "Active (%1)");
|
|
|
|
updateFilter("inactive", "Inactive (%1)");
|
|
|
|
updateFilter("stalled", "Stalled (%1)");
|
|
|
|
updateFilter("stalled_uploading", "Stalled Uploading (%1)");
|
|
|
|
updateFilter("stalled_downloading", "Stalled Downloading (%1)");
|
|
|
|
updateFilter("checking", "Checking (%1)");
|
|
|
|
updateFilter("moving", "Moving (%1)");
|
|
|
|
updateFilter("errored", "Errored (%1)");
|
|
|
|
};
|
|
|
|
|
|
|
|
const highlightSelectedStatus = function() {
|
|
|
|
const statusFilter = document.getElementById("statusFilterList");
|
|
|
|
const filterID = `${selectedStatus}_filter`;
|
|
|
|
for (const status of statusFilter.children)
|
|
|
|
status.classList.toggle("selectedFilter", (status.id === filterID));
|
2022-10-18 22:39:32 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
const updateCategoryList = function() {
|
2024-10-01 14:25:40 -04:00
|
|
|
const categoryList = document.getElementById("categoryFilterList");
|
2022-10-18 22:39:32 -04:00
|
|
|
if (!categoryList)
|
|
|
|
return;
|
2024-01-07 17:04:03 -05:00
|
|
|
categoryList.getChildren().each(c => c.destroy());
|
2022-10-18 22:39:32 -04:00
|
|
|
|
2024-10-01 14:25:40 -04:00
|
|
|
const categoryItemTemplate = document.getElementById("categoryFilterItem");
|
2023-07-18 11:58:05 -04:00
|
|
|
|
2024-10-01 14:25:40 -04:00
|
|
|
const createCategoryLink = (hash, name, count) => {
|
|
|
|
const categoryFilterItem = categoryItemTemplate.content.cloneNode(true).firstElementChild;
|
|
|
|
categoryFilterItem.id = hash;
|
|
|
|
categoryFilterItem.classList.toggle("selectedFilter", hash === selectedCategory);
|
|
|
|
|
|
|
|
const span = categoryFilterItem.firstElementChild;
|
|
|
|
span.lastElementChild.textContent = `${name} (${count})`;
|
|
|
|
|
|
|
|
return categoryFilterItem;
|
|
|
|
};
|
|
|
|
|
|
|
|
const createCategoryTree = (category) => {
|
|
|
|
const stack = [{ parent: categoriesFragment, category: category }];
|
|
|
|
while (stack.length > 0) {
|
|
|
|
const { parent, category } = stack.pop();
|
|
|
|
const displayName = category.nameSegments.at(-1);
|
|
|
|
const listItem = createCategoryLink(category.categoryHash, displayName, category.categoryCount);
|
|
|
|
listItem.firstElementChild.style.paddingLeft = `${(category.nameSegments.length - 1) * 20 + 6}px`;
|
|
|
|
|
|
|
|
parent.appendChild(listItem);
|
|
|
|
|
|
|
|
if (category.children.length > 0) {
|
|
|
|
listItem.querySelector(".categoryToggle").style.visibility = "visible";
|
|
|
|
const unorderedList = document.createElement("ul");
|
|
|
|
listItem.appendChild(unorderedList);
|
|
|
|
for (const subcategory of category.children.reverse())
|
|
|
|
stack.push({ parent: unorderedList, category: subcategory });
|
|
|
|
}
|
|
|
|
const categoryLocalPref = `category_${category.categoryHash}_collapsed`;
|
|
|
|
const isCollapsed = !category.forceExpand && (LocalPreferences.get(categoryLocalPref, "false") === "true");
|
|
|
|
LocalPreferences.set(categoryLocalPref, listItem.classList.toggle("collapsedCategory", isCollapsed).toString());
|
|
|
|
}
|
2022-10-18 22:39:32 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
let uncategorized = 0;
|
2024-10-01 14:25:40 -04:00
|
|
|
for (const { full_data: { category } } of torrentsTable.getRowValues()) {
|
|
|
|
if (category.length === 0)
|
2022-10-18 22:39:32 -04:00
|
|
|
uncategorized += 1;
|
2024-10-01 14:25:40 -04:00
|
|
|
}
|
2022-10-18 22:39:32 -04:00
|
|
|
|
|
|
|
const sortedCategories = [];
|
2024-10-01 14:25:40 -04:00
|
|
|
category_list.forEach((category, hash) => sortedCategories.push({
|
|
|
|
categoryName: category.name,
|
|
|
|
categoryHash: hash,
|
|
|
|
categoryCount: category.torrents.size,
|
|
|
|
nameSegments: category.name.split("/"),
|
|
|
|
...(useSubcategories && {
|
|
|
|
children: [],
|
|
|
|
parentID: null,
|
|
|
|
forceExpand: LocalPreferences.get(`category_${hash}_collapsed`) === null
|
|
|
|
})
|
|
|
|
}));
|
|
|
|
sortedCategories.sort((left, right) => {
|
|
|
|
const leftSegments = left.nameSegments;
|
|
|
|
const rightSegments = right.nameSegments;
|
2024-01-07 17:04:03 -05:00
|
|
|
|
|
|
|
for (let i = 0, iMax = Math.min(leftSegments.length, rightSegments.length); i < iMax; ++i) {
|
|
|
|
const compareResult = window.qBittorrent.Misc.naturalSortCollator.compare(
|
|
|
|
leftSegments[i], rightSegments[i]);
|
|
|
|
if (compareResult !== 0)
|
|
|
|
return compareResult;
|
|
|
|
}
|
|
|
|
|
|
|
|
return leftSegments.length - rightSegments.length;
|
|
|
|
});
|
2022-10-18 22:39:32 -04:00
|
|
|
|
2024-10-01 14:25:40 -04:00
|
|
|
const categoriesFragment = new DocumentFragment();
|
|
|
|
categoriesFragment.appendChild(createCategoryLink(CATEGORIES_ALL, "All", torrentsTable.getRowSize()));
|
|
|
|
categoriesFragment.appendChild(createCategoryLink(CATEGORIES_UNCATEGORIZED, "Uncategorized", uncategorized));
|
|
|
|
|
|
|
|
if (useSubcategories) {
|
|
|
|
categoryList.classList.add("subcategories");
|
|
|
|
for (let i = 0; i < sortedCategories.length; ++i) {
|
|
|
|
const category = sortedCategories[i];
|
|
|
|
for (let j = (i + 1);
|
|
|
|
((j < sortedCategories.length) && sortedCategories[j].categoryName.startsWith(`${category.categoryName}/`)); ++j) {
|
|
|
|
const subcategory = sortedCategories[j];
|
|
|
|
category.categoryCount += subcategory.categoryCount;
|
|
|
|
category.forceExpand ||= subcategory.forceExpand;
|
|
|
|
|
|
|
|
const isDirectSubcategory = (subcategory.nameSegments.length - category.nameSegments.length) === 1;
|
|
|
|
if (isDirectSubcategory) {
|
|
|
|
subcategory.parentID = category.categoryHash;
|
|
|
|
category.children.push(subcategory);
|
|
|
|
}
|
2023-07-18 11:58:05 -04:00
|
|
|
}
|
|
|
|
}
|
2024-10-01 14:25:40 -04:00
|
|
|
for (const category of sortedCategories) {
|
|
|
|
if (category.parentID === null)
|
|
|
|
createCategoryTree(category);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
categoryList.classList.remove("subcategories");
|
|
|
|
for (const { categoryHash, categoryName, categoryCount } of sortedCategories)
|
|
|
|
categoriesFragment.appendChild(createCategoryLink(categoryHash, categoryName, categoryCount));
|
2023-07-18 11:58:05 -04:00
|
|
|
}
|
2022-10-18 22:39:32 -04:00
|
|
|
|
2024-10-01 14:25:40 -04:00
|
|
|
categoryList.appendChild(categoriesFragment);
|
|
|
|
window.qBittorrent.Filters.categoriesFilterContextMenu.searchAndAddTargets();
|
2022-10-18 22:39:32 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
const highlightSelectedCategory = function() {
|
2024-10-01 14:25:40 -04:00
|
|
|
const categoryList = document.getElementById("categoryFilterList");
|
2022-10-18 22:39:32 -04:00
|
|
|
if (!categoryList)
|
|
|
|
return;
|
2024-10-01 14:25:40 -04:00
|
|
|
|
|
|
|
for (const category of categoryList.getElementsByTagName("li"))
|
|
|
|
category.classList.toggle("selectedFilter", (Number(category.id) === selectedCategory));
|
2022-10-18 22:39:32 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
const updateTagList = function() {
|
2024-10-03 08:37:11 -04:00
|
|
|
const tagFilterList = $("tagFilterList");
|
2022-10-18 22:39:32 -04:00
|
|
|
if (tagFilterList === null)
|
|
|
|
return;
|
|
|
|
|
2024-01-07 17:04:03 -05:00
|
|
|
tagFilterList.getChildren().each(c => c.destroy());
|
2022-10-18 22:39:32 -04:00
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
const tagItemTemplate = document.getElementById("tagFilterItem");
|
|
|
|
|
2022-10-18 22:39:32 -04:00
|
|
|
const createLink = function(hash, text, count) {
|
2024-10-03 08:37:11 -04:00
|
|
|
const tagFilterItem = tagItemTemplate.content.cloneNode(true).firstElementChild;
|
|
|
|
tagFilterItem.id = hash;
|
|
|
|
tagFilterItem.classList.toggle("selectedFilter", hash === selectedTag);
|
|
|
|
|
|
|
|
const span = tagFilterItem.firstElementChild;
|
|
|
|
span.lastChild.textContent = `${text} (${count})`;
|
|
|
|
|
|
|
|
return tagFilterItem;
|
2022-10-18 22:39:32 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
let untagged = 0;
|
2024-10-03 08:37:11 -04:00
|
|
|
for (const { full_data: { tags } } of torrentsTable.getRowValues()) {
|
|
|
|
if (tags.length === 0)
|
2022-10-18 22:39:32 -04:00
|
|
|
untagged += 1;
|
|
|
|
}
|
2024-10-03 08:37:11 -04:00
|
|
|
|
|
|
|
tagFilterList.appendChild(createLink(TAGS_ALL, "All", torrentsTable.getRowSize()));
|
|
|
|
tagFilterList.appendChild(createLink(TAGS_UNTAGGED, "Untagged", untagged));
|
2022-10-18 22:39:32 -04:00
|
|
|
|
|
|
|
const sortedTags = [];
|
2024-10-03 08:37:11 -04:00
|
|
|
tagList.forEach((tag, hash) => sortedTags.push({
|
|
|
|
tagName: tag.name,
|
|
|
|
tagHash: hash,
|
|
|
|
tagSize: tag.torrents.size
|
|
|
|
}));
|
|
|
|
sortedTags.sort((left, right) => window.qBittorrent.Misc.naturalSortCollator.compare(left.tagName, right.tagName));
|
2022-10-18 22:39:32 -04:00
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
for (const { tagName, tagHash, tagSize } of sortedTags)
|
|
|
|
tagFilterList.appendChild(createLink(tagHash, tagName, tagSize));
|
|
|
|
|
|
|
|
window.qBittorrent.Filters.tagsFilterContextMenu.searchAndAddTargets();
|
2022-10-18 22:39:32 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
const highlightSelectedTag = function() {
|
2024-10-03 08:37:11 -04:00
|
|
|
const tagFilterList = document.getElementById("tagFilterList");
|
2022-10-18 22:39:32 -04:00
|
|
|
if (!tagFilterList)
|
|
|
|
return;
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
for (const tag of tagFilterList.children)
|
|
|
|
tag.classList.toggle("selectedFilter", (Number(tag.id) === selectedTag));
|
2022-10-18 22:39:32 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
const updateTrackerList = function() {
|
2024-10-01 14:25:40 -04:00
|
|
|
const trackerFilterList = $("trackerFilterList");
|
2022-10-18 22:39:32 -04:00
|
|
|
if (trackerFilterList === null)
|
|
|
|
return;
|
|
|
|
|
2024-01-07 17:04:03 -05:00
|
|
|
trackerFilterList.getChildren().each(c => c.destroy());
|
2022-10-18 22:39:32 -04:00
|
|
|
|
2024-10-01 14:25:40 -04:00
|
|
|
const trackerItemTemplate = document.getElementById("trackerFilterItem");
|
|
|
|
|
2022-10-18 22:39:32 -04:00
|
|
|
const createLink = function(hash, text, count) {
|
2024-10-01 14:25:40 -04:00
|
|
|
const trackerFilterItem = trackerItemTemplate.content.cloneNode(true).firstElementChild;
|
|
|
|
trackerFilterItem.id = hash;
|
|
|
|
trackerFilterItem.classList.toggle("selectedFilter", hash === selectedTracker);
|
|
|
|
|
|
|
|
const span = trackerFilterItem.firstElementChild;
|
|
|
|
span.lastChild.textContent = text.replace("%1", count);
|
|
|
|
|
|
|
|
return trackerFilterItem;
|
2022-10-18 22:39:32 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
let trackerlessTorrentsCount = 0;
|
2024-10-01 14:25:40 -04:00
|
|
|
for (const { full_data: { trackers_count: trackersCount } } of torrentsTable.getRowValues()) {
|
|
|
|
if (trackersCount === 0)
|
2022-10-18 22:39:32 -04:00
|
|
|
trackerlessTorrentsCount += 1;
|
|
|
|
}
|
2024-10-01 14:25:40 -04:00
|
|
|
|
|
|
|
trackerFilterList.appendChild(createLink(TRACKERS_ALL, "All (%1)", torrentsTable.getRowSize()));
|
|
|
|
trackerFilterList.appendChild(createLink(TRACKERS_TRACKERLESS, "Trackerless (%1)", trackerlessTorrentsCount));
|
|
|
|
|
|
|
|
// Remove unused trackers
|
|
|
|
for (const [key, { trackerTorrentMap }] of trackerList) {
|
|
|
|
if (trackerTorrentMap.size === 0)
|
|
|
|
trackerList.delete(key);
|
|
|
|
}
|
2022-10-18 22:39:32 -04:00
|
|
|
|
2023-07-18 11:58:05 -04:00
|
|
|
// Sort trackers by hostname
|
2024-10-01 14:25:40 -04:00
|
|
|
const sortedList = [];
|
|
|
|
trackerList.forEach(({ host, trackerTorrentMap }, hash) => {
|
|
|
|
const uniqueTorrents = new Set();
|
|
|
|
for (const torrents of trackerTorrentMap.values()) {
|
|
|
|
for (const torrent of torrents)
|
|
|
|
uniqueTorrents.add(torrent);
|
|
|
|
}
|
|
|
|
|
|
|
|
sortedList.push({
|
|
|
|
trackerHost: host,
|
|
|
|
trackerHash: hash,
|
|
|
|
trackerCount: uniqueTorrents.size,
|
|
|
|
});
|
2023-07-18 11:58:05 -04:00
|
|
|
});
|
2024-10-01 14:25:40 -04:00
|
|
|
sortedList.sort((left, right) => window.qBittorrent.Misc.naturalSortCollator.compare(left.trackerHost, right.trackerHost));
|
|
|
|
for (const { trackerHost, trackerHash, trackerCount } of sortedList)
|
|
|
|
trackerFilterList.appendChild(createLink(trackerHash, (trackerHost + " (%1)"), trackerCount));
|
2022-10-18 22:39:32 -04:00
|
|
|
|
2024-10-01 14:25:40 -04:00
|
|
|
window.qBittorrent.Filters.trackersFilterContextMenu.searchAndAddTargets();
|
2022-10-18 22:39:32 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
const highlightSelectedTracker = function() {
|
2024-10-03 08:37:11 -04:00
|
|
|
const trackerFilterList = document.getElementById("trackerFilterList");
|
2022-10-18 22:39:32 -04:00
|
|
|
if (!trackerFilterList)
|
|
|
|
return;
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
for (const tracker of trackerFilterList.children)
|
|
|
|
tracker.classList.toggle("selectedFilter", (Number(tracker.id) === selectedTracker));
|
2022-10-18 22:39:32 -04:00
|
|
|
};
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
const setupCopyEventHandler = (function() {
|
|
|
|
let clipboardEvent;
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
if (clipboardEvent)
|
|
|
|
clipboardEvent.destroy();
|
|
|
|
|
|
|
|
clipboardEvent = new ClipboardJS(".copyToClipboard", {
|
|
|
|
text: function(trigger) {
|
|
|
|
switch (trigger.id) {
|
|
|
|
case "copyName":
|
|
|
|
return copyNameFN();
|
|
|
|
case "copyInfohash1":
|
|
|
|
return copyInfohashFN(1);
|
|
|
|
case "copyInfohash2":
|
|
|
|
return copyInfohashFN(2);
|
|
|
|
case "copyMagnetLink":
|
|
|
|
return copyMagnetLinkFN();
|
|
|
|
case "copyID":
|
|
|
|
return copyIdFN();
|
|
|
|
case "copyComment":
|
|
|
|
return copyCommentFN();
|
|
|
|
default:
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
})();
|
|
|
|
|
2024-10-01 14:25:40 -04:00
|
|
|
let syncMainDataTimeoutID = -1;
|
|
|
|
let syncRequestInProgress = false;
|
2022-10-18 22:39:32 -04:00
|
|
|
const syncMainData = function() {
|
2024-10-01 14:25:40 -04:00
|
|
|
const url = new URI("api/v2/sync/maindata");
|
|
|
|
url.setData("rid", syncMainDataLastResponseId);
|
2022-10-18 22:39:32 -04:00
|
|
|
const request = new Request.JSON({
|
|
|
|
url: url,
|
|
|
|
noCache: true,
|
2024-10-01 14:25:40 -04:00
|
|
|
method: "get",
|
2022-10-18 22:39:32 -04:00
|
|
|
onFailure: function() {
|
2024-10-01 14:25:40 -04:00
|
|
|
const errorDiv = $("error_div");
|
2022-10-18 22:39:32 -04:00
|
|
|
if (errorDiv)
|
2024-10-01 14:25:40 -04:00
|
|
|
errorDiv.textContent = "qBittorrent client is not reachable";
|
2022-10-18 22:39:32 -04:00
|
|
|
syncRequestInProgress = false;
|
|
|
|
syncData(2000);
|
|
|
|
},
|
|
|
|
onSuccess: function(response) {
|
2024-10-01 14:25:40 -04:00
|
|
|
$("error_div").textContent = "";
|
2022-10-18 22:39:32 -04:00
|
|
|
if (response) {
|
|
|
|
clearTimeout(torrentsFilterInputTimer);
|
2024-10-01 14:25:40 -04:00
|
|
|
torrentsFilterInputTimer = -1;
|
|
|
|
|
2022-10-18 22:39:32 -04:00
|
|
|
let torrentsTableSelectedRows;
|
|
|
|
let update_categories = false;
|
|
|
|
let updateTags = false;
|
|
|
|
let updateTrackers = false;
|
2024-10-01 14:25:40 -04:00
|
|
|
const full_update = (response["full_update"] === true);
|
2022-10-18 22:39:32 -04:00
|
|
|
if (full_update) {
|
|
|
|
torrentsTableSelectedRows = torrentsTable.selectedRowsIds();
|
2024-10-01 14:25:40 -04:00
|
|
|
update_categories = true;
|
|
|
|
updateTags = true;
|
|
|
|
updateTrackers = true;
|
2022-10-18 22:39:32 -04:00
|
|
|
torrentsTable.clear();
|
2024-10-01 14:25:40 -04:00
|
|
|
category_list.clear();
|
|
|
|
tagList.clear();
|
|
|
|
trackerList.clear();
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
2024-10-01 14:25:40 -04:00
|
|
|
if (response["rid"])
|
|
|
|
syncMainDataLastResponseId = response["rid"];
|
|
|
|
if (response["categories"]) {
|
|
|
|
for (const key in response["categories"]) {
|
|
|
|
if (!Object.hasOwn(response["categories"], key))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
const responseCategory = response["categories"][key];
|
|
|
|
const categoryHash = window.qBittorrent.Misc.genHash(key);
|
|
|
|
const category = category_list.get(categoryHash);
|
|
|
|
if (category !== undefined) {
|
2022-10-18 22:39:32 -04:00
|
|
|
// only the save path can change for existing categories
|
2024-10-01 14:25:40 -04:00
|
|
|
category.savePath = responseCategory.savePath;
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
else {
|
2024-10-01 14:25:40 -04:00
|
|
|
category_list.set(categoryHash, {
|
|
|
|
name: responseCategory.name,
|
|
|
|
savePath: responseCategory.savePath,
|
|
|
|
torrents: new Set()
|
|
|
|
});
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
update_categories = true;
|
|
|
|
}
|
2024-10-01 14:25:40 -04:00
|
|
|
if (response["categories_removed"]) {
|
|
|
|
response["categories_removed"].each((category) => {
|
|
|
|
const categoryHash = window.qBittorrent.Misc.genHash(category);
|
|
|
|
category_list.delete(categoryHash);
|
2022-10-18 22:39:32 -04:00
|
|
|
});
|
|
|
|
update_categories = true;
|
|
|
|
}
|
2024-10-01 14:25:40 -04:00
|
|
|
if (response["tags"]) {
|
|
|
|
for (const tag of response["tags"]) {
|
|
|
|
const tagHash = window.qBittorrent.Misc.genHash(tag);
|
|
|
|
if (!tagList.has(tagHash)) {
|
|
|
|
tagList.set(tagHash, {
|
2022-10-18 22:39:32 -04:00
|
|
|
name: tag,
|
2024-10-01 14:25:40 -04:00
|
|
|
torrents: new Set()
|
|
|
|
});
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
updateTags = true;
|
|
|
|
}
|
2024-10-01 14:25:40 -04:00
|
|
|
if (response["tags_removed"]) {
|
|
|
|
for (let i = 0; i < response["tags_removed"].length; ++i) {
|
|
|
|
const tagHash = window.qBittorrent.Misc.genHash(response["tags_removed"][i]);
|
|
|
|
tagList.delete(tagHash);
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
updateTags = true;
|
|
|
|
}
|
2024-10-01 14:25:40 -04:00
|
|
|
if (response["trackers"]) {
|
|
|
|
for (const [tracker, torrents] of Object.entries(response["trackers"])) {
|
|
|
|
const host = window.qBittorrent.Misc.getHost(tracker);
|
|
|
|
const hash = window.qBittorrent.Misc.genHash(host);
|
|
|
|
|
|
|
|
let trackerListItem = trackerList.get(hash);
|
|
|
|
if (trackerListItem === undefined) {
|
|
|
|
trackerListItem = { host: host, trackerTorrentMap: new Map() };
|
|
|
|
trackerList.set(hash, trackerListItem);
|
2023-07-18 11:58:05 -04:00
|
|
|
}
|
2024-10-01 14:25:40 -04:00
|
|
|
trackerListItem.trackerTorrentMap.set(tracker, new Set(torrents));
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
updateTrackers = true;
|
|
|
|
}
|
2024-10-01 14:25:40 -04:00
|
|
|
if (response["trackers_removed"]) {
|
|
|
|
for (let i = 0; i < response["trackers_removed"].length; ++i) {
|
|
|
|
const tracker = response["trackers_removed"][i];
|
|
|
|
const host = window.qBittorrent.Misc.getHost(tracker);
|
|
|
|
const hash = window.qBittorrent.Misc.genHash(host);
|
|
|
|
const trackerListEntry = trackerList.get(hash);
|
|
|
|
if (trackerListEntry)
|
|
|
|
trackerListEntry.trackerTorrentMap.delete(tracker);
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
updateTrackers = true;
|
|
|
|
}
|
2024-10-01 14:25:40 -04:00
|
|
|
if (response["torrents"]) {
|
2022-10-18 22:39:32 -04:00
|
|
|
let updateTorrentList = false;
|
2024-10-01 14:25:40 -04:00
|
|
|
for (const key in response["torrents"]) {
|
|
|
|
if (!Object.hasOwn(response["torrents"], key))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
response["torrents"][key]["hash"] = key;
|
|
|
|
response["torrents"][key]["rowId"] = key;
|
|
|
|
if (response["torrents"][key]["state"])
|
|
|
|
response["torrents"][key]["status"] = response["torrents"][key]["state"];
|
|
|
|
torrentsTable.updateRowData(response["torrents"][key]);
|
|
|
|
if (addTorrentToCategoryList(response["torrents"][key]))
|
2022-10-18 22:39:32 -04:00
|
|
|
update_categories = true;
|
2024-10-01 14:25:40 -04:00
|
|
|
if (addTorrentToTagList(response["torrents"][key]))
|
2022-10-18 22:39:32 -04:00
|
|
|
updateTags = true;
|
2024-10-01 14:25:40 -04:00
|
|
|
if (response["torrents"][key]["name"])
|
2022-10-18 22:39:32 -04:00
|
|
|
updateTorrentList = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (updateTorrentList)
|
|
|
|
setupCopyEventHandler();
|
|
|
|
}
|
2024-10-01 14:25:40 -04:00
|
|
|
if (response["torrents_removed"]) {
|
|
|
|
response["torrents_removed"].each((hash) => {
|
2022-10-18 22:39:32 -04:00
|
|
|
torrentsTable.removeRow(hash);
|
|
|
|
removeTorrentFromCategoryList(hash);
|
|
|
|
update_categories = true; // Always to update All category
|
|
|
|
removeTorrentFromTagList(hash);
|
|
|
|
updateTags = true; // Always to update All tag
|
|
|
|
});
|
2024-10-01 14:25:40 -04:00
|
|
|
}
|
2022-10-18 22:39:32 -04:00
|
|
|
torrentsTable.updateTable(full_update);
|
2024-10-01 14:25:40 -04:00
|
|
|
if (response["server_state"]) {
|
|
|
|
const tmp = response["server_state"];
|
|
|
|
for (const k in tmp) {
|
|
|
|
if (!Object.hasOwn(tmp, k))
|
|
|
|
continue;
|
2022-10-18 22:39:32 -04:00
|
|
|
serverState[k] = tmp[k];
|
2024-10-01 14:25:40 -04:00
|
|
|
}
|
2022-10-18 22:39:32 -04:00
|
|
|
processServerState();
|
|
|
|
}
|
|
|
|
updateFiltersList();
|
|
|
|
if (update_categories) {
|
|
|
|
updateCategoryList();
|
|
|
|
window.qBittorrent.TransferList.contextMenu.updateCategoriesSubMenu(category_list);
|
|
|
|
}
|
|
|
|
if (updateTags) {
|
|
|
|
updateTagList();
|
|
|
|
window.qBittorrent.TransferList.contextMenu.updateTagsSubMenu(tagList);
|
|
|
|
}
|
|
|
|
if (updateTrackers)
|
|
|
|
updateTrackerList();
|
|
|
|
|
|
|
|
if (full_update)
|
|
|
|
// re-select previously selected rows
|
|
|
|
torrentsTable.reselectRows(torrentsTableSelectedRows);
|
|
|
|
}
|
|
|
|
syncRequestInProgress = false;
|
2024-10-01 14:25:40 -04:00
|
|
|
syncData(window.qBittorrent.Client.getSyncMainDataInterval());
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
});
|
|
|
|
syncRequestInProgress = true;
|
|
|
|
request.send();
|
|
|
|
};
|
|
|
|
|
|
|
|
updateMainData = function() {
|
|
|
|
torrentsTable.updateTable();
|
|
|
|
syncData(100);
|
|
|
|
};
|
|
|
|
|
|
|
|
const syncData = function(delay) {
|
2024-10-01 14:25:40 -04:00
|
|
|
if (syncRequestInProgress)
|
|
|
|
return;
|
|
|
|
|
|
|
|
clearTimeout(syncMainDataTimeoutID);
|
|
|
|
syncMainDataTimeoutID = -1;
|
|
|
|
|
|
|
|
if (window.qBittorrent.Client.isStopped())
|
|
|
|
return;
|
|
|
|
|
|
|
|
syncMainDataTimeoutID = syncMainData.delay(delay);
|
2022-10-18 22:39:32 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
const processServerState = function() {
|
|
|
|
let transfer_info = window.qBittorrent.Misc.friendlyUnit(serverState.dl_info_speed, true);
|
|
|
|
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) + ")";
|
2024-10-03 08:37:11 -04:00
|
|
|
$("DlInfos").textContent = transfer_info;
|
2022-10-18 22:39:32 -04:00
|
|
|
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) + ")";
|
2024-10-03 08:37:11 -04:00
|
|
|
$("UpInfos").textContent = transfer_info;
|
|
|
|
|
|
|
|
document.title = (speedInTitle
|
|
|
|
? (`[D: %1, U: %2] `
|
|
|
|
.replace("%1", window.qBittorrent.Misc.friendlyUnit(serverState.dl_info_speed, true))
|
|
|
|
.replace("%2", window.qBittorrent.Misc.friendlyUnit(serverState.up_info_speed, true)))
|
|
|
|
: "")
|
|
|
|
+ window.qBittorrent.Client.mainTitle();
|
|
|
|
|
|
|
|
$("freeSpaceOnDisk").textContent = "Free space: %1".replace("%1", window.qBittorrent.Misc.friendlyUnit(serverState.free_space_on_disk));
|
|
|
|
|
|
|
|
const dhtElement = document.getElementById("DHTNodes");
|
|
|
|
if (window.qBittorrent.Cache.preferences.get().dht) {
|
|
|
|
dhtElement.textContent = "DHT: %1 nodes".replace("%1", serverState.dht_nodes);
|
|
|
|
dhtElement.classList.remove("invisible");
|
|
|
|
dhtElement.previousElementSibling.classList.remove("invisible");
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
2024-10-03 08:37:11 -04:00
|
|
|
else {
|
|
|
|
dhtElement.classList.add("invisible");
|
|
|
|
dhtElement.previousElementSibling.classList.add("invisible");
|
2024-03-01 20:20:15 +11:00
|
|
|
}
|
2022-10-18 22:39:32 -04:00
|
|
|
|
|
|
|
// Statistics dialog
|
|
|
|
if (document.getElementById("statisticsContent")) {
|
2024-10-03 08:37:11 -04:00
|
|
|
$("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);
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (serverState.connection_status) {
|
2024-10-03 08:37:11 -04:00
|
|
|
case "connected":
|
|
|
|
$("connectionStatus").src = "images/connected.svg";
|
|
|
|
$("connectionStatus").alt = "Connection status: Connected";
|
|
|
|
$("connectionStatus").title = "Connection status: Connected";
|
2022-10-18 22:39:32 -04:00
|
|
|
break;
|
2024-10-03 08:37:11 -04:00
|
|
|
case "firewalled":
|
|
|
|
$("connectionStatus").src = "images/firewalled.svg";
|
|
|
|
$("connectionStatus").alt = "Connection status: Firewalled";
|
|
|
|
$("connectionStatus").title = "Connection status: Firewalled";
|
2022-10-18 22:39:32 -04:00
|
|
|
break;
|
|
|
|
default:
|
2024-10-03 08:37:11 -04:00
|
|
|
$("connectionStatus").src = "images/disconnected.svg";
|
|
|
|
$("connectionStatus").alt = "Connection status: Disconnected";
|
|
|
|
$("connectionStatus").title = "Connection status: Disconnected";
|
2022-10-18 22:39:32 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
if (queueing_enabled !== serverState.queueing) {
|
2022-10-18 22:39:32 -04:00
|
|
|
queueing_enabled = serverState.queueing;
|
2024-10-03 08:37:11 -04:00
|
|
|
torrentsTable.columns["priority"].force_hide = !queueing_enabled;
|
|
|
|
torrentsTable.updateColumn("priority");
|
2022-10-18 22:39:32 -04:00
|
|
|
if (queueing_enabled) {
|
2024-10-03 08:37:11 -04:00
|
|
|
$("topQueuePosItem").removeClass("invisible");
|
|
|
|
$("increaseQueuePosItem").removeClass("invisible");
|
|
|
|
$("decreaseQueuePosItem").removeClass("invisible");
|
|
|
|
$("bottomQueuePosItem").removeClass("invisible");
|
|
|
|
$("queueingButtons").removeClass("invisible");
|
|
|
|
$("queueingMenuItems").removeClass("invisible");
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
else {
|
2024-10-03 08:37:11 -04:00
|
|
|
$("topQueuePosItem").addClass("invisible");
|
|
|
|
$("increaseQueuePosItem").addClass("invisible");
|
|
|
|
$("decreaseQueuePosItem").addClass("invisible");
|
|
|
|
$("bottomQueuePosItem").addClass("invisible");
|
|
|
|
$("queueingButtons").addClass("invisible");
|
|
|
|
$("queueingMenuItems").addClass("invisible");
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
if (alternativeSpeedLimits !== serverState.use_alt_speed_limits) {
|
2022-10-18 22:39:32 -04:00
|
|
|
alternativeSpeedLimits = serverState.use_alt_speed_limits;
|
|
|
|
updateAltSpeedIcon(alternativeSpeedLimits);
|
|
|
|
}
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
if (useSubcategories !== serverState.use_subcategories) {
|
2023-07-18 11:58:05 -04:00
|
|
|
useSubcategories = serverState.use_subcategories;
|
|
|
|
updateCategoryList();
|
|
|
|
}
|
|
|
|
|
2022-10-18 22:39:32 -04:00
|
|
|
serverSyncMainDataInterval = Math.max(serverState.refresh_interval, 500);
|
|
|
|
};
|
|
|
|
|
|
|
|
const updateAltSpeedIcon = function(enabled) {
|
|
|
|
if (enabled) {
|
2024-10-03 08:37:11 -04:00
|
|
|
$("alternativeSpeedLimits").src = "images/slow.svg";
|
|
|
|
$("alternativeSpeedLimits").alt = "Alternative speed limits: On";
|
|
|
|
$("alternativeSpeedLimits").title = "Alternative speed limits: On";
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
else {
|
2024-10-03 08:37:11 -04:00
|
|
|
$("alternativeSpeedLimits").src = "images/slow_off.svg";
|
|
|
|
$("alternativeSpeedLimits").alt = "Alternative speed limits: Off";
|
|
|
|
$("alternativeSpeedLimits").title = "Alternative speed limits: Off";
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
$("alternativeSpeedLimits").addEventListener("click", () => {
|
2022-10-18 22:39:32 -04:00
|
|
|
// Change icon immediately to give some feedback
|
|
|
|
updateAltSpeedIcon(!alternativeSpeedLimits);
|
|
|
|
|
|
|
|
new Request({
|
2024-10-03 08:37:11 -04:00
|
|
|
url: "api/v2/transfer/toggleSpeedLimitsMode",
|
|
|
|
method: "post",
|
2022-10-18 22:39:32 -04:00
|
|
|
onComplete: function() {
|
|
|
|
alternativeSpeedLimits = !alternativeSpeedLimits;
|
|
|
|
updateMainData();
|
|
|
|
},
|
|
|
|
onFailure: function() {
|
|
|
|
// Restore icon in case of failure
|
|
|
|
updateAltSpeedIcon(alternativeSpeedLimits);
|
|
|
|
}
|
|
|
|
}).send();
|
|
|
|
});
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
$("DlInfos").addEventListener("click", () => { globalDownloadLimitFN(); });
|
|
|
|
$("UpInfos").addEventListener("click", () => { globalUploadLimitFN(); });
|
2022-10-18 22:39:32 -04:00
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
$("showTopToolbarLink").addEventListener("click", (e) => {
|
2022-10-18 22:39:32 -04:00
|
|
|
showTopToolbar = !showTopToolbar;
|
2024-10-03 08:37:11 -04:00
|
|
|
LocalPreferences.set("show_top_toolbar", showTopToolbar.toString());
|
2022-10-18 22:39:32 -04:00
|
|
|
if (showTopToolbar) {
|
2024-10-03 08:37:11 -04:00
|
|
|
$("showTopToolbarLink").firstChild.style.opacity = "1";
|
|
|
|
$("mochaToolbar").removeClass("invisible");
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
else {
|
2024-10-03 08:37:11 -04:00
|
|
|
$("showTopToolbarLink").firstChild.style.opacity = "0";
|
|
|
|
$("mochaToolbar").addClass("invisible");
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
MochaUI.Desktop.setDesktopSize();
|
|
|
|
});
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
$("showStatusBarLink").addEventListener("click", (e) => {
|
2022-10-18 22:39:32 -04:00
|
|
|
showStatusBar = !showStatusBar;
|
2024-10-03 08:37:11 -04:00
|
|
|
LocalPreferences.set("show_status_bar", showStatusBar.toString());
|
2022-10-18 22:39:32 -04:00
|
|
|
if (showStatusBar) {
|
2024-10-03 08:37:11 -04:00
|
|
|
$("showStatusBarLink").firstChild.style.opacity = "1";
|
|
|
|
$("desktopFooterWrapper").removeClass("invisible");
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
else {
|
2024-10-03 08:37:11 -04:00
|
|
|
$("showStatusBarLink").firstChild.style.opacity = "0";
|
|
|
|
$("desktopFooterWrapper").addClass("invisible");
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
MochaUI.Desktop.setDesktopSize();
|
|
|
|
});
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
const registerMagnetHandler = function() {
|
|
|
|
if (typeof navigator.registerProtocolHandler !== "function") {
|
|
|
|
if (window.location.protocol !== "https:")
|
|
|
|
alert("To use this feature, the WebUI needs to be accessed over HTTPS");
|
|
|
|
else
|
|
|
|
alert("Your browser does not support this feature");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const hashString = location.hash ? location.hash.replace(/^#/, "") : "";
|
|
|
|
const hashParams = new URLSearchParams(hashString);
|
|
|
|
hashParams.set("download", "");
|
|
|
|
|
|
|
|
const templateHashString = hashParams.toString().replace("download=", "download=%s");
|
|
|
|
const templateUrl = location.origin + location.pathname
|
|
|
|
+ location.search + "#" + templateHashString;
|
|
|
|
|
|
|
|
navigator.registerProtocolHandler("magnet", templateUrl,
|
|
|
|
"qBittorrent WebUI magnet handler");
|
|
|
|
};
|
|
|
|
$("registerMagnetHandlerLink").addEventListener("click", (e) => {
|
2022-10-18 22:39:32 -04:00
|
|
|
registerMagnetHandler();
|
|
|
|
});
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
$("showFiltersSidebarLink").addEventListener("click", (e) => {
|
|
|
|
showFiltersSidebar = !showFiltersSidebar;
|
|
|
|
LocalPreferences.set("show_filters_sidebar", showFiltersSidebar.toString());
|
2022-10-18 22:39:32 -04:00
|
|
|
if (showFiltersSidebar) {
|
2024-10-03 08:37:11 -04:00
|
|
|
$("showFiltersSidebarLink").firstChild.style.opacity = "1";
|
|
|
|
$("filtersColumn").removeClass("invisible");
|
|
|
|
$("filtersColumn_handle").removeClass("invisible");
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
else {
|
2024-10-03 08:37:11 -04:00
|
|
|
$("showFiltersSidebarLink").firstChild.style.opacity = "0";
|
|
|
|
$("filtersColumn").addClass("invisible");
|
|
|
|
$("filtersColumn_handle").addClass("invisible");
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
MochaUI.Desktop.setDesktopSize();
|
|
|
|
});
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
$("speedInBrowserTitleBarLink").addEventListener("click", (e) => {
|
2022-10-18 22:39:32 -04:00
|
|
|
speedInTitle = !speedInTitle;
|
2024-10-03 08:37:11 -04:00
|
|
|
LocalPreferences.set("speed_in_browser_title_bar", speedInTitle.toString());
|
2022-10-18 22:39:32 -04:00
|
|
|
if (speedInTitle)
|
2024-10-03 08:37:11 -04:00
|
|
|
$("speedInBrowserTitleBarLink").firstChild.style.opacity = "1";
|
2022-10-18 22:39:32 -04:00
|
|
|
else
|
2024-10-03 08:37:11 -04:00
|
|
|
$("speedInBrowserTitleBarLink").firstChild.style.opacity = "0";
|
2022-10-18 22:39:32 -04:00
|
|
|
processServerState();
|
|
|
|
});
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
$("showSearchEngineLink").addEventListener("click", (e) => {
|
|
|
|
window.qBittorrent.Client.showSearchEngine(!window.qBittorrent.Client.isShowSearchEngine());
|
|
|
|
LocalPreferences.set("show_search_engine", window.qBittorrent.Client.isShowSearchEngine().toString());
|
2022-10-18 22:39:32 -04:00
|
|
|
updateTabDisplay();
|
|
|
|
});
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
$("showRssReaderLink").addEventListener("click", (e) => {
|
|
|
|
window.qBittorrent.Client.showRssReader(!window.qBittorrent.Client.isShowRssReader());
|
|
|
|
LocalPreferences.set("show_rss_reader", window.qBittorrent.Client.isShowRssReader().toString());
|
2022-10-18 22:39:32 -04:00
|
|
|
updateTabDisplay();
|
|
|
|
});
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
$("showLogViewerLink").addEventListener("click", (e) => {
|
|
|
|
window.qBittorrent.Client.showLogViewer(!window.qBittorrent.Client.isShowLogViewer());
|
|
|
|
LocalPreferences.set("show_log_viewer", window.qBittorrent.Client.isShowLogViewer().toString());
|
2023-07-18 11:58:05 -04:00
|
|
|
updateTabDisplay();
|
|
|
|
});
|
|
|
|
|
2022-10-18 22:39:32 -04:00
|
|
|
const updateTabDisplay = function() {
|
2024-10-03 08:37:11 -04:00
|
|
|
if (window.qBittorrent.Client.isShowRssReader()) {
|
|
|
|
$("showRssReaderLink").firstChild.style.opacity = "1";
|
|
|
|
$("mainWindowTabs").removeClass("invisible");
|
|
|
|
$("rssTabLink").removeClass("invisible");
|
2022-10-18 22:39:32 -04:00
|
|
|
if (!MochaUI.Panels.instances.RssPanel)
|
|
|
|
addRssPanel();
|
|
|
|
}
|
|
|
|
else {
|
2024-10-03 08:37:11 -04:00
|
|
|
$("showRssReaderLink").firstChild.style.opacity = "0";
|
|
|
|
$("rssTabLink").addClass("invisible");
|
|
|
|
if ($("rssTabLink").hasClass("selected"))
|
2022-10-18 22:39:32 -04:00
|
|
|
$("transfersTabLink").click();
|
|
|
|
}
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
if (window.qBittorrent.Client.isShowSearchEngine()) {
|
|
|
|
$("showSearchEngineLink").firstChild.style.opacity = "1";
|
|
|
|
$("mainWindowTabs").removeClass("invisible");
|
|
|
|
$("searchTabLink").removeClass("invisible");
|
2022-10-18 22:39:32 -04:00
|
|
|
if (!MochaUI.Panels.instances.SearchPanel)
|
|
|
|
addSearchPanel();
|
|
|
|
}
|
|
|
|
else {
|
2024-10-03 08:37:11 -04:00
|
|
|
$("showSearchEngineLink").firstChild.style.opacity = "0";
|
|
|
|
$("searchTabLink").addClass("invisible");
|
|
|
|
if ($("searchTabLink").hasClass("selected"))
|
2022-10-18 22:39:32 -04:00
|
|
|
$("transfersTabLink").click();
|
|
|
|
}
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
if (window.qBittorrent.Client.isShowLogViewer()) {
|
|
|
|
$("showLogViewerLink").firstChild.style.opacity = "1";
|
|
|
|
$("mainWindowTabs").removeClass("invisible");
|
|
|
|
$("logTabLink").removeClass("invisible");
|
2023-07-18 11:58:05 -04:00
|
|
|
if (!MochaUI.Panels.instances.LogPanel)
|
|
|
|
addLogPanel();
|
|
|
|
}
|
|
|
|
else {
|
2024-10-03 08:37:11 -04:00
|
|
|
$("showLogViewerLink").firstChild.style.opacity = "0";
|
|
|
|
$("logTabLink").addClass("invisible");
|
|
|
|
if ($("logTabLink").hasClass("selected"))
|
2023-07-18 11:58:05 -04:00
|
|
|
$("transfersTabLink").click();
|
|
|
|
}
|
|
|
|
|
2022-10-18 22:39:32 -04:00
|
|
|
// display no tabs
|
2024-10-03 08:37:11 -04:00
|
|
|
if (!window.qBittorrent.Client.isShowRssReader() && !window.qBittorrent.Client.isShowSearchEngine() && !window.qBittorrent.Client.isShowLogViewer())
|
|
|
|
$("mainWindowTabs").addClass("invisible");
|
2022-10-18 22:39:32 -04:00
|
|
|
};
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
$("StatisticsLink").addEventListener("click", () => { StatisticsLinkFN(); });
|
2022-10-18 22:39:32 -04:00
|
|
|
|
|
|
|
// main window tabs
|
|
|
|
|
|
|
|
const showTransfersTab = function() {
|
2024-10-03 08:37:11 -04:00
|
|
|
const showFiltersSidebar = LocalPreferences.get("show_filters_sidebar", "true") === "true";
|
|
|
|
if (showFiltersSidebar) {
|
|
|
|
$("filtersColumn").removeClass("invisible");
|
|
|
|
$("filtersColumn_handle").removeClass("invisible");
|
|
|
|
}
|
2022-10-18 22:39:32 -04:00
|
|
|
$("mainColumn").removeClass("invisible");
|
2024-10-03 08:37:11 -04:00
|
|
|
$("torrentsFilterToolbar").removeClass("invisible");
|
2022-10-18 22:39:32 -04:00
|
|
|
|
|
|
|
customSyncMainDataInterval = null;
|
|
|
|
syncData(100);
|
|
|
|
|
|
|
|
hideSearchTab();
|
|
|
|
hideRssTab();
|
2023-07-18 11:58:05 -04:00
|
|
|
hideLogTab();
|
2024-10-03 08:37:11 -04:00
|
|
|
|
|
|
|
LocalPreferences.set("selected_window_tab", "transfers");
|
2022-10-18 22:39:32 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
const hideTransfersTab = function() {
|
|
|
|
$("filtersColumn").addClass("invisible");
|
|
|
|
$("filtersColumn_handle").addClass("invisible");
|
|
|
|
$("mainColumn").addClass("invisible");
|
2024-10-03 08:37:11 -04:00
|
|
|
$("torrentsFilterToolbar").addClass("invisible");
|
2022-10-18 22:39:32 -04:00
|
|
|
MochaUI.Desktop.resizePanels();
|
|
|
|
};
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
const showSearchTab = (function() {
|
|
|
|
let searchTabInitialized = false;
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
// we must wait until the panel is fully loaded before proceeding.
|
|
|
|
// this include's the panel's custom js, which is loaded via MochaUI.Panel's 'require' field.
|
|
|
|
// MochaUI loads these files asynchronously and thus all required libs may not be available immediately
|
|
|
|
if (!isSearchPanelLoaded) {
|
|
|
|
setTimeout(() => {
|
|
|
|
showSearchTab();
|
|
|
|
}, 100);
|
|
|
|
return;
|
|
|
|
}
|
2022-10-18 22:39:32 -04:00
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
if (!searchTabInitialized) {
|
|
|
|
window.qBittorrent.Search.init();
|
|
|
|
searchTabInitialized = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
$("searchTabColumn").removeClass("invisible");
|
|
|
|
customSyncMainDataInterval = 30000;
|
|
|
|
hideTransfersTab();
|
|
|
|
hideRssTab();
|
|
|
|
hideLogTab();
|
|
|
|
|
|
|
|
LocalPreferences.set("selected_window_tab", "search");
|
|
|
|
};
|
|
|
|
})();
|
2022-10-18 22:39:32 -04:00
|
|
|
|
|
|
|
const hideSearchTab = function() {
|
|
|
|
$("searchTabColumn").addClass("invisible");
|
|
|
|
MochaUI.Desktop.resizePanels();
|
|
|
|
};
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
const showRssTab = (function() {
|
|
|
|
let rssTabInitialized = false;
|
2022-10-18 22:39:32 -04:00
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
return () => {
|
|
|
|
if (!rssTabInitialized) {
|
|
|
|
window.qBittorrent.Rss.init();
|
|
|
|
rssTabInitialized = true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
window.qBittorrent.Rss.load();
|
|
|
|
}
|
|
|
|
|
|
|
|
$("rssTabColumn").removeClass("invisible");
|
|
|
|
customSyncMainDataInterval = 30000;
|
|
|
|
hideTransfersTab();
|
|
|
|
hideSearchTab();
|
|
|
|
hideLogTab();
|
|
|
|
|
|
|
|
LocalPreferences.set("selected_window_tab", "rss");
|
|
|
|
};
|
|
|
|
})();
|
2022-10-18 22:39:32 -04:00
|
|
|
|
|
|
|
const hideRssTab = function() {
|
|
|
|
$("rssTabColumn").addClass("invisible");
|
2023-07-18 11:58:05 -04:00
|
|
|
window.qBittorrent.Rss && window.qBittorrent.Rss.unload();
|
2022-10-18 22:39:32 -04:00
|
|
|
MochaUI.Desktop.resizePanels();
|
|
|
|
};
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
const showLogTab = (function() {
|
|
|
|
let logTabInitialized = false;
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
// we must wait until the panel is fully loaded before proceeding.
|
|
|
|
// this include's the panel's custom js, which is loaded via MochaUI.Panel's 'require' field.
|
|
|
|
// MochaUI loads these files asynchronously and thus all required libs may not be available immediately
|
|
|
|
if (!isLogPanelLoaded) {
|
|
|
|
setTimeout(() => {
|
|
|
|
showLogTab();
|
|
|
|
}, 100);
|
|
|
|
return;
|
|
|
|
}
|
2023-07-18 11:58:05 -04:00
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
if (!logTabInitialized) {
|
|
|
|
window.qBittorrent.Log.init();
|
|
|
|
logTabInitialized = true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
window.qBittorrent.Log.load();
|
|
|
|
}
|
|
|
|
|
|
|
|
$("logTabColumn").removeClass("invisible");
|
|
|
|
customSyncMainDataInterval = 30000;
|
|
|
|
hideTransfersTab();
|
|
|
|
hideSearchTab();
|
|
|
|
hideRssTab();
|
|
|
|
|
|
|
|
LocalPreferences.set("selected_window_tab", "log");
|
|
|
|
};
|
|
|
|
})();
|
2023-07-18 11:58:05 -04:00
|
|
|
|
|
|
|
const hideLogTab = function() {
|
2024-10-03 08:37:11 -04:00
|
|
|
$("logTabColumn").addClass("invisible");
|
2023-07-18 11:58:05 -04:00
|
|
|
MochaUI.Desktop.resizePanels();
|
|
|
|
window.qBittorrent.Log && window.qBittorrent.Log.unload();
|
|
|
|
};
|
|
|
|
|
2022-10-18 22:39:32 -04:00
|
|
|
const addSearchPanel = function() {
|
|
|
|
new MochaUI.Panel({
|
2024-10-03 08:37:11 -04:00
|
|
|
id: "SearchPanel",
|
|
|
|
title: "Search",
|
2022-10-18 22:39:32 -04:00
|
|
|
header: false,
|
|
|
|
padding: {
|
|
|
|
top: 0,
|
|
|
|
right: 0,
|
|
|
|
bottom: 0,
|
|
|
|
left: 0
|
|
|
|
},
|
2024-10-03 08:37:11 -04:00
|
|
|
loadMethod: "xhr",
|
|
|
|
contentURL: "views/search.html",
|
|
|
|
require: {
|
|
|
|
js: ["scripts/search.js"],
|
|
|
|
onload: () => {
|
|
|
|
isSearchPanelLoaded = true;
|
|
|
|
},
|
|
|
|
},
|
|
|
|
content: "",
|
|
|
|
column: "searchTabColumn",
|
2022-10-18 22:39:32 -04:00
|
|
|
height: null
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
const addRssPanel = function() {
|
|
|
|
new MochaUI.Panel({
|
2024-10-03 08:37:11 -04:00
|
|
|
id: "RssPanel",
|
|
|
|
title: "Rss",
|
2022-10-18 22:39:32 -04:00
|
|
|
header: false,
|
|
|
|
padding: {
|
|
|
|
top: 0,
|
|
|
|
right: 0,
|
|
|
|
bottom: 0,
|
|
|
|
left: 0
|
|
|
|
},
|
2024-10-03 08:37:11 -04:00
|
|
|
loadMethod: "xhr",
|
|
|
|
contentURL: "views/rss.html",
|
|
|
|
content: "",
|
|
|
|
column: "rssTabColumn",
|
2022-10-18 22:39:32 -04:00
|
|
|
height: null
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
const addLogPanel = function() {
|
2023-07-18 11:58:05 -04:00
|
|
|
new MochaUI.Panel({
|
2024-10-03 08:37:11 -04:00
|
|
|
id: "LogPanel",
|
|
|
|
title: "Log",
|
2023-07-18 11:58:05 -04:00
|
|
|
header: true,
|
|
|
|
padding: {
|
|
|
|
top: 0,
|
|
|
|
right: 0,
|
|
|
|
bottom: 0,
|
|
|
|
left: 0
|
|
|
|
},
|
2024-10-03 08:37:11 -04:00
|
|
|
loadMethod: "xhr",
|
|
|
|
contentURL: "views/log.html",
|
2023-07-18 11:58:05 -04:00
|
|
|
require: {
|
2024-10-03 08:37:11 -04:00
|
|
|
css: ["css/vanillaSelectBox.css"],
|
|
|
|
js: ["scripts/lib/vanillaSelectBox.js"],
|
|
|
|
onload: () => {
|
|
|
|
isLogPanelLoaded = true;
|
|
|
|
},
|
2023-07-18 11:58:05 -04:00
|
|
|
},
|
2024-10-03 08:37:11 -04:00
|
|
|
tabsURL: "views/logTabs.html",
|
2023-07-18 11:58:05 -04:00
|
|
|
tabsOnload: function() {
|
2024-10-03 08:37:11 -04:00
|
|
|
MochaUI.initializeTabs("panelTabs");
|
2023-07-18 11:58:05 -04:00
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
$("logMessageLink").addEventListener("click", (e) => {
|
|
|
|
window.qBittorrent.Log.setCurrentTab("main");
|
2023-07-18 11:58:05 -04:00
|
|
|
});
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
$("logPeerLink").addEventListener("click", (e) => {
|
|
|
|
window.qBittorrent.Log.setCurrentTab("peer");
|
2023-07-18 11:58:05 -04:00
|
|
|
});
|
|
|
|
},
|
|
|
|
collapsible: false,
|
2024-10-03 08:37:11 -04:00
|
|
|
content: "",
|
|
|
|
column: "logTabColumn",
|
2023-07-18 11:58:05 -04:00
|
|
|
height: null
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
const handleDownloadParam = function() {
|
|
|
|
// Extract torrent URL from download param in WebUI URL hash
|
|
|
|
const downloadHash = "#download=";
|
|
|
|
if (location.hash.indexOf(downloadHash) !== 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const url = decodeURIComponent(location.hash.substring(downloadHash.length));
|
|
|
|
// Remove the processed hash from the URL
|
|
|
|
history.replaceState("", document.title, (location.pathname + location.search));
|
|
|
|
showDownloadPage([url]);
|
|
|
|
};
|
|
|
|
|
2022-10-18 22:39:32 -04:00
|
|
|
new MochaUI.Panel({
|
2024-10-03 08:37:11 -04:00
|
|
|
id: "transferList",
|
|
|
|
title: "Panel",
|
2022-10-18 22:39:32 -04:00
|
|
|
header: false,
|
|
|
|
padding: {
|
|
|
|
top: 0,
|
|
|
|
right: 0,
|
|
|
|
bottom: 0,
|
|
|
|
left: 0
|
|
|
|
},
|
2024-10-03 08:37:11 -04:00
|
|
|
loadMethod: "xhr",
|
|
|
|
contentURL: "views/transferlist.html",
|
2022-10-18 22:39:32 -04:00
|
|
|
onContentLoaded: function() {
|
|
|
|
handleDownloadParam();
|
|
|
|
updateMainData();
|
|
|
|
},
|
2024-10-03 08:37:11 -04:00
|
|
|
column: "mainColumn",
|
|
|
|
onResize: window.qBittorrent.Misc.createDebounceHandler(500, (e) => {
|
|
|
|
saveColumnSizes();
|
|
|
|
}),
|
2022-10-18 22:39:32 -04:00
|
|
|
height: null
|
|
|
|
});
|
2024-10-03 08:37:11 -04:00
|
|
|
let prop_h = LocalPreferences.get("properties_height_rel");
|
|
|
|
if (prop_h !== null)
|
2022-10-18 22:39:32 -04:00
|
|
|
prop_h = prop_h.toFloat() * Window.getSize().y;
|
|
|
|
else
|
|
|
|
prop_h = Window.getSize().y / 2.0;
|
|
|
|
new MochaUI.Panel({
|
2024-10-03 08:37:11 -04:00
|
|
|
id: "propertiesPanel",
|
|
|
|
title: "Panel",
|
2022-10-18 22:39:32 -04:00
|
|
|
padding: {
|
|
|
|
top: 0,
|
|
|
|
right: 0,
|
|
|
|
bottom: 0,
|
|
|
|
left: 0
|
|
|
|
},
|
2024-10-03 08:37:11 -04:00
|
|
|
contentURL: "views/properties.html",
|
2022-10-18 22:39:32 -04:00
|
|
|
require: {
|
2024-10-03 08:37:11 -04:00
|
|
|
js: ["scripts/prop-general.js", "scripts/prop-trackers.js", "scripts/prop-peers.js", "scripts/prop-webseeds.js", "scripts/prop-files.js"],
|
|
|
|
onload: function() {
|
|
|
|
updatePropertiesPanel = function() {
|
|
|
|
switch (LocalPreferences.get("selected_properties_tab")) {
|
|
|
|
case "propGeneralLink":
|
|
|
|
window.qBittorrent.PropGeneral.updateData();
|
|
|
|
break;
|
|
|
|
case "propTrackersLink":
|
|
|
|
window.qBittorrent.PropTrackers.updateData();
|
|
|
|
break;
|
|
|
|
case "propPeersLink":
|
|
|
|
window.qBittorrent.PropPeers.updateData();
|
|
|
|
break;
|
|
|
|
case "propWebSeedsLink":
|
|
|
|
window.qBittorrent.PropWebseeds.updateData();
|
|
|
|
break;
|
|
|
|
case "propFilesLink":
|
|
|
|
window.qBittorrent.PropFiles.updateData();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
2022-10-18 22:39:32 -04:00
|
|
|
},
|
2024-10-03 08:37:11 -04:00
|
|
|
tabsURL: "views/propertiesToolbar.html",
|
|
|
|
tabsOnload: function() {}, // must be included, otherwise panel won't load properly
|
|
|
|
onContentLoaded: function() {
|
|
|
|
this.panelHeaderCollapseBoxEl.classList.add("invisible");
|
|
|
|
|
|
|
|
const togglePropertiesPanel = () => {
|
|
|
|
this.collapseToggleEl.click();
|
|
|
|
LocalPreferences.set("properties_panel_collapsed", this.isCollapsed.toString());
|
2022-10-18 22:39:32 -04:00
|
|
|
};
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
const selectTab = (tabID) => {
|
|
|
|
const isAlreadySelected = this.panelHeaderEl.getElementById(tabID).classList.contains("selected");
|
|
|
|
if (!isAlreadySelected) {
|
|
|
|
for (const tab of this.panelHeaderEl.getElementById("propertiesTabs").children)
|
|
|
|
tab.classList.toggle("selected", tab.id === tabID);
|
2022-10-18 22:39:32 -04:00
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
const tabContentID = tabID.replace("Link", "");
|
|
|
|
for (const tabContent of this.contentEl.children)
|
|
|
|
tabContent.classList.toggle("invisible", tabContent.id !== tabContentID);
|
2022-10-18 22:39:32 -04:00
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
LocalPreferences.set("selected_properties_tab", tabID);
|
|
|
|
}
|
2022-10-18 22:39:32 -04:00
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
if (isAlreadySelected || this.isCollapsed)
|
|
|
|
togglePropertiesPanel();
|
|
|
|
};
|
2022-10-18 22:39:32 -04:00
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
const lastUsedTab = LocalPreferences.get("selected_properties_tab", "propGeneralLink");
|
|
|
|
selectTab(lastUsedTab);
|
2022-10-18 22:39:32 -04:00
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
const startCollapsed = LocalPreferences.get("properties_panel_collapsed", "false") === "true";
|
|
|
|
if (startCollapsed)
|
|
|
|
togglePropertiesPanel();
|
|
|
|
|
|
|
|
this.panelHeaderContentEl.addEventListener("click", (e) => {
|
|
|
|
const selectedTab = e.target.closest("li");
|
|
|
|
if (!selectedTab)
|
|
|
|
return;
|
|
|
|
|
|
|
|
selectTab(selectedTab.id);
|
2022-10-18 22:39:32 -04:00
|
|
|
updatePropertiesPanel();
|
2024-10-03 08:37:11 -04:00
|
|
|
|
|
|
|
const showFilesFilter = (selectedTab.id === "propFilesLink") && !this.isCollapsed;
|
|
|
|
document.getElementById("torrentFilesFilterToolbar").classList.toggle("invisible", !showFilesFilter);
|
2022-10-18 22:39:32 -04:00
|
|
|
});
|
|
|
|
},
|
2024-10-03 08:37:11 -04:00
|
|
|
column: "mainColumn",
|
2022-10-18 22:39:32 -04:00
|
|
|
height: prop_h
|
|
|
|
});
|
|
|
|
|
|
|
|
// listen for changes to torrentsFilterInput
|
2024-10-03 08:37:11 -04:00
|
|
|
let torrentsFilterInputTimer = -1;
|
|
|
|
$("torrentsFilterInput").addEventListener("input", () => {
|
|
|
|
clearTimeout(torrentsFilterInputTimer);
|
|
|
|
torrentsFilterInputTimer = setTimeout(() => {
|
|
|
|
torrentsFilterInputTimer = -1;
|
|
|
|
torrentsTable.updateTable();
|
|
|
|
}, window.qBittorrent.Misc.FILTER_INPUT_DELAY);
|
2022-10-18 22:39:32 -04:00
|
|
|
});
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
document.getElementById("torrentsFilterToolbar").addEventListener("change", (e) => { torrentsTable.updateTable(); });
|
|
|
|
|
|
|
|
$("transfersTabLink").addEventListener("click", () => { showTransfersTab(); });
|
|
|
|
$("searchTabLink").addEventListener("click", () => { showSearchTab(); });
|
|
|
|
$("rssTabLink").addEventListener("click", () => { showRssTab(); });
|
|
|
|
$("logTabLink").addEventListener("click", () => { showLogTab(); });
|
2022-10-18 22:39:32 -04:00
|
|
|
updateTabDisplay();
|
|
|
|
|
|
|
|
const registerDragAndDrop = () => {
|
2024-10-03 08:37:11 -04:00
|
|
|
$("desktop").addEventListener("dragover", (ev) => {
|
2022-10-18 22:39:32 -04:00
|
|
|
if (ev.preventDefault)
|
|
|
|
ev.preventDefault();
|
|
|
|
});
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
$("desktop").addEventListener("dragenter", (ev) => {
|
2022-10-18 22:39:32 -04:00
|
|
|
if (ev.preventDefault)
|
|
|
|
ev.preventDefault();
|
|
|
|
});
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
$("desktop").addEventListener("drop", (ev) => {
|
2022-10-18 22:39:32 -04:00
|
|
|
if (ev.preventDefault)
|
|
|
|
ev.preventDefault();
|
|
|
|
|
|
|
|
const droppedFiles = ev.dataTransfer.files;
|
|
|
|
|
|
|
|
if (droppedFiles.length > 0) {
|
|
|
|
// dropped files or folders
|
|
|
|
|
|
|
|
// can't handle folder due to cannot put the filelist (from dropped folder)
|
|
|
|
// to <input> `files` field
|
|
|
|
for (const item of ev.dataTransfer.items) {
|
|
|
|
if (item.webkitGetAsEntry().isDirectory)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
const id = "uploadPage";
|
2022-10-18 22:39:32 -04:00
|
|
|
new MochaUI.Window({
|
|
|
|
id: id,
|
2024-10-03 08:37:11 -04:00
|
|
|
icon: "images/qbittorrent-tray.svg",
|
2022-11-30 13:49:48 -05:00
|
|
|
title: "Upload local torrent",
|
2024-10-03 08:37:11 -04:00
|
|
|
loadMethod: "iframe",
|
2022-10-18 22:39:32 -04:00
|
|
|
contentURL: new URI("upload.html").toString(),
|
2024-10-03 08:37:11 -04:00
|
|
|
addClass: "windowFrame", // fixes iframe scrolling on iOS Safari
|
2022-10-18 22:39:32 -04:00
|
|
|
scrollbars: true,
|
|
|
|
maximizable: false,
|
|
|
|
paddingVertical: 0,
|
|
|
|
paddingHorizontal: 0,
|
|
|
|
width: loadWindowWidth(id, 500),
|
|
|
|
height: loadWindowHeight(id, 460),
|
2024-10-03 08:37:11 -04:00
|
|
|
onResize: window.qBittorrent.Misc.createDebounceHandler(500, (e) => {
|
2022-10-18 22:39:32 -04:00
|
|
|
saveWindowSize(id);
|
2024-10-03 08:37:11 -04:00
|
|
|
}),
|
2022-10-18 22:39:32 -04:00
|
|
|
onContentLoaded: () => {
|
2024-10-03 08:37:11 -04:00
|
|
|
const fileInput = $(`${id}_iframe`).contentDocument.getElementById("fileselect");
|
2022-10-18 22:39:32 -04:00
|
|
|
fileInput.files = droppedFiles;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
const droppedText = ev.dataTransfer.getData("text");
|
|
|
|
if (droppedText.length > 0) {
|
|
|
|
// dropped text
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
const urls = droppedText.split("\n")
|
2022-10-18 22:39:32 -04:00
|
|
|
.map((str) => str.trim())
|
|
|
|
.filter((str) => {
|
|
|
|
const lowercaseStr = str.toLowerCase();
|
|
|
|
return lowercaseStr.startsWith("http:")
|
|
|
|
|| lowercaseStr.startsWith("https:")
|
|
|
|
|| lowercaseStr.startsWith("magnet:")
|
2024-10-03 08:37:11 -04:00
|
|
|
|| ((str.length === 40) && !(/[^0-9A-F]/i.test(str))) // v1 hex-encoded SHA-1 info-hash
|
|
|
|
|| ((str.length === 32) && !(/[^2-7A-Z]/i.test(str))); // v1 Base32 encoded SHA-1 info-hash
|
2022-10-18 22:39:32 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
if (urls.length <= 0)
|
|
|
|
return;
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
const id = "downloadPage";
|
|
|
|
const contentURI = new URI("download.html").setData("urls", urls.map(encodeURIComponent).join("|"));
|
2022-10-18 22:39:32 -04:00
|
|
|
new MochaUI.Window({
|
|
|
|
id: id,
|
2024-10-03 08:37:11 -04:00
|
|
|
icon: "images/qbittorrent-tray.svg",
|
2022-11-30 13:49:48 -05:00
|
|
|
title: "Download from URLs",
|
2024-10-03 08:37:11 -04:00
|
|
|
loadMethod: "iframe",
|
2022-10-18 22:39:32 -04:00
|
|
|
contentURL: contentURI.toString(),
|
2024-10-03 08:37:11 -04:00
|
|
|
addClass: "windowFrame", // fixes iframe scrolling on iOS Safari
|
2022-10-18 22:39:32 -04:00
|
|
|
scrollbars: true,
|
|
|
|
maximizable: false,
|
|
|
|
closable: true,
|
|
|
|
paddingVertical: 0,
|
|
|
|
paddingHorizontal: 0,
|
|
|
|
width: loadWindowWidth(id, 500),
|
|
|
|
height: loadWindowHeight(id, 600),
|
2024-10-03 08:37:11 -04:00
|
|
|
onResize: window.qBittorrent.Misc.createDebounceHandler(500, (e) => {
|
2022-10-18 22:39:32 -04:00
|
|
|
saveWindowSize(id);
|
2024-10-03 08:37:11 -04:00
|
|
|
})
|
2022-10-18 22:39:32 -04:00
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
registerDragAndDrop();
|
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
new Keyboard({
|
|
|
|
defaultEventType: "keydown",
|
|
|
|
events: {
|
|
|
|
"ctrl+a": function(event) {
|
|
|
|
if ((event.target.nodeName === "INPUT") || (event.target.nodeName === "TEXTAREA"))
|
|
|
|
return;
|
|
|
|
if (event.target.isContentEditable)
|
|
|
|
return;
|
|
|
|
torrentsTable.selectAll();
|
|
|
|
event.preventDefault();
|
|
|
|
},
|
|
|
|
"delete": function(event) {
|
|
|
|
if ((event.target.nodeName === "INPUT") || (event.target.nodeName === "TEXTAREA"))
|
|
|
|
return;
|
|
|
|
if (event.target.isContentEditable)
|
|
|
|
return;
|
|
|
|
deleteFN();
|
|
|
|
event.preventDefault();
|
|
|
|
},
|
|
|
|
"shift+delete": (event) => {
|
|
|
|
if ((event.target.nodeName === "INPUT") || (event.target.nodeName === "TEXTAREA"))
|
|
|
|
return;
|
|
|
|
if (event.target.isContentEditable)
|
|
|
|
return;
|
|
|
|
deleteFN(true);
|
|
|
|
event.preventDefault();
|
2022-10-18 22:39:32 -04:00
|
|
|
}
|
|
|
|
}
|
2024-10-03 08:37:11 -04:00
|
|
|
}).activate();
|
|
|
|
});
|
2022-10-18 22:39:32 -04:00
|
|
|
|
2024-10-03 08:37:11 -04:00
|
|
|
window.addEventListener("load", () => {
|
|
|
|
// fetch various data and store it in memory
|
|
|
|
window.qBittorrent.Cache.buildInfo.init();
|
|
|
|
window.qBittorrent.Cache.preferences.init();
|
|
|
|
window.qBittorrent.Cache.qbtVersion.init();
|
|
|
|
|
|
|
|
// switch to previously used tab
|
|
|
|
const previouslyUsedTab = LocalPreferences.get("selected_window_tab", "transfers");
|
|
|
|
switch (previouslyUsedTab) {
|
|
|
|
case "search":
|
|
|
|
if (window.qBittorrent.Client.isShowSearchEngine())
|
|
|
|
$("searchTabLink").click();
|
|
|
|
break;
|
|
|
|
case "rss":
|
|
|
|
if (window.qBittorrent.Client.isShowRssReader())
|
|
|
|
$("rssTabLink").click();
|
|
|
|
break;
|
|
|
|
case "log":
|
|
|
|
if (window.qBittorrent.Client.isShowLogViewer())
|
|
|
|
$("logTabLink").click();
|
|
|
|
break;
|
|
|
|
case "transfers":
|
|
|
|
$("transfersTabLink").click();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
console.error(`Unexpected 'selected_window_tab' value: ${previouslyUsedTab}`);
|
|
|
|
$("transfersTabLink").click();
|
|
|
|
break;
|
|
|
|
};
|
|
|
|
});
|