🔀 Merge pull request #790 from alucarddelta/FEATURE/widget-sabnzbd

Feature/widget Sabnzbd
This commit is contained in:
Alicia Sykes 2022-07-10 15:20:42 +01:00 committed by GitHub
commit f3bdcef019
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 250 additions and 0 deletions

View File

@ -54,6 +54,7 @@ Dashy has support for displaying dynamic content in the form of widgets. There a
- [Nextcloud System](#nextcloud-system)
- [Nextcloud Stats](#nextcloud-stats)
- [Nextcloud PHP Opcache](#nextcloud-php-opcache-stats)
- [Sabnzbd](#sabnzbd)
- **[System Resource Monitoring](#system-resource-monitoring)**
- [CPU Usage Current](#current-cpu-usage)
- [CPU Usage Per Core](#cpu-usage-per-core)
@ -1790,6 +1791,42 @@ Shows statistics about PHP Opcache perforamnce on your Nextcloud server.
---
### Sabnzbd
Shows queue information regarding your self hosted Sabnzbd server.
<p align="center"><img width="450" src="https://i.ibb.co/5TTSRyM/sabnzbd.png" alt="Sabnzbd" /></p>
##### Options
**Field** | **Type** | **Required** | **Description**
--- | --- | --- | ---
**`sabnzbdUrl`** | `string` | Required | The URL of the Sabnzbd server. No trailing `/`.
**`apiKey`** | `string` | Required | API key for Sabnzbd access. Located under `Config` -> `General` -> `Security` -> `API Key`.
**`hideDetails`** | `boolean` | _Optional_ | Hides extra server queue details.
**`hideQueue`** | `boolean` | _Optional_ | Hides the queue list in an expandable dropdown.
##### Example
```yaml
- type: sabnzbd
options:
sabnzbdUrl: 'https://sabnzbd.example.com'
apiKey: XXXXXXXXXXXXXXXXXX
hideDetails: false
hideQueue: false
```
##### Info
- **CORS**: 🟠 Proxied
- **Auth**: 🟢 Required
- **Price**: 🟢 Free
- **Host**: Self-Hosted (see [Sabnzbd](https://sabnzbd.org/))
- **Privacy**: _See [Sabnzbd Privacy Policy](https://forums.sabnzbd.org/ucp.php?mode=privacy)_
---
## System Resource Monitoring
The easiest method for displaying system info and resource usage in Dashy is with [Glances](https://nicolargo.github.io/glances/).

View File

@ -0,0 +1,212 @@
<template>
<div class="sabznbd">
<!-- Sabznbd Header -->
<div class="intro">
<p class="download">{{ download_speed }}</p>
<em :class="`fas fa-${status}`"></em>
</div>
<!-- Sabnzbd Details, If hideDetails set False -->
<div class="details" v-if="sabnzbdDetails.length > 0">
<div class="info-wrap" v-for="(section, indx) in sabnzbdDetails" :key="indx">
<p class="info-line" v-for="sabznbd in section" :key="sabznbd.label">
<span class="lbl">{{sabznbd.label}}</span>
<span class="val">{{ sabznbd.value }}</span>
</p>
</div>
</div>
<!-- Queue Details, If hideQueue set False -->
<div class="details" v-if="showQueue && sabnzbdQueue.length > 0">
<div class="info-wrap">
<p class="info-line" v-for="sabznbd in sabnzbdQueue" :key="sabznbd.label">
<em :class="`fas fa-${sabznbd.status}`"></em>
<span class="lbl">{{ sabznbd.filename }}</span>
<span class="lbl">{{ sabznbd.percentage }}%</span>
</p>
</div>
</div>
<!-- Show/ hide toggle button for Queue-->
<p class="more-details-btn" @click="toggleQueue" v-if="sabnzbdQueue.length > 0">
{{ showQueue ? "Hide Queue" : "Show Queue" }}
</p>
</div>
</template>
<script>
import WidgetMixin from '@/mixins/WidgetMixin';
export default {
mixins: [WidgetMixin],
data() {
return {
download_speed: null,
status: null,
sabnzbdDetails: [],
showQueue: false,
sabnzbdQueue: [],
};
},
mounted() {
this.checkProps();
},
computed: {
endpoint() {
const { apiKey, sabnzbdUrl } = this.options;
return `${sabnzbdUrl}/sabnzbd/api?output=json&apikey=${apiKey}&mode=queue`;
},
},
methods: {
/* Reads the kbpersec value of the server status, converts to mb/s if over 1024 kb. */
processKBperSec(kbpersec) {
if (kbpersec <= 1024) {
return `${Number(kbpersec).toFixed(0)} kb/s`;
} else {
return `${Number(kbpersec / 1024).toFixed(1)} mb/s`;
}
},
/* Reads the bool status output of the server status to append the correct icon */
processPaused(paused) {
if (paused === true) {
return 'pause';
} else {
return 'play';
}
},
/* Reads the string status output of the queue list to append the correct icon */
processPausedStr(paused) {
if (['Queued', 'Paused'].includes(paused)) {
return 'pause';
} else {
return 'play';
}
},
fetchData() {
this.makeRequest(this.endpoint).then(this.processData);
},
/* Fetches the Sabnzbd status, and processes results */
processData(data) {
this.download_speed = this.processKBperSec(data.queue.kbpersec);
this.status = this.processPaused(data.queue.paused);
if (!this.options.hideDetails) {
this.makeSabnzbdataData(data);
}
if (!this.options.hideQueue) {
this.makeSabnzbdataQueueData(data);
}
},
/* If showing Details, then Creates the object required */
makeSabnzbdataData(data) {
this.sabnzbdDetails = [
[
{ label: 'Time Left', value: data.queue.timeleft },
{ label: 'Queue', value: data.queue.noofslots },
],
[
{ label: 'Status', value: data.queue.status },
{ label: 'Size Left', value: data.queue.sizeleft },
],
];
},
/* If showing Queue, Creates list of downloads that are in the sabnzbd list */
makeSabnzbdataQueueData(data) {
this.sabnzbdQueue = [];
let i = 0;
for (i; i < data.queue.slots.length; i += 1) {
this.sabnzbdQueue.push({
status: this.processPausedStr(data.queue.slots[i].status),
filename: data.queue.slots[i].filename.substring(0, 25),
percentage: data.queue.slots[i].percentage,
});
}
},
/* Show/ hide Queue list */
toggleQueue() {
this.showQueue = !this.showQueue;
},
/* Validate input props, and print warning if incorrect */
checkProps() {
const ops = this.options;
if (!ops.sabnzbdUrl) this.error('Missing URL for Sabnzbd. Configure sabnzbdUrl in config file.');
if (!ops.apiKey) this.error('Missing API key for Sabnzbd. Configure apiKey in config file.');
},
},
};
</script>
<style scoped lang="scss">
.loader {
margin: 0 auto;
display: flex;
}
p {
color: var(--widget-text-color);
}
.sabznbd {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
.intro {
grid-column-start: span 2;
display: flex;
justify-content: space-around;
.fas {
font-size: 2rem;
color: var(--widget-text-color);
margin: 2;
}
.download {
font-size: 2rem;
margin: 0;
}
}
.more-details-btn {
grid-column-start: span 2;
cursor: pointer;
font-size: 0.9rem;
text-align: center;
width: fit-content;
margin: 0.25rem auto;
padding: 0.1rem 0.25rem;
border: 1px solid transparent;
opacity: var(--dimming-factor);
border-radius: var(--curve-factor);
&:hover {
border: 1px solid var(--widget-text-color);
}
&:focus, &:active {
background: var(--widget-text-color);
color: var(--widget-background-color);
}
}
// More sabznbd details table
.details {
grid-column-start: span 2;
display: flex;
.fas {
font-size: 1rem;
color: var(--widget-text-color);
margin: 2;
}
.info-wrap {
display: flex;
flex-direction: column;
width: 100%;
opacity: var(--dimming-factor);
p.info-line {
display: flex;
justify-content: space-between;
margin: 0.1rem 0.5rem;
padding: 0.1rem 0;
color: var(--widget-text-color);
&:not(:last-child) {
border-bottom: 1px dashed var(--widget-text-color);
}
span.lbl {
text-transform: capitalize;
}
}
}
}
}
</style>

View File

@ -97,6 +97,7 @@ const COMPAT = {
'public-holidays': 'PublicHolidays',
'public-ip': 'PublicIp',
'rss-feed': 'RssFeed',
sabnzbd: 'Sabnzbd',
'sports-scores': 'SportsScores',
'stat-ping': 'StatPing',
'stock-price-chart': 'StockPriceChart',