From cf0dcb476996e8b86afc8b103bfa6de58ae9275e Mon Sep 17 00:00:00 2001 From: Bastien Wirtz Date: Thu, 7 Aug 2025 20:11:22 +0200 Subject: [PATCH 01/12] feat(auto-refresh): centralized auto refresh System --- src/App.vue | 5 + src/components/services/DockerSocketProxy.vue | 8 +- src/components/services/FreshRSS.vue | 6 +- src/components/services/Glances.vue | 8 +- src/components/services/Immich.vue | 8 +- src/components/services/Lidarr.vue | 9 +- src/components/services/PiAlert.vue | 8 +- src/components/services/PiHole.vue | 33 +---- src/components/services/Ping.vue | 7 +- src/components/services/Plex.vue | 8 +- src/components/services/Prowlarr.vue | 9 +- src/components/services/Radarr.vue | 9 +- src/components/services/Rtorrent.vue | 22 ++- src/components/services/SABnzbd.vue | 7 +- src/components/services/Scrutiny.vue | 8 +- src/components/services/Sonarr.vue | 9 +- src/components/services/Tautulli.vue | 7 +- src/components/services/Tdarr.vue | 7 +- src/components/services/qBittorrent.vue | 19 ++- src/mixins/service.js | 96 ++++++++++++- src/utils/updateScheduler.js | 131 ++++++++++++++++++ 21 files changed, 310 insertions(+), 114 deletions(-) create mode 100644 src/utils/updateScheduler.js diff --git a/src/App.vue b/src/App.vue index 7a120973b..2e0e5d019 100644 --- a/src/App.vue +++ b/src/App.vue @@ -130,6 +130,11 @@ export default { DarkMode, DynamicTheme, }, + provide() { + return { + config: () => this.config, + }; + }, data: function () { return { loaded: false, diff --git a/src/components/services/DockerSocketProxy.vue b/src/components/services/DockerSocketProxy.vue index 444f11aa0..345c7ed01 100644 --- a/src/components/services/DockerSocketProxy.vue +++ b/src/components/services/DockerSocketProxy.vue @@ -48,10 +48,10 @@ export default { }; }, created: function () { - const checkInterval = parseInt(this.item.checkInterval, 10) || 0; - if (checkInterval > 0) { - setInterval(() => this.fetchData(), checkInterval); - } + // Set up auto-update method for the scheduler + this.autoUpdateMethod = this.fetchData; + + // Initial data fetch this.fetchData(); }, methods: { diff --git a/src/components/services/FreshRSS.vue b/src/components/services/FreshRSS.vue index fa49fe646..5947befef 100644 --- a/src/components/services/FreshRSS.vue +++ b/src/components/services/FreshRSS.vue @@ -40,10 +40,10 @@ export default { }; }, created: function () { - const updateInterval = parseInt(this.item.updateInterval, 10) || 0; - if (updateInterval > 0) - setInterval(() => this.fetchConfig(), updateInterval); + // Set up auto-update method for the scheduler + this.autoUpdateMethod = this.fetchConfig; + // Initial data fetch this.fetchConfig(); }, methods: { diff --git a/src/components/services/Glances.vue b/src/components/services/Glances.vue index 0630d88fc..327ae6c3a 100644 --- a/src/components/services/Glances.vue +++ b/src/components/services/Glances.vue @@ -29,10 +29,10 @@ export default { error: null, }), created() { - const updateInterval = parseInt(this.item.updateInterval, 10) || 0; - if (updateInterval > 0) { - setInterval(() => this.fetchStat(), updateInterval); - } + // Set up auto-update method for the scheduler + this.autoUpdateMethod = this.fetchStat; + + // Initial data fetch this.fetchStat(); }, methods: { diff --git a/src/components/services/Immich.vue b/src/components/services/Immich.vue index 19675886d..390dd81f0 100644 --- a/src/components/services/Immich.vue +++ b/src/components/services/Immich.vue @@ -62,10 +62,10 @@ export default { }, }, created: function () { - const updateInterval = parseInt(this.item.updateInterval, 10) || 0; - if (updateInterval > 0) { - setInterval(() => this.fetchConfig(), updateInterval); - } + // Set up auto-update method for the scheduler + this.autoUpdateMethod = this.fetchConfig; + + // Initial data fetch this.fetchConfig(); }, methods: { diff --git a/src/components/services/Lidarr.vue b/src/components/services/Lidarr.vue index 970d2381a..184633886 100644 --- a/src/components/services/Lidarr.vue +++ b/src/components/services/Lidarr.vue @@ -43,12 +43,11 @@ export default { serverError: false, }; }, - created: function () { - const checkInterval = parseInt(this.item.checkInterval, 10) || 0; - if (checkInterval > 0) { - setInterval(() => this.fetchConfig(), checkInterval); - } + created() { + // Set up auto-update method for the scheduler + this.autoUpdateMethod = this.fetchConfig; + // Initial data fetch this.fetchConfig(); }, methods: { diff --git a/src/components/services/PiAlert.vue b/src/components/services/PiAlert.vue index 63bfebc87..ba231eefa 100644 --- a/src/components/services/PiAlert.vue +++ b/src/components/services/PiAlert.vue @@ -44,10 +44,10 @@ export default { }; }, created() { - const updateInterval = parseInt(this.item.updateInterval, 10) || 0; - if (updateInterval > 0) { - setInterval(() => this.fetchStatus(), updateInterval); - } + // Set up auto-update method for the scheduler + this.autoUpdateMethod = this.fetchStatus; + + // Initial data fetch this.fetchStatus(); }, methods: { diff --git a/src/components/services/PiHole.vue b/src/components/services/PiHole.vue index 0d9dd782e..7f9a9c740 100644 --- a/src/components/services/PiHole.vue +++ b/src/components/services/PiHole.vue @@ -39,8 +39,6 @@ export default { retryCount: 0, maxRetries: 3, retryDelay: 5000, - localCheckInterval: 1000, // Default value or a fallback - pollInterval: null, }), computed: { percentage: function () { @@ -57,18 +55,16 @@ export default { }, created() { if (parseInt(this.item.apiVersion, 10) === 6) { - // Set the interval to the checkInterval or default to 5 minutes - this.localCheckInterval = parseInt(this.item.checkInterval, 10) || 300000; this.loadCachedSession(); - this.startStatusPolling(); + + // Set up auto-update method for the scheduler + this.autoUpdateMethod = this.fetchStatus; } else { - this.fetchStatus_v5(); - } - }, - beforeUnmount() { - if (parseInt(this.item.apiVersion, 10) === 6) { - this.stopStatusPolling(); + // Set up auto-update method for the scheduler + this.autoUpdateMethod = this.fetchStatus_v5(); } + // Initial data fetch + this.autoUpdateMethod(); }, methods: { handleError: function (error, status) { @@ -76,21 +72,6 @@ export default { this.subtitle = error; this.status = status; }, - startStatusPolling: function () { - this.fetchStatus(); - if (this.localCheckInterval < 1000) { - this.localCheckInterval = 1000; - } - this.pollInterval = setInterval( - this.fetchStatus, - this.localCheckInterval, - ); - }, - stopStatusPolling: function () { - if (this.pollInterval) { - clearInterval(this.pollInterval); - } - }, loadCachedSession: function () { try { const cachedSession = localStorage.getItem( diff --git a/src/components/services/Ping.vue b/src/components/services/Ping.vue index 88b03c7e7..46b536254 100644 --- a/src/components/services/Ping.vue +++ b/src/components/services/Ping.vue @@ -41,11 +41,10 @@ export default { }, }, created() { - const updateInterval = parseInt(this.item.updateInterval, 10) || 0; - if (updateInterval > 0) { - setInterval(this.fetchStatus, updateInterval); - } + // Set up auto-update method for the scheduler + this.autoUpdateMethod = this.fetchStatus; + // Initial data fetch this.fetchStatus(); }, methods: { diff --git a/src/components/services/Plex.vue b/src/components/services/Plex.vue index f65ff180d..135b0e0b4 100644 --- a/src/components/services/Plex.vue +++ b/src/components/services/Plex.vue @@ -52,10 +52,10 @@ export default { }; }, created: function () { - const checkInterval = parseInt(this.item.checkInterval, 10) || 0; - if (checkInterval > 0) { - setInterval(() => this.fetchData(), checkInterval); - } + // Set up auto-update method for the scheduler + this.autoUpdateMethod = this.fetchData; + + // Initial data fetch this.fetchData(); }, methods: { diff --git a/src/components/services/Prowlarr.vue b/src/components/services/Prowlarr.vue index 95890da56..3ea9ef543 100644 --- a/src/components/services/Prowlarr.vue +++ b/src/components/services/Prowlarr.vue @@ -36,12 +36,11 @@ export default { serverError: false, }; }, - created: function () { - const checkInterval = parseInt(this.item.checkInterval, 10) || 0; - if (checkInterval > 0) { - setInterval(() => this.fetchConfig(), checkInterval); - } + created() { + // Set up auto-update method for the scheduler + this.autoUpdateMethod = this.fetchConfig; + // Initial data fetch this.fetchConfig(); }, methods: { diff --git a/src/components/services/Radarr.vue b/src/components/services/Radarr.vue index 77a3af974..014f731ca 100644 --- a/src/components/services/Radarr.vue +++ b/src/components/services/Radarr.vue @@ -51,12 +51,11 @@ export default { return this.item.legacyApi ? LEGACY_API : V3_API; }, }, - created: function () { - const checkInterval = parseInt(this.item.checkInterval, 10) || 0; - if (checkInterval > 0) { - setInterval(() => this.fetchConfig(), checkInterval); - } + created() { + // Set up auto-update method for the scheduler + this.autoUpdateMethod = this.fetchConfig; + // Initial data fetch this.fetchConfig(); }, methods: { diff --git a/src/components/services/Rtorrent.vue b/src/components/services/Rtorrent.vue index 7830a6858..5c0be86be 100644 --- a/src/components/services/Rtorrent.vue +++ b/src/components/services/Rtorrent.vue @@ -59,24 +59,18 @@ export default { }, }, created() { - // Set intervals if configured so the rates and/or torrent count - // will be updated. - const rateInterval = parseInt(this.item.rateInterval, 10) || 0; - const torrentInterval = parseInt(this.item.torrentInterval, 10) || 0; - - if (rateInterval > 0) { - setInterval(() => this.fetchRates(), rateInterval); - } - - if (torrentInterval > 0) { - setInterval(() => this.fetchCount(), torrentInterval); - } + // Set up auto-update method for the scheduler + this.autoUpdateMethod = this.fetchAllData; // Fetch the initial values. - this.fetchRates(); - this.fetchCount(); + this.fetchAllData(); }, methods: { + // Combined method for scheduler - fetches both rates and count + fetchAllData: async function () { + this.fetchRates(); + this.fetchCount(); + }, // Perform two calls to the XML-RPC service and fetch download // and upload rates. Values are saved to the `ul` and `dl` // properties. diff --git a/src/components/services/SABnzbd.vue b/src/components/services/SABnzbd.vue index 417968a23..1223fa153 100644 --- a/src/components/services/SABnzbd.vue +++ b/src/components/services/SABnzbd.vue @@ -80,11 +80,10 @@ export default { }, }, created() { - const downloadInterval = parseInt(this.item.downloadInterval, 10) || 0; - if (downloadInterval > 0) { - setInterval(() => this.fetchStatus(), downloadInterval); - } + // Set up auto-update method for the scheduler + this.autoUpdateMethod = this.fetchStatus; + // Initial data fetch this.fetchStatus(); }, methods: { diff --git a/src/components/services/Scrutiny.vue b/src/components/services/Scrutiny.vue index e01bad28e..6a64285b1 100644 --- a/src/components/services/Scrutiny.vue +++ b/src/components/services/Scrutiny.vue @@ -40,10 +40,10 @@ export default { }; }, created: function () { - const updateInterval = parseInt(this.item.updateInterval, 10) || 0; - if (updateInterval > 0) { - setInterval(() => this.fetchSummary(), updateInterval); - } + // Set up auto-update method for the scheduler + this.autoUpdateMethod = this.fetchSummary; + + // Initial data fetch this.fetchSummary(); }, methods: { diff --git a/src/components/services/Sonarr.vue b/src/components/services/Sonarr.vue index 3a610d585..69a6671a5 100644 --- a/src/components/services/Sonarr.vue +++ b/src/components/services/Sonarr.vue @@ -52,12 +52,11 @@ export default { return this.item.legacyApi ? LEGACY_API : V3_API; }, }, - created: function () { - const checkInterval = parseInt(this.item.checkInterval, 10) || 0; - if (checkInterval > 0) { - setInterval(() => this.fetchConfig(), checkInterval); - } + created() { + // Set up auto-update method for the scheduler + this.autoUpdateMethod = this.fetchConfig; + // Initial data fetch this.fetchConfig(); }, methods: { diff --git a/src/components/services/Tautulli.vue b/src/components/services/Tautulli.vue index 77e781d45..e7bf94702 100644 --- a/src/components/services/Tautulli.vue +++ b/src/components/services/Tautulli.vue @@ -41,11 +41,10 @@ export default { }, }, created() { - const checkInterval = parseInt(this.item.checkInterval, 10) || 0; - if (checkInterval > 0) { - setInterval(() => this.fetchStatus(), checkInterval); - } + // Set up auto-update method for the scheduler + this.autoUpdateMethod = this.fetchStatus; + // Initial data fetch this.fetchStatus(); }, methods: { diff --git a/src/components/services/Tdarr.vue b/src/components/services/Tdarr.vue index bc5c892f0..dd821ca8f 100644 --- a/src/components/services/Tdarr.vue +++ b/src/components/services/Tdarr.vue @@ -54,11 +54,10 @@ export default { }, }, created() { - const checkInterval = parseInt(this.item.checkInterval, 10) || 0; - if (checkInterval > 0) { - setInterval(() => this.fetchStatus(), checkInterval); - } + // Set up auto-update method for the scheduler + this.autoUpdateMethod = this.fetchStatus; + // Initial data fetch this.fetchStatus(); }, methods: { diff --git a/src/components/services/qBittorrent.vue b/src/components/services/qBittorrent.vue index 829e85051..182958895 100644 --- a/src/components/services/qBittorrent.vue +++ b/src/components/services/qBittorrent.vue @@ -61,19 +61,18 @@ export default { }, }, created() { - const rateInterval = parseInt(this.item.rateInterval, 10) || 0; - const torrentInterval = parseInt(this.item.torrentInterval, 10) || 0; - if (rateInterval > 0) { - setInterval(() => this.getRate(), rateInterval); - } - if (torrentInterval > 0) { - setInterval(() => this.fetchCount(), torrentInterval); - } + // Set up auto-update method for the scheduler + this.autoUpdateMethod = this.fetchAllData; - this.getRate(); - this.fetchCount(); + // Fetch initial values + this.fetchAllData(); }, methods: { + // Combined method for scheduler - fetches both rates and count + fetchAllData: async function () { + this.getRate(); + this.fetchCount(); + }, fetchCount: async function () { try { const body = await this.fetch("/api/v2/torrents/info"); diff --git a/src/mixins/service.js b/src/mixins/service.js index 6d5c25315..aae6985e2 100644 --- a/src/mixins/service.js +++ b/src/mixins/service.js @@ -1,15 +1,35 @@ +import updateScheduler from "@/utils/updateScheduler.js"; + export default { props: { proxy: Object, }, + inject: { + // Inject global config from parent components + config: { + default: () => ({}), + }, + }, + computed: { + globalConfig() { + return this.config() || {}; + }, + }, created: function () { - // custom service often consume info from an API using the item link (url) as a base url, + // Custom service often consume info from an API using the item link (url) as a base url, // but sometimes the base url is different. An optional alternative URL can be provided with the "endpoint" key. this.endpoint = this.item.endpoint || this.item.url; if (this.endpoint && this.endpoint.endsWith("/")) { this.endpoint = this.endpoint.slice(0, -1); } + + // Initialize auto-update if configured + this.initAutoUpdate(); + }, + beforeUnmount() { + // Clean up auto-update registration + updateScheduler.unregister(this); }, methods: { fetch: function (path, init, json = true) { @@ -62,5 +82,79 @@ export default { return json ? response.json() : response.text(); }); }, + initAutoUpdate: function () { + // Check if component has defined an auto-update method and interval + const interval = this.getUpdateInterval(); + if ( + interval > 0 && + this.autoUpdateMethod && + typeof this.autoUpdateMethod === "function" + ) { + updateScheduler.register(this, interval, this.autoUpdateMethod); + } + }, + getUpdateInterval: function () { + // Check if auto-update is explicitly disabled for this service + if (this.item.autoUpdateInterval === false) { + return 0; + } + + // Use service-specific interval if defined + if (this.item.autoUpdateInterval) { + return parseInt(this.item.autoUpdateInterval, 10) || 0; + } + + // Check for deprecated keys and warn users + const deprecatedKeys = [ + "updateInterval", + "checkInterval", + "localCheckInterval", + "downloadInterval", + "rateInterval", + "torrentInterval", + ]; + + for (const key of deprecatedKeys) { + if (this.item[key]) { + console.warn( + `[DEPRECATED] Service "${this.item.name || "unknown"}" uses deprecated config key "${key}". ` + + `Please use "autoUpdateInterval" instead. Support for "${key}" will be removed in a future version.`, + ); + return parseInt(this.item[key], 10) || 0; + } + } + + // Use global auto-update configuration + return this.getGlobalAutoUpdateInterval(); + }, + + getGlobalAutoUpdateInterval: function () { + const globalAutoUpdate = this.globalConfig.autoUpdate; + + // If auto-update is not configured globally, disable + if (!globalAutoUpdate) { + return 0; + } + + // If global auto-update is explicitly disabled + if (globalAutoUpdate.enabled === false) { + return 0; + } + + // If autoUpdate is just a number (simplified config) + if (typeof globalAutoUpdate === "number") { + return globalAutoUpdate; + } + + // If autoUpdate is an object, use defaultInterval + if ( + typeof globalAutoUpdate === "object" && + globalAutoUpdate.defaultInterval + ) { + return parseInt(globalAutoUpdate.defaultInterval, 10) || 0; + } + + return 0; + }, }, }; diff --git a/src/utils/updateScheduler.js b/src/utils/updateScheduler.js new file mode 100644 index 000000000..64e126bba --- /dev/null +++ b/src/utils/updateScheduler.js @@ -0,0 +1,131 @@ +/** + * This module provides a single-timer solution for managing automatic data updates + * across all service components in Homer. Instead of each service component creating + * its own setInterval timer, all components register with this centralized scheduler. + * + */ +class UpdateScheduler { + constructor() { + this.registeredComponents = new Map(); + this.globalTimer = null; + this.tickCount = 0; + this.isRunning = false; + } + + register(component, intervalMs, updateMethod) { + if (!component || !updateMethod || intervalMs <= 0) { + console.warn("UpdateScheduler: Invalid registration parameters"); + return; + } + + const intervalSeconds = Math.floor(intervalMs / 1000); + const componentId = this.generateComponentId(component); + + this.registeredComponents.set(componentId, { + component, + interval: intervalSeconds, + method: updateMethod, + lastUpdate: 0, + }); + + this.startGlobalTimer(); + console.log( + `UpdateScheduler: Registered component with ${intervalSeconds}s interval`, + ); + } + + unregister(component) { + const componentId = this.generateComponentId(component); + const removed = this.registeredComponents.delete(componentId); + + if (removed) { + console.log("UpdateScheduler: Unregistered component"); + } + + if (this.registeredComponents.size === 0) { + this.stopGlobalTimer(); + } + } + + generateComponentId(component) { + // Use component's unique identifier or Vue instance uid + return component._uid || component.$.uid || Symbol("component"); + } + + startGlobalTimer() { + if (!this.globalTimer && !this.isRunning) { + this.isRunning = true; + this.tickCount = 0; + + this.globalTimer = setInterval(() => { + this.tickCount++; + this.processUpdates(); + }, 1000); + + console.log("UpdateScheduler: Global timer started"); + } + } + + stopGlobalTimer() { + if (this.globalTimer) { + clearInterval(this.globalTimer); + this.globalTimer = null; + this.isRunning = false; + this.tickCount = 0; + console.log("UpdateScheduler: Global timer stopped"); + } + } + + processUpdates() { + for (const [, config] of this.registeredComponents) { + try { + if (this.tickCount - config.lastUpdate >= config.interval) { + config.method.call(config.component); + config.lastUpdate = this.tickCount; + } + } catch (error) { + console.error("UpdateScheduler: Error during component update:", error); + } + } + } + + pause() { + if (this.globalTimer) { + clearInterval(this.globalTimer); + this.globalTimer = null; + this.isRunning = false; + console.log("UpdateScheduler: Paused"); + } + } + + resume() { + if (!this.globalTimer && this.registeredComponents.size > 0) { + this.startGlobalTimer(); + console.log("UpdateScheduler: Resumed"); + } + } + + getStatus() { + return { + isRunning: this.isRunning, + registeredCount: this.registeredComponents.size, + tickCount: this.tickCount, + }; + } +} + +// Create and export global singleton instance +const updateScheduler = new UpdateScheduler(); + +// Pause updates when tab is hidden (power saving) +if (typeof document !== "undefined") { + document.addEventListener("visibilitychange", () => { + if (document.hidden) { + updateScheduler.pause(); + } else { + updateScheduler.resume(); + } + }); +} + +export default updateScheduler; From fdddbfd1ec0c53171b86d955b9e9933e166397aa Mon Sep 17 00:00:00 2001 From: "Joris W. van Rijn" Date: Tue, 7 Oct 2025 14:08:57 +0200 Subject: [PATCH 02/12] feat(auto-refresh): add Transmission and docs --- docs/customservices.md | 29 ++++++++++++------------ src/components/services/Transmission.vue | 11 +++------ src/mixins/service.js | 1 + 3 files changed, 18 insertions(+), 23 deletions(-) diff --git a/docs/customservices.md b/docs/customservices.md index a244a8d45..6a6891558 100644 --- a/docs/customservices.md +++ b/docs/customservices.md @@ -83,6 +83,7 @@ Available services are located in `src/components/`: endpoint: https://my-service-api.url # Optional: alternative base URL used to fetch service data when necessary. useCredentials: false # Optional: Override global proxy.useCredentials configuration. headers: # Optional: Override global proxy.headers configuration. + autoUpdateInterval: # Optional: Time in ms. Some services can periodically fetch data (see below) ``` If a subtitle is provided, (using the `subtitle` configuration key), **it will override (hide)** any custom information displayed on the subtitle line by the custom integration. @@ -159,10 +160,10 @@ The `libraryType` configuration let you choose which stats to show. Displays unread article count and total subscriptions from your FreshRSS server. ```yaml -- name: "FreshRSS" +- name: "FreshRSS" type: "FreshRSS" url: https://my-service.url - updateInterval: 5000 # (Optional) Interval (in ms) for updating the stats + autoUpdateInterval: 5000 # (Optional) Interval (in ms) for updating the stats username: "<---your-username--->" password: "<---your-password--->" ``` @@ -185,7 +186,7 @@ Optionally, the results can be filtered to only include jobs in the defined grou The status can be checked regularly by defining an update Interval in ms: ```yaml - updateInterval: 5000 + autoUpdateInterval: 5000 ``` The average times can be hidden (saves their calculation also) by setting the following: @@ -335,7 +336,7 @@ Two lines are needed in the `config.yml`: type: "Lidarr" # "Lidarr" "Prowlarr", "Radarr" or "Sonarr" logo: "assets/tools/sample.png" url: https://my-service.url - checkInterval: 5000 # (Optional) Interval (in ms) for updating the status + autoUpdateInterval: 5000 # (Optional) Interval (in ms) for updating the status apikey: "<---insert-api-key-here--->" ``` @@ -551,7 +552,7 @@ Displays stats from your PiAlert server. type: "PiAlert" logo: "assets/tools/sample.png" url: https://my-service.url - updateInterval: 5000 # (Optional) Interval (in ms) for updating the stats + autoUpdateInterval: 5000 # (Optional) Interval (in ms) for updating the stats ``` ## PiHole @@ -566,7 +567,7 @@ Displays info about your local PiHole instance right on your Homer dashboard. # endpoint: "https://my-service-api.url" # optional, For v6 API, this is the base URL used to fetch Pi-hole data overwriting the url apikey: "<---insert-api-key-here--->" # optional, needed if web interface is password protected apiVersion: 5 # optional, defaults to 5. Use 6 if your PiHole instance uses API v6 - checkInterval: 3000 # optional, defaults to 300000. interval in ms to check Pi-hole status + autoUpdateInterval: 3000 # optional, defaults to 300000. interval in ms to check Pi-hole status ``` **API Key**: Required only if Pi-hole web interface is password protected. Go to **Settings > API/Web Interface > Show API token** @@ -682,8 +683,7 @@ for setting up qBittorrent. type: "qBittorrent" logo: "assets/tools/sample.png" url: https://my-service.url # Your rTorrent web UI, f.e. ruTorrent or Flood. - rateInterval: 2000 # Interval for updating the download and upload rates. - torrentInterval: 5000 # Interval for updating the torrent count. + autoUpdateInterval: 2000 # Interval for updating the download, upload rates & torrent count ``` ## rTorrent @@ -700,8 +700,7 @@ for setting up rTorrent. logo: "assets/tools/sample.png" url: "https://my-service.url" # Your rTorrent web UI, f.e. ruTorrent or Flood. xmlrpc: "https://my-service.url:port" # Reverse proxy for rTorrent's XML-RPC. - rateInterval: 5000 # Interval for updating the download and upload rates. - torrentInterval: 60000 # Interval for updating the torrent count. + autoUpdateInterval: 5000 # Interval for updating the download, upload rates & torrent count. username: "username" # Username for logging into rTorrent (if applicable). password: "password" # Password for logging into rTorrent (if applicable). ``` @@ -716,7 +715,7 @@ Displays the number of currently active downloads on your SABnzbd instance. logo: "assets/tools/sample.png" url: https://my-service.url apikey: "<---insert-api-key-here--->" - downloadInterval: 5000 # (Optional) Interval (in ms) for updating the download count + autoUpdateInterval: 5000 # (Optional) Interval (in ms) for updating the download count ``` **API Key**: An API key is required, and can be obtained from the "Config" > "General" section of the SABnzbd config in the web UI. @@ -730,7 +729,7 @@ Displays info about the total number of disk passed and failed S.M.A.R.T and scr type: "Scrutiny" logo: "assets/tools/sample.png" url: https://my-service.url - updateInterval: 5000 # (Optional) Interval (in ms) for updating the status + autoUpdateInterval: 5000 # (Optional) Interval (in ms) for updating the status ``` ## SpeedtestTracker @@ -753,7 +752,7 @@ Displays the number of currently active streams on you Plex instance. type: "Tautulli" logo: "assets/tools/sample.png" url: https://my-service.url - checkInterval: 5000 # (Optional) Interval (in ms) for updating the status + autoUpdateInterval: 5000 # (Optional) Interval (in ms) for updating the status apikey: "<---insert-api-key-here--->" ``` @@ -781,7 +780,7 @@ Displays the number of currently queued items for transcoding on your Tdarr inst type: "Tdarr" logo: "assets/tools/sample.png" url: https://my-service.url - checkInterval: 5000 # (Optional) Interval (in ms) for updating the queue & error counts + autoUpdateInterval: 5000 # (Optional) Interval (in ms) for updating the queue & error counts ``` ## Traefik @@ -809,7 +808,7 @@ The service communicates with the Transmission RPC interface which needs to be a url: "http://192.168.1.2:9091" # Your Transmission web interface URL type: "Transmission" auth: "username:password" # Optional: HTTP Basic Auth - interval: 5000 # Optional: Interval for refreshing data (ms) + autoUpdateInterval: 5000 # Optional: Interval for refreshing data (ms) target: "_blank" # Optional: HTML a tag target attribute ``` diff --git a/src/components/services/Transmission.vue b/src/components/services/Transmission.vue index 802c4f38c..f6ce4dd75 100644 --- a/src/components/services/Transmission.vue +++ b/src/components/services/Transmission.vue @@ -18,8 +18,7 @@