Service for rTorrent. (#511)

Service for rTorrent.
This commit is contained in:
lindely 2022-10-31 10:09:59 +01:00 committed by GitHub
parent 7edcfe0705
commit 51ba5ff503
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 197 additions and 0 deletions

View File

@ -25,6 +25,7 @@ within Homer:
- [Mealie](#mealie) - [Mealie](#mealie)
- [Healthchecks](#healthchecks) - [Healthchecks](#healthchecks)
- [Proxmox](#proxmox) - [Proxmox](#proxmox)
- [rTorrent](#rtorrent)
- [qBittorrent](#qbittorrent) - [qBittorrent](#qbittorrent)
If you experiencing any issue, please have a look to the [troubleshooting](troubleshooting.md) page. If you experiencing any issue, please have a look to the [troubleshooting](troubleshooting.md) page.
@ -249,6 +250,27 @@ Two lines are needed in the config.yml :
The url must be the root url of the Healthchecks application. The url must be the root url of the Healthchecks application.
The Healthchecks API key can be found in Settings > API Access > API key (read-only). The key is needed to access Healthchecks API. The Healthchecks API key can be found in Settings > API Access > API key (read-only). The key is needed to access Healthchecks API.
## rTorrent
This service displays the global upload and download rates, as well as the number of torrents
listed in rTorrent. The service communicates with the rTorrent XML-RPC interface which needs
to be accessible from the browser. Please consult
[the instructions](https://github.com/rakshasa/rtorrent-doc/blob/master/RPC-Setup-XMLRPC.md)
for setting up rTorrent and make sure the correct CORS-settings are applied. Examples for various
servers can be found at https://enable-cors.org/server.html.
```yaml
- name: "rTorrent"
logo: "assets/tools/sample.png"
url: "http://192.168.0.151" # Your rTorrent web UI, f.e. ruTorrent or Flood.
xmlrpc: "http://192.168.0.151:8081" # Reverse proxy for rTorrent's XML-RPC.
type: "Rtorrent"
rateInterval: 5000 # Interval for updating the download and upload rates.
torrentInterval: 60000 # Interval for updating the torrent count.
username: "username" # Username for logging into rTorrent (if applicable).
password: "password" # Password for logging into rTorrent (if applicable).
## Proxmox ## Proxmox
This service displays status information of a Proxmox node (VMs running and disk, memory and cpu used). It uses the proxmox API and [API Tokens](https://pve.proxmox.com/pve-docs/pveum-plain.html) for authorization so you need to generate one to set in the yaml config. You can set it up in Proxmox under Permissions > API Tokens. You also need to know the realm the user of the API Token is assigned to (by default pam). This service displays status information of a Proxmox node (VMs running and disk, memory and cpu used). It uses the proxmox API and [API Tokens](https://pve.proxmox.com/pve-docs/pveum-plain.html) for authorization so you need to generate one to set in the yaml config. You can set it up in Proxmox under Permissions > API Tokens. You also need to know the realm the user of the API Token is assigned to (by default pam).

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<params>
<param><value><array><data>
<value><string>2BAC78C9E10D82415142E57D24601F2FD8927816</string></value>
<value><string>8BB10DB9EA239106D4907601C342ABBA29BE4391</string></value>
<value><string>2790CE71493BE7083929D5A1CE9CFD6B8394F224</string></value>
</data></array></value></param>
</params>
</methodResponse>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<params>
<param><value><i8>149279</i8></value></param>
</params>
</methodResponse>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<params>
<param><value><i8>45616</i8></value></param>
</params>
</methodResponse>

View File

@ -0,0 +1,153 @@
<template>
<Generic :item="item">
<template #content>
<p class="title is-4">{{ item.name }}</p>
<p class="subtitle is-6">
<span v-if="error" class="error">An error has occurred.</span>
<template v-else>
<span class="down">
<i class="fas fa-download"></i> {{ downRate }}
</span>
<span class="up">
<i class="fas fa-upload"></i> {{ upRate }}
</span>
</template>
</p>
</template>
<template #indicator>
<span v-if="!error" class="count">{{ count }}
<template v-if="count === 1">torrent</template>
<template v-else>torrents</template>
</span>
</template>
</Generic>
</template>
<script>
import Generic from './Generic.vue';
// Units to add to download and upload rates.
const units = ['B', 'kiB', 'MiB', 'GiB'];
// Take the rate in bytes and keep dividing it by 1k until the lowest
// value for which we have a unit is determined. Return the value with
// up to two decimals as a string and unit/s appended.
const displayRate = (rate) => {
let i = 0;
while (rate > 1000 && i < units.length) {
rate /= 1000;
i++;
}
return Intl.NumberFormat(undefined, {maximumFractionDigits: 2})
.format(rate || 0) + ` ${units[i]}/s`;
}
export default {
name: 'rTorrent',
props: {item: Object},
components: {Generic},
// Properties for download, upload, torrent count and errors.
data: () => ({dl: null, ul: null, count: null, error: null}),
// Computed properties for the rate labels.
computed: {
downRate: function() {
return displayRate(this.dl);
},
upRate: function() {
return displayRate(this.ul);
},
},
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);
}
// Fetch the initial values.
this.fetchRates();
this.fetchCount();
},
methods: {
// Perform two calls to the XML-RPC service and fetch download
// and upload rates. Values are saved to the `ul` and `dl`
// properties.
fetchRates: async function() {
this.getRate('throttle.global_up.rate')
.then((ul) => this.ul = ul)
.catch(() => this.error = true);
this.getRate('throttle.global_down.rate')
.then((dl) => this.dl = dl)
.catch(() => this.error = true);
},
// Perform a call to the XML-RPC service to fetch the number of
// torrents.
fetchCount: async function() {
this.getCount().catch(() => this.error = true);
},
// Fetch a numeric value from the XML-RPC service by requesting
// the specified method name and parsing the XML. The response
// is expected to adhere to the structure of a single numeric
// value.
getRate: async function(methodName) {
return this.getXml(methodName)
.then((xml) => parseInt(xml.getElementsByTagName('value')[0].firstChild.textContent, 10));
},
// Fetch the numer of torrents by requesting the download list
// and counting the number of entries therein.
getCount: async function() {
return this.getXml('download_list')
.then((xml) => {
const arrayEl = xml.getElementsByTagName('array');
this.count = arrayEl ? arrayEl[0].getElementsByTagName('value').length : 0;
});
},
// Perform a call to the XML-RPC service and parse the response
// as XML, which is then returned.
getXml: async function(methodName) {
const headers = {'Content-Type': 'text/xml'};
if (this.item.username && this.item.password) {
headers['Authorization'] = `${this.item.username}:${this.item.password}`;
}
return fetch(`${this.item.xmlrpc.replace(/\/$/, '')}/RPC2`, {
method: 'POST',
headers,
body: `<methodCall><methodName>${methodName}</methodName></methodCall>`
})
.then((response) => {
if (!response.ok) {
throw Error(response.statusText);
}
return response.text();
})
.then((text) => Promise.resolve(new DOMParser().parseFromString(text, 'text/xml')));
}
}
}
</script>
<style scoped lang="scss">
.error {
color: #e51111 !important;
}
.down {
margin-right: 1em;
}
.count {
color: var(--text);
font-size: 0.8em;
}
</style>