aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorShagon94 <Shagon94@gmail.com>2022-10-30 18:32:51 +0100
committerGitHub <noreply@github.com>2022-10-30 10:32:51 -0700
commitcfd31b86b5a71d059dd9b6f24f0df5b20ac9c0ca (patch)
treee7df4c2311358aeb85e6bf52e0d4a56b06f3bf4c
parentac5f04f058344be4eb61bcc8684771973f18bc71 (diff)
downloadhomer-cfd31b86b5a71d059dd9b6f24f0df5b20ac9c0ca.tar.gz
homer-cfd31b86b5a71d059dd9b6f24f0df5b20ac9c0ca.tar.zst
homer-cfd31b86b5a71d059dd9b6f24f0df5b20ac9c0ca.zip
qBittorrent service (#540)
qBittorrent service
-rw-r--r--docs/customservices.md56
-rw-r--r--dummy-data/README.md13
-rw-r--r--dummy-data/qBittorrent/api/v2/torrents/info53
-rw-r--r--dummy-data/qBittorrent/api/v2/transfer/info10
-rw-r--r--src/components/services/qBittorrent.vue120
5 files changed, 229 insertions, 23 deletions
diff --git a/docs/customservices.md b/docs/customservices.md
index 3c4f5ad..e84afdb 100644
--- a/docs/customservices.md
+++ b/docs/customservices.md
@@ -7,24 +7,27 @@ if your homer instance is secured behind some form of authentication or access r
7 7
8Available services are in `src/components/`. Here is an overview of all custom services that are available 8Available services are in `src/components/`. Here is an overview of all custom services that are available
9within Homer: 9within Homer:
10+ [PiHole](#pihole)
11+ [OpenWeatherMap](#openweathermap)
12+ [Medusa](#medusa)
13+ [Lidarr, Prowlarr, Sonarr and Radarr](#lidarr-prowlarr-sonarr-and-radarr)
14+ [PaperlessNG](#paperlessng)
15+ [Ping](#ping)
16+ [Prometheus](#prometheus)
17+ [AdGuard Home](#adguard-home)
18+ [Portainer](#portainer)
19+ [Emby / Jellyfin](#emby--jellyfin)
20+ [Uptime Kuma](#uptime-kuma)
21+ [Tautulli](#tautulli)
22+ [Mealie](#mealie)
23+ [Healthchecks](#healthchecks)
24+ [Proxmox](#proxmox)
25 10
26If you experiencing any issue, please have a look to the [troubleshooting](troubleshooting.md) page. 11- [Custom Services](#custom-services)
12 - [Common options](#common-options)
13 - [PiHole](#pihole)
14 - [OpenWeatherMap](#openweathermap)
15 - [Medusa](#medusa)
16 - [Lidarr, Prowlarr, Sonarr and Radarr](#lidarr-prowlarr-sonarr-and-radarr)
17 - [PaperlessNG](#paperlessng)
18 - [Ping](#ping)
19 - [Prometheus](#prometheus)
20 - [AdGuard Home](#adguard-home)
21 - [Portainer](#portainer)
22 - [Emby / Jellyfin](#emby--jellyfin)
23 - [Uptime Kuma](#uptime-kuma)
24 - [Tautulli](#tautulli)
25 - [Mealie](#mealie)
26 - [Healthchecks](#healthchecks)
27 - [Proxmox](#proxmox)
28 - [qBittorrent](#qbittorrent)
27 29
30If you experiencing any issue, please have a look to the [troubleshooting](troubleshooting.md) page.
28 31
29## Common options 32## Common options
30 33
@@ -272,4 +275,23 @@ Configuration example:
272 warning_value: 50 275 warning_value: 50
273 danger_value: 80 276 danger_value: 80
274 api_token: "PVEAPIToken=root@pam!your-api-token-name=your-api-token-key" 277 api_token: "PVEAPIToken=root@pam!your-api-token-name=your-api-token-key"
275``` \ No newline at end of file 278```
279
280## qBittorrent
281
282This service displays the global upload and download rates, as well as the number of torrents
283listed. The service communicates with the qBittorrent API interface which needs
284to be accessible from the browser. Please consult
285[the instructions](https://github.com/qbittorrent/qBittorrent/pull/12579)
286for setting up qBittorrent and make sure the correct CORS-settings are applied. Examples for various
287servers can be found at [enable-cors.org](https://enable-cors.org/server.html).
288
289```yaml
290- name: "qBittorrent"
291 logo: "assets/tools/sample.png"
292 url: "http://192.168.1.2:8080" # Your rTorrent web UI, f.e. ruTorrent or Flood.
293 type: "qBittorrent"
294 rateInterval: 2000 # Interval for updating the download and upload rates.
295 torrentInterval: 5000 # Interval for updating the torrent count.
296 target: "_blank" # optional html a tag target attribute
297```
diff --git a/dummy-data/README.md b/dummy-data/README.md
index eeff4ec..6db4712 100644
--- a/dummy-data/README.md
+++ b/dummy-data/README.md
@@ -1,15 +1,16 @@
1# Dummy data 1# Dummy data
2 2
3This directory content makes possible to test custom services cards or create a demo without actually running the service. 3This directory content makes possible to test custom services cards or create a demo without actually running the service.
4The principle is simple: save a sample output of the API used in the service in a static file in this directory. The path must be identical as the service endpoint to be used seamlessly. 4The principle is simple: save a sample output of the API used in the service in a static file in this directory. The path must be identical as the service endpoint to be used seamlessly.
5 5
6## How to add a new services sample: 6## How to add a new services sample
7 7
8- create a directory for your service, and any sub-folder existing in the service api path. 8- create a directory for your service, and any sub-folder existing in the service api path.
9- save the api output in a file named after the service endpoint. 9- save the api output in a file named after the service endpoint.
10 10
11Example: 11Example:
12``` 12
13```sh
13mkdir pihole 14mkdir pihole
14curl http://my-pihole.me/admin/api.php -o pihole/api.php # /admin is omited because for PiHole, the implementation expect it to be in the base url (`url` or `enpoint` property) 15curl http://my-pihole.me/admin/api.php -o pihole/api.php # /admin is omited because for PiHole, the implementation expect it to be in the base url (`url` or `endpoint` property)
15``` \ No newline at end of file 16```
diff --git a/dummy-data/qBittorrent/api/v2/torrents/info b/dummy-data/qBittorrent/api/v2/torrents/info
new file mode 100644
index 0000000..e1bc722
--- /dev/null
+++ b/dummy-data/qBittorrent/api/v2/torrents/info
@@ -0,0 +1,53 @@
1[
2 {
3 "added_on": 1666985518,
4 "amount_left": 0,
5 "auto_tmm": false,
6 "availability": -1,
7 "category": "",
8 "completed": 1474873344,
9 "completion_on": 1666985584,
10 "content_path": "/downloads/ubuntu-22.04.1-live-server-amd64.iso",
11 "dl_limit": -1,
12 "dlspeed": 0,
13 "download_path": "",
14 "downloaded": 1513976240,
15 "downloaded_session": 0,
16 "eta": 8640000,
17 "f_l_piece_prio": false,
18 "force_start": false,
19 "hash": "cf3ea75e2ebbd30e0da6e6e215e2226bf35f2e33",
20 "infohash_v1": "cf3ea75e2ebbd30e0da6e6e215e2226bf35f2e33",
21 "infohash_v2": "",
22 "last_activity": 1666985588,
23 "magnet_uri": "magnet:?xt=urn:btih:cf3ea75e2ebbd30e0da6e6e215e2226bf35f2e33&dn=ubuntu-22.04.1-live-server-amd64.iso&tr=https%3a%2f%2ftorrent.ubuntu.com%2fannounce&tr=https%3a%2f%2fipv6.torrent.ubuntu.com%2fannounce",
24 "max_ratio": 0,
25 "max_seeding_time": -1,
26 "name": "ubuntu-22.04.1-live-server-amd64.iso",
27 "num_complete": 0,
28 "num_incomplete": 583,
29 "num_leechs": 0,
30 "num_seeds": 0,
31 "priority": 0,
32 "progress": 1,
33 "ratio": 1.7163413343924075e-05,
34 "ratio_limit": -2,
35 "save_path": "/downloads/",
36 "seeding_time": 4,
37 "seeding_time_limit": -2,
38 "seen_complete": 1666985584,
39 "seq_dl": false,
40 "size": 1474873344,
41 "state": "pausedUP",
42 "super_seeding": false,
43 "tags": "",
44 "time_active": 69,
45 "total_size": 1474873344,
46 "tracker": "",
47 "trackers_count": 2,
48 "up_limit": -1,
49 "uploaded": 25985,
50 "uploaded_session": 0,
51 "upspeed": 0
52 }
53] \ No newline at end of file
diff --git a/dummy-data/qBittorrent/api/v2/transfer/info b/dummy-data/qBittorrent/api/v2/transfer/info
new file mode 100644
index 0000000..dd7b318
--- /dev/null
+++ b/dummy-data/qBittorrent/api/v2/transfer/info
@@ -0,0 +1,10 @@
1{
2 "connection_status": "connected",
3 "dht_nodes": 318,
4 "dl_info_data": 23481469329,
5 "dl_info_speed": 1234567,
6 "dl_rate_limit": 40960000,
7 "up_info_data": 1788370216,
8 "up_info_speed": 765432,
9 "up_rate_limit": 10547200
10} \ No newline at end of file
diff --git a/src/components/services/qBittorrent.vue b/src/components/services/qBittorrent.vue
new file mode 100644
index 0000000..1f1ef49
--- /dev/null
+++ b/src/components/services/qBittorrent.vue
@@ -0,0 +1,120 @@
1<template>
2 <Generic :item="item">
3 <template #content>
4 <p class="title is-4">{{ item.name }}</p>
5 <p class="subtitle is-6">
6 <span v-if="error" class="error">An error has occurred.</span>
7 <template v-else>
8 <span class="down monospace">
9 <p class="fas fa-download "></p> {{ downRate }}
10 </span>
11 <span class="up monospace">
12 <p class="fas fa-upload"></p> {{ upRate }}
13 </span>
14 </template>
15 </p>
16 </template>
17 <template #indicator>
18 <span v-if="!error" class="count">{{ count }}
19 <template v-if="count === 1">torrent</template>
20 <template v-else>torrents</template>
21 </span>
22 </template>
23 </Generic>
24</template>
25
26<script>
27import service from "@/mixins/service.js";
28import Generic from "./Generic.vue";
29const units = ["B", "KB", "MB", "GB"];
30
31// Take the rate in bytes and keep dividing it by 1k until the lowest
32// value for which we have a unit is determined. Return the value with
33// up to two decimals as a string and unit/s appended.
34const displayRate = (rate) => {
35 let i = 0;
36
37 while (rate > 1000 && i < units.length) {
38 rate /= 1000;
39 i++;
40 }
41 return (
42 Intl.NumberFormat(undefined, { maximumFractionDigits: 2 }).format(
43 rate || 0
44 ) + ` ${units[i]}/s`
45 );
46};
47
48export default {
49 name: "qBittorrent",
50 mixins: [service],
51 props: { item: Object },
52 components: { Generic },
53 data: () => ({ dl: null, ul: null, count: null, error: null }),
54 computed: {
55 downRate: function () {
56 return displayRate(this.dl);
57 },
58 upRate: function () {
59 return displayRate(this.ul);
60 },
61 },
62 created() {
63 const rateInterval = parseInt(this.item.rateInterval, 10) || 0;
64 const torrentInterval = parseInt(this.item.torrentInterval, 10) || 0;
65 if (rateInterval > 0) {
66 setInterval(() => this.getRate(), rateInterval);
67 }
68 if (torrentInterval > 0) {
69 setInterval(() => this.fetchCount(), torrentInterval);
70 }
71
72 this.getRate();
73 this.fetchCount();
74 },
75 methods: {
76 fetchCount: async function () {
77 try {
78 const body = await this.fetch('/api/v2/torrents/info');
79 this.error = false;
80 this.count = body.length;
81 } catch (e) {
82 this.error = true;
83 console.error(e);
84 }
85 },
86 getRate: async function () {
87 try {
88 const body = await this.fetch('/api/v2/transfer/info');
89 this.error = false;
90 this.dl = body.dl_info_speed;
91 this.ul = body.up_info_speed;
92 } catch (e) {
93 this.error = true;
94 console.error(e);
95 }
96 },
97 },
98};
99
100</script>
101
102<style scoped lang="scss">
103.error {
104 color: #e51111 !important;
105}
106
107.down {
108 margin-right: 1em;
109}
110
111.count {
112 color: var(--text);
113 font-size: 0.8em;
114}
115
116.monospace {
117 font-weight: 300;
118 font-family: monospace;
119}
120</style> \ No newline at end of file