Compare commits

..

2 Commits

Author SHA1 Message Date
shamoon
b48d283dc2 Retry Omada login on HTML response; preserve cookies 2026-03-04 11:34:44 -08:00
shamoon
d313e0a124 Add some debug logging for omada 2026-03-02 09:22:39 -08:00
110 changed files with 2346 additions and 3239 deletions

View File

@@ -51,7 +51,7 @@ body:
id: troubleshooting
attributes:
label: Troubleshooting
description: Please include output from your [troubleshooting steps](https://gethomepage.dev/troubleshooting/#service-widget-errors), if relevant.
description: Please include output from your [troubleshooting steps](https://gethomepage.dev/more/troubleshooting/#service-widget-errors), if relevant.
validations:
required: true
- type: markdown

View File

@@ -8,12 +8,8 @@ updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
cooldown:
default-days: 7
interval: "daily"
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "monthly"
cooldown:
default-days: 7

View File

@@ -1,87 +0,0 @@
name-template: 'v$RESOLVED_VERSION'
tag-template: 'v$RESOLVED_VERSION'
change-template: '- $TITLE (#$NUMBER) @$AUTHOR'
change-title-escapes: '\\<*_&'
version-resolver:
major:
labels:
- 'major'
- 'breaking-change'
minor:
labels:
- 'enhancement'
- 'feature'
patch:
labels:
- 'bug'
- 'fix'
- 'dependencies'
- 'translation'
- 'documentation'
default: patch
categories:
- title: '⚠️ Breaking Changes'
labels:
- 'major'
- 'breaking-change'
- title: '🚀 Features'
labels:
- 'enhancement'
- 'feature'
- title: '🐛 Fixes'
labels:
- 'bug'
- 'fix'
- title: '🧰 Maintenance'
labels:
- 'dependencies'
- 'ci'
- 'chore'
- title: '🌐 Translations'
labels:
- 'translation'
- title: '📚 Documentation'
labels:
- 'documentation'
autolabeler:
- label: 'documentation'
files:
- 'docs/**'
- '*.md'
- '.github/**/*.md'
- label: 'ci'
files:
- '.github/workflows/**'
- label: 'dependencies'
files:
- 'package.json'
- 'pnpm-lock.yaml'
- 'pyproject.toml'
- 'uv.lock'
- label: 'feature'
files:
- 'src/components/**'
- 'src/widgets/**'
- 'src/pages/**'
- 'src/utils/**'
- label: 'chore'
files:
- 'Dockerfile*'
- 'docker-entrypoint.sh'
- 'k3d/**'
- label: 'translation'
files:
- 'public/locales/**'
template: |
## What's Changed
$CHANGES

View File

@@ -25,7 +25,6 @@ jobs:
download_translations: true
crowdin_branch_name: dev
localization_branch_name: l10n_dev
pull_request_labels: translation
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}

View File

@@ -33,7 +33,7 @@ jobs:
uses: pre-commit/action@v3.0.1
- name: Install pnpm
uses: pnpm/action-setup@v5
uses: pnpm/action-setup@v4
with:
version: 10
run_install: false
@@ -41,7 +41,7 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24
node-version: 20
cache: 'pnpm'
- name: Install dependencies
@@ -53,7 +53,7 @@ jobs:
build:
name: Docker Build & Push
if: github.repository == 'gethomepage/homepage'
runs-on: ubuntu-22.04
runs-on: self-hosted
needs: [ pre-commit ]
permissions:
contents: read
@@ -66,7 +66,7 @@ jobs:
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v6
uses: docker/metadata-action@v5
with:
images: |
${{ env.IMAGE_NAME }}
@@ -92,7 +92,7 @@ jobs:
nextjs-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install pnpm
uses: pnpm/action-setup@v5
uses: pnpm/action-setup@v4
with:
version: 10
run_install: false
@@ -100,7 +100,7 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24
node-version: 20
cache: 'pnpm'
- name: Install dependencies
@@ -115,7 +115,7 @@ jobs:
- name: Log into registry ${{ env.REGISTRY }}
if: github.event_name != 'pull_request'
uses: docker/login-action@v4
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
@@ -123,20 +123,20 @@ jobs:
- name: Login to Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v4
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Setup QEMU
uses: docker/setup-qemu-action@v4.0.0
uses: docker/setup-qemu-action@v3.7.0
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v4
uses: docker/setup-buildx-action@v3
- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@v7
uses: docker/build-push-action@v6
with:
context: .
push: ${{ github.event_name != 'pull_request' }}

View File

@@ -1,18 +0,0 @@
name: PR Quality
permissions:
contents: read
issues: read
pull-requests: write
on:
pull_request_target:
types: [opened, reopened]
jobs:
anti-slop:
runs-on: ubuntu-latest
steps:
- uses: peakoss/anti-slop@v0
with:
max-failures: 4

View File

@@ -1,54 +0,0 @@
name: Release Drafter
on:
push:
branches:
- dev
pull_request_target:
types: [opened, reopened, synchronize]
workflow_dispatch:
inputs:
version:
description: "Optional explicit version override (for example: 2.0.0)"
required: false
type: string
permissions:
contents: read
jobs:
update_release_draft:
name: Update Release Draft
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
permissions:
contents: write
pull-requests: read
runs-on: ubuntu-latest
steps:
- if: github.event_name == 'workflow_dispatch' && github.event.inputs.version != ''
uses: release-drafter/release-drafter@v7
with:
config-name: release-drafter.yml
version: ${{ github.event.inputs.version }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- if: github.event_name != 'workflow_dispatch' || github.event.inputs.version == ''
uses: release-drafter/release-drafter@v7
with:
config-name: release-drafter.yml
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
auto_label:
name: Auto Label PR
if: github.event_name == 'pull_request_target'
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: release-drafter/release-drafter/autolabeler@ebb69bb56f1b0ebd19897745035726b19bef973e
with:
config-name: release-drafter.yml
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -15,7 +15,7 @@ jobs:
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v5
- uses: pnpm/action-setup@v4
with:
version: 9

1
.vscode/launch.json vendored
View File

@@ -3,7 +3,6 @@
{
"name": "Debug homepage",
"type": "node",
"preLaunchTask": "pnpm install",
"request": "launch",
"runtimeExecutable": "pnpm",
"runtimeArgs": ["run", "dev"],

21
.vscode/tasks.json vendored
View File

@@ -1,21 +0,0 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "shell",
"label": "pnpm install",
"command": "pnpm install",
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"clear": true,
"panel": "shared",
"showReuseMessage": false
},
"problemMatcher": []
}
]
}

View File

@@ -27,6 +27,13 @@
<a href="https://paypal.me/phelpsben" title="Donate"><img alt="GitHub Sponsors" src="https://img.shields.io/github/sponsors/benphelps"></a>
</p>
<p align="center">
<a href="https://www.digitalocean.com/?refcode=df14bcb7c016&utm_campaign=Referral_Invite&utm_medium=Referral_Program&utm_source=badge"><img src="https://web-platforms.sfo2.cdn.digitaloceanspaces.com/WWW/Badge%201.svg" alt="DigitalOcean Referral Badge" /></a>
</p>
<p align="center">
<em>Homepage builds are kindly powered by DigitalOcean.</em>
</p>
# Features
With features like quick search, bookmarks, weather support, a wide range of integrations and widgets, an elegant and modern design, and a focus on performance, Homepage is your ideal start to the day and a handy companion throughout it.

View File

@@ -129,7 +129,7 @@ A progressive web app is an app that can be installed on a device and provide us
More information on PWAs can be found in [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps).
### App icons
## App icons
You can set custom icons for installable apps. More information about how you can set them can be found in the [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/icons).
@@ -150,7 +150,7 @@ For icon `src` you can pass either full URL or a local path relative to the `/ap
### Shortcuts
Shortcuts can be used to specify links to tabs, to be preselected when the homepage is opened as an app.
Shortcuts can e used to specify links to tabs, to be preselected when the homepage is opened as an app.
More information about how you can set them can be found in the [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Manifest/Reference/shortcuts).
```yaml

View File

@@ -223,33 +223,13 @@ spec:
- name: homepage
image: "ghcr.io/gethomepage/homepage:latest"
imagePullPolicy: Always
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
seccompProfile:
type: RuntimeDefault
env:
- name: MY_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: HOMEPAGE_ALLOWED_HOSTS
value: "$(MY_POD_IP):3000,gethomepage.dev" # See gethomepage.dev/installation/#homepage_allowed_hosts . Value before the comma is required for the k8s probe
value: gethomepage.dev # required, may need port. See gethomepage.dev/installation/#homepage_allowed_hosts
ports:
- name: http
containerPort: 3000
protocol: TCP
livenessProbe:
httpGet:
path: /api/healthcheck
port: http
initialDelaySeconds: 5
periodSeconds: 15
volumeMounts:
- mountPath: /app/config/custom.js
name: homepage-config

View File

@@ -16,7 +16,6 @@ The Glances widget allows you to monitor the resources (CPU, memory, storage, te
cpu: true # optional, enabled by default, disable by setting to false
mem: true # optional, enabled by default, disable by setting to false
cputemp: true # disabled by default
unit: imperial # optional for temp, default is metric
uptime: true # disabled by default
disk: / # disabled by default, use mount point of disk(s) in glances. Can also be a list (see below)
diskUnits: bytes # optional, bytes (default) or bbytes. Only applies to disk
@@ -32,3 +31,5 @@ disk:
- /boot
...
```
_Added in v0.4.18, updated in v0.6.11, v0.6.21_

View File

@@ -20,13 +20,13 @@ helm install my-release jameswynn/homepage
Set the `mode` in the `kubernetes.yaml` to `cluster`.
```yaml
mode: cluster
mode: default
```
To enable Kubernetes gateway-api compatibility, set `gateway` to `true`.
To enable Kubernetes gateway-api compatibility, set `route` to `gateway`.
```yaml
gateway: true
route: gateway
```
## Widgets

View File

@@ -5,12 +5,7 @@ const nextConfig = {
reactStrictMode: true,
output: "standalone",
images: {
remotePatterns: [
{
protocol: "https",
hostname: "cdn.jsdelivr.net",
},
],
domains: ["cdn.jsdelivr.net"],
unoptimized: true,
},
i18n,

View File

@@ -1,11 +1,11 @@
{
"name": "homepage",
"version": "1.12.0",
"version": "1.10.1",
"private": true,
"scripts": {
"preinstall": "npx only-allow pnpm",
"dev": "next dev",
"build": "next build --webpack",
"build": "next build",
"start": "next start",
"lint": "eslint .",
"test": "vitest run",
@@ -22,26 +22,26 @@
"follow-redirects": "^1.15.11",
"gamedig": "^5.3.2",
"i18next": "^25.8.0",
"ical.js": "^2.2.1",
"ical.js": "^2.1.0",
"js-yaml": "^4.1.1",
"json-rpc-2.0": "^1.7.0",
"luxon": "^3.6.1",
"memory-cache": "^0.2.0",
"minecraftstatuspinger": "^1.2.2",
"next": "^16.1.7",
"next-i18next": "^15.4.3",
"next": "^15.5.11",
"next-i18next": "^12.1.0",
"ping": "^0.4.4",
"pretty-bytes": "^7.1.0",
"raw-body": "^3.0.2",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-i18next": "^15.5.3",
"react-icons": "^5.6.0",
"react-icons": "^5.5.0",
"recharts": "^3.1.2",
"swr": "^2.4.1",
"systeminformation": "^5.30.8",
"swr": "^2.4.0",
"systeminformation": "^5.27.11",
"tough-cookie": "^6.0.0",
"urbackup-server-api": "^0.92.2",
"urbackup-server-api": "^0.91.0",
"winston": "^3.19.0",
"ws": "^8.18.3",
"xml-js": "^1.6.11"
@@ -60,12 +60,12 @@
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-prettier": "^5.5.5",
"eslint-plugin-prettier": "^5.5.4",
"eslint-plugin-react": "^7.37.4",
"eslint-plugin-react-hooks": "^5.2.0",
"jsdom": "^28.1.0",
"jsdom": "^26.1.0",
"postcss": "^8.5.6",
"prettier": "^3.8.1",
"prettier": "^3.7.3",
"prettier-plugin-organize-imports": "^4.3.0",
"tailwind-scrollbar": "^4.0.2",
"tailwindcss": "^4.1.18",

1236
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -108,14 +108,14 @@
"songs": "Liedjies"
},
"jellyfin": {
"playing": "Speel",
"transcoding": "Transkodering",
"bitrate": "Bistempo",
"no_active": "Geen Aktiewe Strome",
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"movies": "Movies",
"series": "Reekse",
"episodes": "Episode",
"songs": "Liedjies"
"series": "Series",
"episodes": "Episodes",
"songs": "Songs"
},
"esphome": {
"offline": "Vanlyn af",
@@ -184,13 +184,6 @@
"no_active": "Geen aktiewe strome nie",
"plex_connection_error": "Gaan Plex-verbinding Na"
},
"tracearr": {
"no_active": "Geen Aktiewe Strome",
"streams": "Uitsendings",
"transcodes": "Transkodering",
"directplay": "Direkte Speel",
"bitrate": "Bistempo"
},
"omada": {
"connectedAp": "Gekoppelde APs",
"activeUser": "Aktiewe toestelle",
@@ -289,14 +282,18 @@
"approved": "Goedgekeur",
"available": "Beskikbaar"
},
"seerr": {
"jellyseerr": {
"pending": "Afwagtend",
"approved": "Goedgekeur",
"available": "Beskikbaar",
"completed": "Afgehandel",
"processing": "Verwerking",
"issues": "Oop Kwessies"
},
"overseerr": {
"pending": "Afwagtend",
"processing": "Verwerking",
"approved": "Goedgekeur",
"available": "Beskikbaar"
},
"netalertx": {
"total": "Totaal",
"connected": "Gekoppel",
@@ -1155,11 +1152,11 @@
"artists": "Kunstenaars"
},
"arcane": {
"containers": "Houers",
"images": "Beelde",
"image_updates": "Beeldopdaterings",
"images_unused": "Ongebruik",
"environment_required": "Omgewings-ID Vereis"
"containers": "Containers",
"images": "Images",
"image_updates": "Image Updates",
"images_unused": "Unused",
"environment_required": "Environment ID Required"
},
"dockhand": {
"running": "Lopend",
@@ -1174,11 +1171,5 @@
"paused": "Onderbreek",
"total": "Totaal",
"environment_not_found": "Omgewing Nie Gevind Nie"
},
"sparkyfitness": {
"eaten": "Geëet",
"burned": "Verbrand",
"remaining": "Oorblywende",
"steps": "Stappe"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "No Active Streams",
"plex_connection_error": "تحقق من الاتصال بـ Plex"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "المتصلة APs",
"activeUser": "الأجهزة النشطة",
@@ -289,14 +282,18 @@
"approved": "مصدق",
"available": "متاح"
},
"seerr": {
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "معالجة",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "Няма активни потоци",
"plex_connection_error": "Провери връзка с Plex"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Свързани точки",
"activeUser": "Активни устройства",
@@ -289,14 +282,18 @@
"approved": "Одобрен",
"available": "Наличен"
},
"seerr": {
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Processing",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -61,7 +61,7 @@
"wlan_devices": "Dispositius WLAN",
"lan_users": "Usuaris LAN",
"wlan_users": "Usuaris WLAN",
"up": "ACTIU",
"up": "UP",
"down": "INACTIU",
"wait": "Si us plau espera",
"empty_data": "Estat del subsistema desconegut"
@@ -93,8 +93,8 @@
"http_status": "Estat HTTP",
"error": "Error",
"response": "Resposta",
"down": "Inactiu",
"up": "Actiu",
"down": "Down",
"up": "Up",
"not_available": "No disponible"
},
"emby": {
@@ -108,21 +108,21 @@
"songs": "Cançons"
},
"jellyfin": {
"playing": "Reproduïnt",
"transcoding": "Transcodificant",
"bitrate": "Taxa de bits",
"no_active": "Sense reproduccions actives",
"movies": "Pel·lícules",
"series": "Sèries",
"episodes": "Episodis",
"songs": "Cançons"
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"movies": "Movies",
"series": "Series",
"episodes": "Episodes",
"songs": "Songs"
},
"esphome": {
"offline": "Desconnectat",
"offline_alt": "Desconnectat",
"offline": "Offline",
"offline_alt": "Offline",
"online": "En línia",
"total": "Total",
"unknown": "Desconegut"
"unknown": "Unknown"
},
"evcc": {
"pv_power": "Producció",
@@ -143,7 +143,7 @@
"unread": "Sense llegir"
},
"fritzbox": {
"connectionStatus": "Estat",
"connectionStatus": "Status",
"connectionStatusUnconfigured": "Sense configurar",
"connectionStatusConnecting": "Connectant",
"connectionStatusAuthenticating": "Autenticant",
@@ -151,11 +151,11 @@
"connectionStatusDisconnecting": "Desconnectant",
"connectionStatusDisconnected": "Desconnectat",
"connectionStatusConnected": "Connectat",
"uptime": "Temps en funcionament",
"uptime": "Uptime",
"maxDown": "Màx. Descàrrega",
"maxUp": "Màx. Càrrega",
"down": "Inactiu",
"up": "Actiu",
"down": "Down",
"up": "Up",
"received": "Rebuts",
"sent": "Enviats",
"externalIPAddress": "IP ext.",
@@ -178,24 +178,17 @@
"passes": "Aprovat"
},
"tautulli": {
"playing": "Reproduïnt",
"transcoding": "Transcodificant",
"bitrate": "Taxa de bits",
"no_active": "Sense reproduccions actives",
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"plex_connection_error": "Comprova la connexió de Plex"
},
"tracearr": {
"no_active": "Sense reproduccions actives",
"streams": "Transmissions",
"transcodes": "Transcodificacions",
"directplay": "Reproducció directa",
"bitrate": "Taxa de bits"
},
"omada": {
"connectedAp": "AP connectats",
"activeUser": "Dispositius actius",
"alerts": "Alertes",
"connectedGateways": "Pasarel·les connectades",
"connectedGateways": "Connected gateways",
"connectedSwitches": "Conmutadors connectats"
},
"nzbget": {
@@ -206,24 +199,24 @@
"plex": {
"streams": "Transmissions actives",
"albums": "Àlbums",
"movies": "Pel·lícules",
"movies": "Movies",
"tv": "Sèries"
},
"sabnzbd": {
"rate": "Taxa",
"rate": "Rate",
"queue": "Cua",
"timeleft": "Temps restant"
},
"rutorrent": {
"active": "Actiu",
"upload": "Pujada",
"download": "Baixada"
"upload": "Upload",
"download": "Download"
},
"transmission": {
"download": "Baixada",
"upload": "Pujada",
"leech": "Sangonera",
"seed": "Sembrat"
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"qbittorrent": {
"download": "Download",
@@ -289,14 +282,18 @@
"approved": "Aprovat",
"available": "Disponible"
},
"seerr": {
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Processant",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -326,10 +323,10 @@
"total": "Total"
},
"suwayomi": {
"download": "Descarregat",
"download": "Downloaded",
"nondownload": "No descarregat",
"read": "Llegits",
"unread": "No llegits",
"read": "Read",
"unread": "Unread",
"downloadedread": "Descarregat i llegit",
"downloadedunread": "Descarregat i per llegir",
"nondownloadedread": "No descarregat i llegit",
@@ -350,7 +347,7 @@
"ago": "Fa {{value}}"
},
"technitium": {
"totalQueries": "Consultes",
"totalQueries": "Queries",
"totalNoError": "Èxits",
"totalServerFailure": "Fallades",
"totalNxDomain": "Dominis NX",
@@ -358,12 +355,12 @@
"totalAuthoritative": "Autoritatiu",
"totalRecursive": "Recursiu",
"totalCached": "A la memòria cau",
"totalBlocked": "Bloquejats",
"totalBlocked": "Blocked",
"totalDropped": "Abandonat",
"totalClients": "Clients"
},
"tdarr": {
"queue": "Cua",
"queue": "Queue",
"processed": "Processat",
"errored": "Error",
"saved": "Estalviat"
@@ -374,13 +371,13 @@
"middleware": "Intermediari"
},
"trilium": {
"version": "Versió",
"version": "Version",
"notesCount": "Notes",
"dbSize": "Tamany de la base de dades",
"unknown": "Desconegut"
"dbSize": "Database Size",
"unknown": "Unknown"
},
"navidrome": {
"nothing_streaming": "Sense reproduccions actives",
"nothing_streaming": "No Active Streams",
"please_wait": "Espereu si us plau"
},
"npm": {
@@ -403,43 +400,43 @@
"prowlarr": {
"enableIndexers": "Indexadors",
"numberOfGrabs": "Captures",
"numberOfQueries": "Consultes",
"numberOfQueries": "Queries",
"numberOfFailGrabs": "Captures fallides",
"numberOfFailQueries": "Consultes fallides"
},
"jackett": {
"configured": "Configurat",
"errored": "Errors"
"errored": "Errored"
},
"strelaysrv": {
"numActiveSessions": "Sessions",
"numConnections": "Connexions",
"dataRelayed": "Transmès",
"transferRate": "Taxa"
"transferRate": "Rate"
},
"mastodon": {
"user_count": "Usuaris",
"user_count": "Users",
"status_count": "Publicacions",
"domain_count": "Dominis"
},
"medusa": {
"wanted": "Volguts",
"queued": "Encuat",
"series": "Sèries"
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"minecraft": {
"players": "Jugadors",
"version": "Versió",
"status": "Estat",
"up": "En línia",
"down": "Fora de línia"
"status": "Status",
"up": "Online",
"down": "Offline"
},
"miniflux": {
"read": "Llegit",
"unread": "No llegits"
"unread": "Unread"
},
"authentik": {
"users": "Usuaris",
"users": "Users",
"loginsLast24H": "Inicis de sessió (24h)",
"failedLoginsLast24H": "Errors d'inici de sessió (24h)"
},
@@ -451,19 +448,19 @@
},
"glances": {
"cpu": "CPU",
"load": "Càrrega",
"wait": "Si us plau espera",
"load": "Load",
"wait": "Please wait",
"temp": "TEMP",
"_temp": "Temp",
"warn": "Avís",
"uptime": "ACTIU",
"uptime": "UP",
"total": "Total",
"free": "Lliure",
"used": "Utilitzat",
"free": "Free",
"used": "Used",
"days": "d",
"hours": "h",
"crit": "Crític",
"read": "Lectura",
"read": "Read",
"write": "Escriptura",
"gpu": "GPU",
"mem": "Mem",
@@ -484,25 +481,25 @@
"1-day": "Majorment assolellat",
"1-night": "Majorment clar",
"2-day": "Parcialment ennuvolat",
"2-night": "Parcialment ennuvolat",
"2-night": "Partly Cloudy",
"3-day": "Ennuvolat",
"3-night": "Ennuvolat",
"3-night": "Cloudy",
"45-day": "Boirós",
"45-night": "Emboirat",
"48-day": "Boirós",
"48-night": "Emboirat",
"45-night": "Foggy",
"48-day": "Foggy",
"48-night": "Foggy",
"51-day": "Ruixats lleugers",
"51-night": "Plugim lleuger",
"51-night": "Light Drizzle",
"53-day": "Ruixat",
"53-night": "Plugim",
"53-night": "Drizzle",
"55-day": "Ruixat intens",
"55-night": "Plovisqueig intens",
"55-night": "Heavy Drizzle",
"56-day": "Lleuger ruixat gelat",
"56-night": "Lleuger ruixat gelat",
"56-night": "Light Freezing Drizzle",
"57-day": "Ruixat gelat",
"57-night": "Plugim gelat",
"57-night": "Freezing Drizzle",
"61-day": "Pluja lleugera",
"61-night": "Pluja lleugera",
"61-night": "Light Rain",
"63-day": "Pluja",
"63-night": "Rain",
"65-day": "Pluja intensa",
@@ -637,12 +634,12 @@
"mikrotik": {
"cpuLoad": "Càrrega de CPU",
"memoryUsed": "Memoria en ús",
"uptime": "Temps en funcionament",
"uptime": "Uptime",
"numberOfLeases": "IPs assignades"
},
"xteve": {
"streams_all": "Tots els streams",
"streams_active": "Transmissions actives",
"streams_active": "Active Streams",
"streams_xepg": "Canals XEPG"
},
"opendtu": {
@@ -652,7 +649,7 @@
"limit": "Límit"
},
"opnsense": {
"cpu": "Càrrega de CPU",
"cpu": "CPU Load",
"memory": "Memòria activa",
"wanUpload": "Pujada WAN",
"wanDownload": "Baixada WAN"
@@ -664,21 +661,21 @@
"layers": "Capes"
},
"octoprint": {
"printer_state": "Estat",
"printer_state": "Status",
"temp_tool": "Temperatura capçal",
"temp_bed": "Temperatura llit",
"job_completion": "Finalització"
},
"cloudflared": {
"origin_ip": "IP Origen",
"status": "Estat"
"status": "Status"
},
"pfsense": {
"load": "Càrrega mitjana",
"memory": "Ús Memòria",
"wanStatus": "Estat WAN",
"up": "Actiu",
"down": "Inactiu",
"up": "Up",
"down": "Down",
"temp": "Temp",
"disk": "Ús Disc",
"wanIP": "IP WAN"
@@ -690,58 +687,58 @@
"memory_usage": "Memòria"
},
"immich": {
"users": "Usuaris",
"users": "Users",
"photos": "Fotos",
"videos": "Vídeos",
"videos": "Videos",
"storage": "Emmagatzematge"
},
"uptimekuma": {
"up": "Actius",
"down": "Caiguts",
"uptime": "Temps en funcionament",
"uptime": "Uptime",
"incident": "Incidència",
"m": "m"
},
"atsumeru": {
"series": "Sèries",
"series": "Series",
"archives": "Arxius",
"chapters": "Capítols",
"categories": "Categories"
},
"komga": {
"libraries": "Biblioteques",
"series": "Sèries",
"books": "Llibres"
"series": "Series",
"books": "Books"
},
"diskstation": {
"days": "Dies",
"uptime": "Temps en funcionament",
"volumeAvailable": "Disponible"
"days": "Days",
"uptime": "Uptime",
"volumeAvailable": "Available"
},
"dispatcharr": {
"channels": "Canals",
"streams": "Transmissions"
"channels": "Channels",
"streams": "Streams"
},
"mylar": {
"series": "Sèries",
"series": "Series",
"issues": "Problemes",
"wanted": "Volguts"
"wanted": "Wanted"
},
"photoprism": {
"albums": "Àlbums",
"photos": "Fotos",
"videos": "Vídeos",
"albums": "Albums",
"photos": "Photos",
"videos": "Videos",
"people": "Gent"
},
"fileflows": {
"queue": "Cua",
"processing": "Processant",
"processed": "Processat",
"queue": "Queue",
"processing": "Processing",
"processed": "Processed",
"time": "Temps"
},
"firefly": {
"networth": "Valor Net",
"budget": "Pressupost"
"networth": "Net Worth",
"budget": "Budget"
},
"grafana": {
"dashboards": "Taulells",
@@ -758,11 +755,11 @@
"numshares": "Elements compartits"
},
"kopia": {
"status": "Estat",
"status": "Status",
"size": "Mida",
"lastrun": "Darrera execució",
"nextrun": "Següent execució",
"failed": "Error"
"failed": "Failed"
},
"unmanic": {
"active_workers": "Treballadors actius",
@@ -779,21 +776,21 @@
"targets_total": "Objectius Totals"
},
"gatus": {
"up": "Actius",
"down": "Caiguts",
"uptime": "Temps en funcionament"
"up": "Sites Up",
"down": "Sites Down",
"uptime": "Uptime"
},
"ghostfolio": {
"gross_percent_today": "Avui",
"gross_percent_today": "Today",
"gross_percent_1y": "Un any",
"gross_percent_max": "Sempre",
"net_worth": "Valor Net"
"net_worth": "Net Worth"
},
"audiobookshelf": {
"podcasts": "Pòdcasts",
"books": "Llibres",
"books": "Books",
"podcastsDuration": "Durada",
"booksDuration": "Durada"
"booksDuration": "Duration"
},
"homeassistant": {
"people_home": "Gent a casa",
@@ -802,23 +799,23 @@
},
"whatsupdocker": {
"monitoring": "Supervisió",
"updates": "Actualitzacions"
"updates": "Updates"
},
"calibreweb": {
"books": "Llibres",
"books": "Books",
"authors": "Autors",
"categories": "Categories",
"series": "Sèries"
"series": "Series"
},
"booklore": {
"libraries": "Biblioteques",
"books": "Llibres",
"reading": "Llegint",
"finished": "Acabats"
"libraries": "Libraries",
"books": "Books",
"reading": "Reading",
"finished": "Finished"
},
"jdownloader": {
"downloadCount": "Cua",
"downloadBytesRemaining": "Restant",
"downloadCount": "Queue",
"downloadBytesRemaining": "Remaining",
"downloadTotalBytes": "Size",
"downloadSpeed": "Speed"
},
@@ -990,17 +987,17 @@
},
"frigate": {
"cameras": "Càmeres",
"uptime": "Temps en funcionament",
"version": "Versió"
"uptime": "Uptime",
"version": "Version"
},
"linkwarden": {
"links": "Enllaços",
"collections": "Col·leccions",
"tags": "Etiquetes"
"tags": "Tags"
},
"zabbix": {
"unclassified": "No classificat",
"information": "Informació",
"information": "Information",
"warning": "Avís",
"average": "Mitjana",
"high": "Alt",
@@ -1021,22 +1018,22 @@
"tasksInProgress": "Tasques en marxa"
},
"headscale": {
"name": "Nom",
"address": "Adreça",
"last_seen": "Vist per darrera vegada",
"status": "Estat",
"online": "En línia",
"offline": "Desconnectat"
"name": "Name",
"address": "Address",
"last_seen": "Last Seen",
"status": "Status",
"online": "Online",
"offline": "Offline"
},
"beszel": {
"name": "Nom",
"name": "Name",
"systems": "Sistemes",
"up": "Actiu",
"down": "Inactiu",
"paused": "Pausat",
"pending": "Pendent",
"status": "Estat",
"updated": "Actualitzat",
"up": "Up",
"down": "Down",
"paused": "Paused",
"pending": "Pending",
"status": "Status",
"updated": "Updated",
"cpu": "CPU",
"memory": "MEM",
"disk": "Disc",
@@ -1046,34 +1043,34 @@
"apps": "Apps",
"synced": "Sincronitzats",
"outOfSync": "Dessincronitzats",
"healthy": "Sa",
"healthy": "Healthy",
"degraded": "Degradats",
"progressing": "Progressant",
"missing": "Falten",
"missing": "Missing",
"suspended": "Suspesos"
},
"spoolman": {
"loading": "Carregant"
"loading": "Loading"
},
"gitlab": {
"groups": "Grups",
"issues": "Problemes",
"issues": "Issues",
"merges": "Merge Requests",
"projects": "Projectes"
},
"apcups": {
"status": "Estat",
"load": "Càrrega",
"bcharge": "Càrrega de la bateria",
"timeleft": "Temps restant"
"status": "Status",
"load": "Load",
"bcharge": "Battery Charge",
"timeleft": "Time Left"
},
"karakeep": {
"bookmarks": "Marcadors",
"favorites": "Preferits",
"archived": "Arxivats",
"highlights": "Destacats",
"lists": "Llistes",
"tags": "Etiquetes"
"bookmarks": "Bookmarks",
"favorites": "Favorites",
"archived": "Archived",
"highlights": "Highlights",
"lists": "Lists",
"tags": "Tags"
},
"slskd": {
"slskStatus": "Network",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -184,13 +184,6 @@
"no_active": "No Active Streams",
"plex_connection_error": "Tjek Plex-forbindelse"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Forbundne APs",
"activeUser": "Aktive enheder",
@@ -289,14 +282,18 @@
"approved": "Godkendt",
"available": "Tilgængelig"
},
"seerr": {
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Behandler",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -108,7 +108,7 @@
"songs": "Songs"
},
"jellyfin": {
"playing": "Wiedergabe",
"playing": "Playing",
"transcoding": "Transkodierung",
"bitrate": "Bitrate",
"no_active": "Keine aktiven Streams",
@@ -184,13 +184,6 @@
"no_active": "Keine aktiven Streams",
"plex_connection_error": "Prüfe Plex-Verbindung"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Verbundene APs",
"activeUser": "Aktive Geräte",
@@ -289,13 +282,17 @@
"approved": "Genehmigt",
"available": "Verfügbar"
},
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
"jellyseerr": {
"pending": "Wartend",
"approved": "Genehmigt",
"available": "Verfügbar",
"issues": "Offene Issues"
},
"overseerr": {
"pending": "Wartend",
"processing": "Wird verarbeitet",
"approved": "Genehmigt",
"available": "Verfügbar"
},
"netalertx": {
"total": "Total",
@@ -1162,23 +1159,17 @@
"environment_required": "Environment ID Required"
},
"dockhand": {
"running": "Wird ausgeführt",
"stopped": "Gestoppt",
"running": "Running",
"stopped": "Stopped",
"cpu": "CPU",
"memory": "RAM",
"memory": "Memory",
"images": "Images",
"volumes": "Volumes",
"events_today": "Heutige Ereignisse",
"pending_updates": "Ausstehende Updates",
"stacks": "Stacks",
"paused": "Pausiert",
"total": "Gesamt",
"total": "Total",
"environment_not_found": "Umgebung nicht gefunden"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "No Active Streams",
"plex_connection_error": "Έλεγχος Σύνδεσης με Plex"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Συνδεδεμένα APs",
"activeUser": "Ενεργές συσκευές",
@@ -289,14 +282,18 @@
"approved": "Εγκρίθηκε",
"available": "Διαθέσιμο"
},
"seerr": {
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Σε επεξεργασία",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "No Active Streams",
"plex_connection_error": "Check Plex Connection"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Connected APs",
"activeUser": "Active devices",
@@ -289,14 +282,18 @@
"approved": "Aprobita",
"available": "Havebla"
},
"seerr": {
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Processing",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "Sin transmisiones activas",
"plex_connection_error": "Comprueba la conexión a Plex"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "AP conectados",
"activeUser": "Dispositivos activos",
@@ -289,13 +282,17 @@
"approved": "Aprobado",
"available": "Disponible"
},
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
"jellyseerr": {
"pending": "Pendiente",
"approved": "Aprobado",
"available": "Disponible",
"issues": "Issues Abiertos"
},
"overseerr": {
"pending": "Pendiente",
"processing": "Procesando",
"approved": "Aprobado",
"available": "Disponible"
},
"netalertx": {
"total": "Total",
@@ -1174,11 +1171,5 @@
"paused": "En Pausa",
"total": "Total",
"environment_not_found": "Entorno no encontrado"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "No Active Streams",
"plex_connection_error": "Check Plex Connection"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Connected APs",
"activeUser": "Active devices",
@@ -289,14 +282,18 @@
"approved": "Approved",
"available": "Available"
},
"seerr": {
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Processing",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "No Active Streams",
"plex_connection_error": "Check Plex Connection"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Connected APs",
"activeUser": "Active devices",
@@ -289,14 +282,18 @@
"approved": "Hyväksytty",
"available": "Saatavilla"
},
"seerr": {
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Processing",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -108,8 +108,8 @@
"songs": "Morceaux"
},
"jellyfin": {
"playing": "En cours",
"transcoding": "En cours d'encodage",
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"movies": "Movies",
@@ -184,13 +184,6 @@
"no_active": "Aucune lecture en cours",
"plex_connection_error": "Vérifier la connexion à Plex"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "APs connectées",
"activeUser": "Périphériques actifs",
@@ -289,13 +282,17 @@
"approved": "Approuvé",
"available": "Disponible"
},
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
"jellyseerr": {
"pending": "En attente",
"approved": "Approuvé",
"available": "Disponible",
"issues": "Problèmes non résolus"
},
"overseerr": {
"pending": "En attente",
"processing": "En cours de traitement",
"approved": "Approuvé",
"available": "Disponible"
},
"netalertx": {
"total": "Total",
@@ -616,9 +613,9 @@
"pangolin": {
"orgs": "Orgs",
"sites": "Sites",
"resources": "Ressources",
"targets": "Cibles",
"traffic": "Trafique",
"resources": "Resources",
"targets": "Targets",
"traffic": "Traffic",
"in": "In",
"out": "Out"
},
@@ -715,7 +712,7 @@
},
"diskstation": {
"days": "Jours",
"uptime": "Démarré depuis",
"uptime": "Disponibilité",
"volumeAvailable": "Disponible"
},
"dispatcharr": {
@@ -746,7 +743,7 @@
"grafana": {
"dashboards": "Tableau de bord",
"datasources": "Sources données",
"totalalerts": "Alertes totales",
"totalalerts": "Total alertes",
"alertstriggered": "Alertes déclenchées"
},
"nextcloud": {
@@ -945,7 +942,7 @@
"studios": "Studios",
"movies": "Films",
"tags": "Tags",
"oCount": "O-mètre"
"oCount": "0 Compte"
},
"tandoor": {
"users": "Utilisateurs",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "אין הזרמות פעילות",
"plex_connection_error": "בדוק חיבור ל-Plex"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "נקודות גישה מחוברות",
"activeUser": "מכשירים פעילים",
@@ -289,14 +282,18 @@
"approved": "מאושר",
"available": "זמין"
},
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"jellyseerr": {
"pending": "ממתין לאישור",
"approved": "מאושר",
"available": "זמין",
"issues": "Open Issues"
},
"overseerr": {
"pending": "ממתין לאישור",
"processing": "מעבד",
"approved": "מאושר",
"available": "זמין"
},
"netalertx": {
"total": "סה\"כ",
"connected": "מחובר",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "No Active Streams",
"plex_connection_error": "Check Plex Connection"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Connected APs",
"activeUser": "Active devices",
@@ -289,14 +282,18 @@
"approved": "Approved",
"available": "Available"
},
"seerr": {
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Processing",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -108,14 +108,14 @@
"songs": "Pjesme"
},
"jellyfin": {
"playing": "Reprodukcija u tijeku",
"transcoding": "Prekodiranje",
"bitrate": "Stopa bitova",
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"movies": "Filmovi",
"series": "Serije",
"episodes": "Epizode",
"songs": "Pjesme"
"movies": "Movies",
"series": "Series",
"episodes": "Episodes",
"songs": "Songs"
},
"esphome": {
"offline": "Offline",
@@ -184,13 +184,6 @@
"no_active": "Nema aktivnih prijenosa",
"plex_connection_error": "Provjeri Plex vezu"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Prekodiranja",
"directplay": "Izravna reprodukcija",
"bitrate": "Stopa bitova"
},
"omada": {
"connectedAp": "Povezani AP-ovi",
"activeUser": "Aktivni uređaji",
@@ -289,14 +282,18 @@
"approved": "Odobreno",
"available": "Dostupno"
},
"seerr": {
"pending": "Na čekanju",
"jellyseerr": {
"pending": "U tijeku",
"approved": "Odobreno",
"available": "Dostupno",
"completed": "Dovršeno",
"processing": "Obrada",
"issues": "Otvoreni problemi"
},
"overseerr": {
"pending": "U tijeku",
"processing": "Obrada",
"approved": "Odobreno",
"available": "Dostupno"
},
"netalertx": {
"total": "Ukupno",
"connected": "Spojeno",
@@ -546,7 +543,7 @@
"up": "Aktivno",
"pending": "U tijeku",
"down": "Neaktivno",
"ok": "U redu"
"ok": "Ok"
},
"healthchecks": {
"new": "Novo",
@@ -614,11 +611,11 @@
"total": "Ukupno"
},
"pangolin": {
"orgs": "Organizacije",
"sites": "Web-stranice",
"resources": "Resursi",
"targets": "Ciljevi",
"traffic": "Promet",
"orgs": "Orgs",
"sites": "Sites",
"resources": "Resources",
"targets": "Targets",
"traffic": "Traffic",
"in": "In",
"out": "Out"
},
@@ -719,7 +716,7 @@
"volumeAvailable": "Dostupno"
},
"dispatcharr": {
"channels": "Kanali",
"channels": "Channels",
"streams": "Streams"
},
"mylar": {
@@ -811,10 +808,10 @@
"series": "Serije"
},
"booklore": {
"libraries": "Knjižnice",
"books": "Knjige",
"reading": "Čitanje",
"finished": "Završeno"
"libraries": "Libraries",
"books": "Books",
"reading": "Reading",
"finished": "Finished"
},
"jdownloader": {
"downloadCount": "Red čekanja",
@@ -1155,30 +1152,24 @@
"artists": "Izvođači"
},
"arcane": {
"containers": "Kontejneri",
"images": "Slike",
"image_updates": "Aktualizirane slike",
"images_unused": "Nekorišteno",
"environment_required": "ID okruženja se mora navesti"
"containers": "Containers",
"images": "Images",
"image_updates": "Image Updates",
"images_unused": "Unused",
"environment_required": "Environment ID Required"
},
"dockhand": {
"running": "Pokreće se",
"stopped": "Zaustavljeno",
"running": "Running",
"stopped": "Stopped",
"cpu": "CPU",
"memory": "Memorija",
"images": "Slike",
"volumes": "Jedinice memorije",
"events_today": "Događanja danas",
"pending_updates": "Aktualiziranja na čekanju",
"memory": "Memory",
"images": "Images",
"volumes": "Volumes",
"events_today": "Events Today",
"pending_updates": "Pending Updates",
"stacks": "Stacks",
"paused": "Pauzirano",
"total": "Ukupno",
"environment_not_found": "Okruženje nije pronađeno"
},
"sparkyfitness": {
"eaten": "Pojedeno",
"burned": "Potrošeno",
"remaining": "Preostalo",
"steps": "Koraci"
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "Nincs aktív lejátszás",
"plex_connection_error": "Plex kapcsolat ellenőrzése"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Csatlakoztatott AP-k",
"activeUser": "Aktív eszközök",
@@ -289,13 +282,17 @@
"approved": "Engedélyezett",
"available": "Elérhető"
},
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
"jellyseerr": {
"pending": "Függőben lévő",
"approved": "Jóváhagyott",
"available": "Elérhető",
"issues": "Nyitott problémák"
},
"overseerr": {
"pending": "Függőben lévő",
"processing": "Feldolgozás",
"approved": "Jóváhagyott",
"available": "Elérhető"
},
"netalertx": {
"total": "Összes",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "No Active Streams",
"plex_connection_error": "Cek Koneksi ke Plex"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "AP Tersambung",
"activeUser": "Perangakat yang Aktif",
@@ -289,14 +282,18 @@
"approved": "Tersetujui",
"available": "Tersedia"
},
"seerr": {
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Memproses",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -113,7 +113,7 @@
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"movies": "Movies",
"series": "Serie",
"series": "Series",
"episodes": "Episodes",
"songs": "Songs"
},
@@ -184,13 +184,6 @@
"no_active": "No Active Streams",
"plex_connection_error": "Controllare la connessione a Plex"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "AP Connessi",
"activeUser": "Dispositivi attivi",
@@ -289,14 +282,18 @@
"approved": "Approvati",
"available": "Disponibili"
},
"seerr": {
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "In lavorazione",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -321,7 +318,7 @@
"ping": "Ping"
},
"portainer": {
"running": "In esecuzione",
"running": "Running",
"stopped": "Fermati",
"total": "Total"
},
@@ -716,7 +713,7 @@
"diskstation": {
"days": "Days",
"uptime": "Uptime",
"volumeAvailable": "Disponibili"
"volumeAvailable": "Available"
},
"dispatcharr": {
"channels": "Channels",
@@ -1087,9 +1084,9 @@
"sharedFiles": "Files"
},
"jellystat": {
"songs": "Brani",
"movies": "Film",
"episodes": "Episodi",
"songs": "Songs",
"movies": "Movies",
"episodes": "Episodes",
"other": "Altro"
},
"checkmk": {
@@ -1113,11 +1110,11 @@
"total": "Total"
},
"wallos": {
"activeSubscriptions": "Abbonamenti",
"thisMonthlyCost": "Questo Mese",
"nextMonthlyCost": "Mese Prossimo",
"activeSubscriptions": "Subscriptions",
"thisMonthlyCost": "This Month",
"nextMonthlyCost": "Next Month",
"previousMonthlyCost": "Prev. Month",
"nextRenewingSubscription": ""
"nextRenewingSubscription": "Next Payment"
},
"unraid": {
"STARTED": "Started",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "No Active Streams",
"plex_connection_error": "Plex接続の確認"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "接続されたAP",
"activeUser": "アクティブデバイス",
@@ -289,14 +282,18 @@
"approved": "承認済",
"available": "利用可"
},
"seerr": {
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "処理中",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "활성 스트림 없음",
"plex_connection_error": "Plex 연결 확인"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "연결된 AP",
"activeUser": "활성 장치",
@@ -289,13 +282,17 @@
"approved": "승인됨",
"available": "이용 가능"
},
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
"jellyseerr": {
"pending": "대기 중",
"approved": "승인됨",
"available": "이용 가능",
"issues": "열린 이슈"
},
"overseerr": {
"pending": "대기 중",
"processing": "처리 중",
"approved": "승인됨",
"available": "이용 가능"
},
"netalertx": {
"total": "전체",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "No Active Streams",
"plex_connection_error": "Check Plex Connection"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Savienotie piekļuves punkti",
"activeUser": "Aktīvās ierīces",
@@ -289,14 +282,18 @@
"approved": "Approved",
"available": "Available"
},
"seerr": {
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Processing",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "No Active Streams",
"plex_connection_error": "Check Plex Connection"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Connected APs",
"activeUser": "Peranti aktif",
@@ -289,14 +282,18 @@
"approved": "Lulus",
"available": "Sudah Ada"
},
"seerr": {
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Processing",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "Geen Actieve Streams",
"plex_connection_error": "Controleer Plex Connectie"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Verbonden APs",
"activeUser": "Actieve apparaten",
@@ -289,14 +282,18 @@
"approved": "Goedgekeurd",
"available": "Beschikbaar"
},
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"jellyseerr": {
"pending": "In afwachting",
"approved": "Goedgekeurd",
"available": "Beschikbaar",
"issues": "Open Issues"
},
"overseerr": {
"pending": "In afwachting",
"processing": "Verwerken",
"approved": "Goedgekeurd",
"available": "Beschikbaar"
},
"netalertx": {
"total": "Totaal",
"connected": "Verbonden",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "No Active Streams",
"plex_connection_error": "Kontroller Plex tilkoblingen"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Tilkoblede AP'er",
"activeUser": "Aktive enheter",
@@ -289,14 +282,18 @@
"approved": "Godkjent",
"available": "Tilgjengelig"
},
"seerr": {
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Behandler",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -108,14 +108,14 @@
"songs": "Piosenki"
},
"jellyfin": {
"playing": "Odtwarza",
"transcoding": "Transkoduje",
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "Brak aktywnych strumieni",
"movies": "Filmy",
"series": "Seriale",
"episodes": "Odcinki",
"songs": "Piosenki"
"no_active": "No Active Streams",
"movies": "Movies",
"series": "Series",
"episodes": "Episodes",
"songs": "Songs"
},
"esphome": {
"offline": "Offline",
@@ -184,13 +184,6 @@
"no_active": "Brak aktywnych strumieni",
"plex_connection_error": "Sprawdź połączenie z Plex"
},
"tracearr": {
"no_active": "Brak aktywnych strumieni",
"streams": "Strumienie",
"transcodes": "Transkodowania",
"directplay": "Odtwarzanie bezpośrednie",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Połączone punkty dostępowe",
"activeUser": "Aktywne urządzenia",
@@ -289,14 +282,18 @@
"approved": "Zaakceptowane",
"available": "Dostępne"
},
"seerr": {
"jellyseerr": {
"pending": "Oczekujące",
"approved": "Zaakceptowane",
"available": "Dostępne",
"completed": "Ukończone",
"processing": "Przetwarzane",
"issues": "Otwarte zgłoszenia"
},
"overseerr": {
"pending": "Oczekujące",
"processing": "Przetwarzane",
"approved": "Zaakceptowane",
"available": "Dostępne"
},
"netalertx": {
"total": "Razem",
"connected": "Połączono",
@@ -719,8 +716,8 @@
"volumeAvailable": "Dostępne"
},
"dispatcharr": {
"channels": "Kanały",
"streams": "Strumienie"
"channels": "Channels",
"streams": "Streams"
},
"mylar": {
"series": "Seriale",
@@ -1155,11 +1152,11 @@
"artists": "Wykonawcy"
},
"arcane": {
"containers": "Kontenery",
"images": "Obrazy",
"image_updates": "Aktualizacje obrazów",
"images_unused": "Nieużywane",
"environment_required": "Wymagane ID środowiska"
"containers": "Containers",
"images": "Images",
"image_updates": "Image Updates",
"images_unused": "Unused",
"environment_required": "Environment ID Required"
},
"dockhand": {
"running": "Działające",
@@ -1174,11 +1171,5 @@
"paused": "Wstrzymane",
"total": "Razem",
"environment_not_found": "Środowisko nie znalezione"
},
"sparkyfitness": {
"eaten": "Zjedzone",
"burned": "Spalone",
"remaining": "Pozostało",
"steps": "Kroki"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "No Active Streams",
"plex_connection_error": "Verifique a conexão do Plex"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "APs Ligados",
"activeUser": "Dispositivos activos",
@@ -289,14 +282,18 @@
"approved": "Aprovado",
"available": "Disponível"
},
"seerr": {
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "A Processar",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "Sem Streams Ativos",
"plex_connection_error": "Verifique a conexão do Plex"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "APs Ligados",
"activeUser": "Dispositivos ativos",
@@ -289,13 +282,17 @@
"approved": "Aprovada",
"available": "Disponível"
},
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
"jellyseerr": {
"pending": "Pendente",
"approved": "Aprovado",
"available": "Disponível",
"issues": "Incidentes Abertos"
},
"overseerr": {
"pending": "Pendente",
"processing": "Processando",
"approved": "Aprovado",
"available": "Disponível"
},
"netalertx": {
"total": "Total",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "No Active Streams",
"plex_connection_error": "Check Plex Connection"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Connected APs",
"activeUser": "Dispozitive active",
@@ -289,14 +282,18 @@
"approved": "Aprobate",
"available": "Disponibile"
},
"seerr": {
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Procesare",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -108,14 +108,14 @@
"songs": "Песни"
},
"jellyfin": {
"playing": "Воспроизводится",
"transcoding": "Перекодирование",
"bitrate": "Битрейт",
"no_active": "Нет активных потоков",
"movies": "Фильмы",
"series": "Сериалы",
"episodes": "Эпизоды",
"songs": "Песни"
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"movies": "Movies",
"series": "Series",
"episodes": "Episodes",
"songs": "Songs"
},
"esphome": {
"offline": "Не в сети",
@@ -184,13 +184,6 @@
"no_active": "Нет активных стримов",
"plex_connection_error": "Проверка соединения Plex"
},
"tracearr": {
"no_active": "Нет активных потоков",
"streams": "Потоки",
"transcodes": "Transcodes",
"directplay": "Прямое воспроизведение",
"bitrate": "Битрейт"
},
"omada": {
"connectedAp": "Подключенные точки доступа",
"activeUser": "Активные устройства",
@@ -289,13 +282,17 @@
"approved": "Одобрено",
"available": "Доступно"
},
"seerr": {
"pending": "Pending",
"jellyseerr": {
"pending": "Ожидают",
"approved": "Одобрено",
"available": "Доступно",
"completed": "Завершено",
"processing": "Обработка",
"issues": "Открытые задачи"
"issues": "Open Issues"
},
"overseerr": {
"pending": "Ожидают",
"processing": "В процессе",
"approved": "Одобрено",
"available": "Доступно"
},
"netalertx": {
"total": "Всего",
@@ -1133,8 +1130,8 @@
"NO_DATA_DISKS": "No Data Disks",
"notifications": "Уведомления",
"status": "Статус",
"cpu": "ЦП",
"memoryUsed": "Использовано ОЗУ",
"cpu": "CPU",
"memoryUsed": "Memory Used",
"memoryAvailable": "Memory Available",
"arrayUsed": "Array Used",
"arrayFree": "Array Free",
@@ -1144,14 +1141,14 @@
"backrest": {
"num_plans": "Plans",
"num_success_30": "Successes",
"num_failure_30": "Ошибки",
"num_failure_30": "Failures",
"num_success_latest": "Succeeding",
"num_failure_latest": "Failing",
"bytes_added_30": "Bytes Added"
},
"yourspotify": {
"songs": "Songs",
"time": "Время",
"time": "Time",
"artists": "Artists"
},
"arcane": {
@@ -1173,12 +1170,6 @@
"stacks": "Stacks",
"paused": "Paused",
"total": "Total",
"environment_not_found": "Среда не найдена"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
"environment_not_found": "Environment Not Found"
}
}

View File

@@ -93,7 +93,7 @@
"http_status": "HTTP stavový kód",
"error": "Chyba",
"response": "Odpoveď",
"down": "Nedostupné",
"down": "Down",
"up": "Beží",
"not_available": "Nedostupné"
},
@@ -108,18 +108,18 @@
"songs": "Skladby"
},
"jellyfin": {
"playing": "Prehráva sa",
"transcoding": "Prebieha prekódovanie",
"bitrate": "Prenosová rýchlosť",
"no_active": "Žiadne aktívne vysielania",
"movies": "Filmov",
"series": "Seriálov",
"episodes": "Epizód",
"songs": "Skladieb"
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"movies": "Movies",
"series": "Series",
"episodes": "Episodes",
"songs": "Songs"
},
"esphome": {
"offline": "Nedostupné",
"offline_alt": "Nedostupné",
"offline": "Offline",
"offline_alt": "Offline",
"online": "Online",
"total": "Celkom",
"unknown": "Neznáme"
@@ -154,7 +154,7 @@
"uptime": "Dostupnosť",
"maxDown": "Max. sťahovanie",
"maxUp": "Max. nahrávanie",
"down": "Nedostupné",
"down": "Down",
"up": "Beží",
"received": "Prijaté",
"sent": "Odoslané",
@@ -178,19 +178,12 @@
"passes": "Odvysielané"
},
"tautulli": {
"playing": "Prehráva sa",
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Prenosová rýchlosť",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"plex_connection_error": "Skontroluj spojenie s Plex"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Prenosová rýchlosť"
},
"omada": {
"connectedAp": "Pripojené prístupové body",
"activeUser": "Aktívne zariadenia",
@@ -289,14 +282,18 @@
"approved": "Schválené",
"available": "Dostupné"
},
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"jellyseerr": {
"pending": "Čakajúce",
"approved": "Schválené",
"available": "Dostupné",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Čakajúce",
"processing": "Spracovávané",
"approved": "Schválené",
"available": "Dostupné"
},
"netalertx": {
"total": "Celkom",
"connected": "Pripojené",
@@ -432,7 +429,7 @@
"version": "Verzia",
"status": "Stav",
"up": "Online",
"down": "Nedostupné"
"down": "Offline"
},
"miniflux": {
"read": "Prečítané",
@@ -453,7 +450,7 @@
"cpu": "CPU",
"load": "Záťaž",
"wait": "Čakajte, prosím",
"temp": "TEPL",
"temp": "TEMP",
"_temp": "Teplota",
"warn": "Upozornení",
"uptime": "BEŽÍ",
@@ -494,13 +491,13 @@
"51-day": "Mierne mrholenie",
"51-night": "Slabé mrholenie",
"53-day": "Mrholenie",
"53-night": "Mrholenie",
"53-night": "Drizzle",
"55-day": "Silné mrholenie",
"55-night": "Silné mrholenie",
"56-day": "Mierne mrazivé mrholenie",
"56-night": "Jemné mrznúce mrholenie",
"56-night": "Light Freezing Drizzle",
"57-day": "Mrazivé mrholenie",
"57-night": "Mrznúce mrholenie",
"57-night": "Freezing Drizzle",
"61-day": "Slabý dážď",
"61-night": "Slabý dážď",
"63-day": "Dážď",
@@ -545,14 +542,14 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Beží",
"pending": "Čakajúce",
"down": "Nedostupné",
"down": "Down",
"ok": "Ok"
},
"healthchecks": {
"new": "Nový",
"up": "Beží",
"grace": "V dodatočnej lehote",
"down": "Nedostupné",
"down": "Down",
"paused": "Pozastavené",
"status": "Stav",
"last_ping": "Poslendný ping",
@@ -678,7 +675,7 @@
"memory": "Využitie pamäte",
"wanStatus": "Stav WAN",
"up": "Beží",
"down": "Nedostupné",
"down": "Down",
"temp": "Temp",
"disk": "Využitie disku",
"wanIP": "IP adresa WAN"
@@ -779,8 +776,8 @@
"targets_total": "Cieľov spolu"
},
"gatus": {
"up": "Dostupné stránky",
"down": "Nedostupné stránky",
"up": "Sites Up",
"down": "Sites Down",
"uptime": "Dostupnosť"
},
"ghostfolio": {
@@ -802,7 +799,7 @@
},
"whatsupdocker": {
"monitoring": "Monitoring",
"updates": "Aktualizácie"
"updates": "Updates"
},
"calibreweb": {
"books": "Books",
@@ -875,7 +872,7 @@
"uptime": "Dostupnosť",
"cpuLoad": "Záťaž CPU priem. (5m)",
"up": "Beží",
"down": "Nedostupné",
"down": "Down",
"bytesTx": "Prenesených",
"bytesRx": "Prijaté"
},
@@ -884,13 +881,13 @@
"uptime": "Dostupnosť",
"lastDown": "Posledný čas nedostupnosti",
"downDuration": "Trvanie nedostupnosti",
"sitesUp": "Dostupné stránky",
"sitesDown": "Nedostupné stránky",
"sitesUp": "Sites Up",
"sitesDown": "Sites Down",
"paused": "Pozastavené",
"notyetchecked": "Neskontrolované",
"up": "Beží",
"seemsdown": "Javí sa nedostupný",
"down": "Nedostupné",
"down": "Down",
"unknown": "Neznáme"
},
"calendar": {
@@ -1026,17 +1023,17 @@
"last_seen": "Last Seen",
"status": "Stav",
"online": "Online",
"offline": "Nedostupné"
"offline": "Offline"
},
"beszel": {
"name": "Name",
"systems": "Systems",
"up": "Beží",
"down": "Nedostupné",
"down": "Down",
"paused": "Pozastavené",
"pending": "Čakajúce",
"status": "Stav",
"updated": "Aktualizované",
"updated": "Updated",
"cpu": "CPU",
"memory": "RAM",
"disk": "Disk",
@@ -1081,7 +1078,7 @@
"disconnected": "Odpojené",
"updateStatus": "Update",
"update_yes": "Dostupné",
"update_no": "Aktuálne",
"update_no": "Up to Date",
"downloads": "Downloads",
"uploads": "Uploads",
"sharedFiles": "Files"
@@ -1100,7 +1097,7 @@
"total": "Celkom",
"running": "Beží",
"stopped": "Zastavené",
"down": "Nedostupné",
"down": "Down",
"unhealthy": "Nezdravý",
"unknown": "Neznáme",
"servers": "Servery",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "No Active Streams",
"plex_connection_error": "Preveri Plex povezavo"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Povezanih AP",
"activeUser": "Aktivne naprave",
@@ -289,14 +282,18 @@
"approved": "Odobreno",
"available": "Na voljo"
},
"seerr": {
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Procesiram",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -108,14 +108,14 @@
"songs": "Песме"
},
"jellyfin": {
"playing": "Репродукција",
"transcoding": "Транскодирање",
"bitrate": "Проток",
"no_active": "Нема активних стримова",
"movies": "Филмови",
"series": "Серије",
"episodes": "Епизоде",
"songs": "Песме"
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"movies": "Movies",
"series": "Series",
"episodes": "Episodes",
"songs": "Songs"
},
"esphome": {
"offline": "Није на мрежи",
@@ -184,13 +184,6 @@
"no_active": "Нема активних стримова",
"plex_connection_error": "Провери везу са Plex-ом"
},
"tracearr": {
"no_active": "Нема активних стримова",
"streams": "Стримови",
"transcodes": "Транскодирање",
"directplay": "Директно репродуковање",
"bitrate": "Проток"
},
"omada": {
"connectedAp": "Повезани АПи",
"activeUser": "Активни уређаји",
@@ -289,14 +282,18 @@
"approved": "Одобрено",
"available": "Доступно"
},
"seerr": {
"jellyseerr": {
"pending": "На чекању",
"approved": "Одобрено",
"available": "Доступно",
"completed": "Завршено",
"processing": "Обрада",
"issues": "Отворених питања"
},
"overseerr": {
"pending": "На чекању",
"processing": "Обрада",
"approved": "Одобрено",
"available": "Доступно"
},
"netalertx": {
"total": "Укупно",
"connected": "Повезано",
@@ -546,7 +543,7 @@
"up": "Горе",
"pending": "На чекању",
"down": "Доле",
"ok": "Ок"
"ok": "Ok"
},
"healthchecks": {
"new": "Сада",
@@ -719,8 +716,8 @@
"volumeAvailable": "Доступно"
},
"dispatcharr": {
"channels": "Канали",
"streams": "Стримови"
"channels": "Channels",
"streams": "Streams"
},
"mylar": {
"series": "Серије",
@@ -811,10 +808,10 @@
"series": "Серије"
},
"booklore": {
"libraries": "Библиотеке",
"books": "Књиге",
"reading": "Читање",
"finished": "Завршено"
"libraries": "Libraries",
"books": "Books",
"reading": "Reading",
"finished": "Finished"
},
"jdownloader": {
"downloadCount": "Ред",
@@ -1155,30 +1152,24 @@
"artists": "Извођачи"
},
"arcane": {
"containers": "Контејнера",
"images": "Слике",
"image_updates": "Ажурирања слика",
"images_unused": "Неискоришћено",
"environment_required": "ИД окружења је обавезан"
"containers": "Containers",
"images": "Images",
"image_updates": "Image Updates",
"images_unused": "Unused",
"environment_required": "Environment ID Required"
},
"dockhand": {
"running": "Покренуто",
"stopped": "Заустављено",
"cpu": "Процесор",
"memory": "Меморија",
"images": "Слике",
"volumes": "Јачине звука",
"events_today": "Данашњи догађаји",
"pending_updates": "Ажурирања на чекању",
"stacks": "Стекови",
"paused": "Паузирано",
"total": "Укупно",
"environment_not_found": "Окружење није пронађено"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
"running": "Running",
"stopped": "Stopped",
"cpu": "CPU",
"memory": "Memory",
"images": "Images",
"volumes": "Volumes",
"events_today": "Events Today",
"pending_updates": "Pending Updates",
"stacks": "Stacks",
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "No Active Streams",
"plex_connection_error": "Check Plex Connection"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Connected APs",
"activeUser": "Active devices",
@@ -289,14 +282,18 @@
"approved": "Godkända",
"available": "Tillgänglig"
},
"seerr": {
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Processing",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "No Active Streams",
"plex_connection_error": "Check Plex Connection"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Connected APs",
"activeUser": "Active devices",
@@ -289,14 +282,18 @@
"approved": "ఆమోదించబడింది",
"available": "అందుబాటులో వున్నవి"
},
"seerr": {
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Processing",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "No Active Streams",
"plex_connection_error": "Check Plex Connection"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Connected APs",
"activeUser": "Active devices",
@@ -289,14 +282,18 @@
"approved": "Approved",
"available": "Available"
},
"seerr": {
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Processing",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -40,7 +40,7 @@
},
"resources": {
"cpu": "İşlemci",
"mem": "Bellek",
"mem": "MEM",
"total": "Toplam",
"free": "Boş",
"used": "Kullanımda",
@@ -80,7 +80,7 @@
"unhealthy": "Sağlıksız",
"not_found": "Bulunamadı",
"exited": "Kapandı",
"partial": "Kısmi"
"partial": "Parçalı"
},
"ping": {
"error": "Hata",
@@ -93,29 +93,29 @@
"http_status": "HTTPS durumu",
"error": "Hata",
"response": "Yanıt",
"down": "İndirme",
"down": "Çalışmayan",
"up": "Çalışıyor",
"not_available": "Uygun değil"
},
"emby": {
"playing": "Oynatılıyor",
"transcoding": "Dönüştürülüyor",
"bitrate": "Bit Hızı",
"bitrate": "Bit Oranı",
"no_active": "Etkin akış yok",
"movies": "Film",
"series": "Dizi",
"episodes": "Bölüm",
"songs": "Şarkı"
"movies": "Filmler",
"series": "Diziler",
"episodes": "Bölümler",
"songs": "Şarkılar"
},
"jellyfin": {
"playing": "Oynatılıyor",
"transcoding": "Dönüştürülüyor",
"bitrate": "Bit Hızı",
"no_active": "Aktif Yayın Yok",
"movies": "Film",
"series": "Dizi",
"episodes": "Bölüm",
"songs": "Şarkı"
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"movies": "Movies",
"series": "Series",
"episodes": "Episodes",
"songs": "Songs"
},
"esphome": {
"offline": "Çevrimdışı",
@@ -135,8 +135,8 @@
"flood": {
"download": "İndirme",
"upload": "Yükleme",
"leech": "İndirilen",
"seed": "Gönderilen"
"leech": "Tüketici",
"seed": "Sağlayıcı"
},
"freshrss": {
"subscriptions": "Abonelikler",
@@ -152,10 +152,10 @@
"connectionStatusDisconnected": "Bağlı değil",
"connectionStatusConnected": "Bağlı",
"uptime": "Çalışma Süresi",
"maxDown": "Maks. İndirme",
"maxUp": "Maks. Gönderme",
"down": "İndirme",
"up": "Yükleme",
"maxDown": "Max. Indirme",
"maxUp": "Max. Gönderme",
"down": "Çalışmayan",
"up": "Çalışıyor",
"received": "Alınan",
"sent": "Gönderilen",
"externalIPAddress": "Harici IP",
@@ -180,17 +180,10 @@
"tautulli": {
"playing": "Oynatılıyor",
"transcoding": "Dönüştürülüyor",
"bitrate": "Bit Hızı",
"bitrate": "Bit Oranı",
"no_active": "Etkin akış yok",
"plex_connection_error": "Plex Bağlantısı Kontrol Ediliyor"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Bağlı AP'ler",
"activeUser": "Etkin aygıtlar",
@@ -206,7 +199,7 @@
"plex": {
"streams": "Etkin akış",
"albums": "Albümler",
"movies": "Film",
"movies": "Filmler",
"tv": "TV Showları"
},
"sabnzbd": {
@@ -216,20 +209,20 @@
},
"rutorrent": {
"active": "Etkin",
"upload": "Gönderme",
"upload": "Yükleme",
"download": "İndirme"
},
"transmission": {
"download": "İndirme",
"upload": "Gönderme",
"leech": "İndirilen",
"seed": "Gönderilen"
"upload": "Yükleme",
"leech": "Tüketici",
"seed": "Sağlayıcı"
},
"qbittorrent": {
"download": "İndirme",
"upload": "Gönderme",
"leech": "İndirilen",
"seed": "Gönderilen"
"upload": "Yükleme",
"leech": "Tüketici",
"seed": "Sağlayıcı"
},
"qnap": {
"cpuUsage": "İşlemci Kullanımı",
@@ -241,9 +234,9 @@
},
"deluge": {
"download": "İndirme",
"upload": "Gönderme",
"leech": "İndirilen",
"seed": "Gönderilen"
"upload": "Yükleme",
"leech": "Leech",
"seed": "Seed"
},
"develancacheui": {
"cachehitbytes": "Önbellek İsabetli Byte",
@@ -251,14 +244,14 @@
},
"downloadstation": {
"download": "İndirme",
"upload": "Gönderme",
"leech": "İndirilen",
"seed": "Gönderilen"
"upload": "Yükleme",
"leech": "Tüketici",
"seed": "Sağlayıcı"
},
"sonarr": {
"wanted": "İstendi",
"queued": "Kuyrukta",
"series": "Diziler",
"series": "Seriler",
"queue": "Kuyruk",
"unknown": "Bilinmeyen"
},
@@ -266,7 +259,7 @@
"wanted": "İstendi",
"missing": "Eksik",
"queued": "Kuyrukta",
"movies": "Film",
"movies": "Filmler",
"queue": "Kuyruk",
"unknown": "Bilinmeyen"
},
@@ -289,14 +282,18 @@
"approved": "Onaylı",
"available": "Kullanılabilir"
},
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"jellyseerr": {
"pending": "Bekleyen",
"approved": "Onaylı",
"available": "Uygun",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "İşleniyor",
"approved": "Onaylı",
"available": "Uygun"
},
"netalertx": {
"total": "Toplam",
"connected": "Bağlı",
@@ -310,7 +307,7 @@
"gravity": "Gravity"
},
"adguard": {
"queries": "Sorgular",
"queries": "Queries",
"blocked": "Engellenen",
"filtered": "Filtrelendi",
"latency": "Gecikme"
@@ -451,9 +448,9 @@
},
"glances": {
"cpu": "İşlemci",
"load": "Yük",
"load": "Load",
"wait": "Lütfen bekleyin",
"temp": "Sıcaklık",
"temp": "TEMP",
"_temp": "Sıcaklık",
"warn": "Uyarı",
"uptime": "ÇALIŞIYOR",
@@ -466,7 +463,7 @@
"read": "Okundu",
"write": "Yazma",
"gpu": "GPU",
"mem": "Bellek",
"mem": "Hafıza",
"swap": "Swap"
},
"quicklaunch": {
@@ -546,7 +543,7 @@
"up": "Çalışıyor",
"pending": "Bekleyen",
"down": "Çalışmayan",
"ok": "Tamam"
"ok": "Ok"
},
"healthchecks": {
"new": "Yeni",
@@ -601,7 +598,7 @@
"signalStrength": "Sağlamlık",
"signalQuality": "Kalite",
"symbolQuality": "Kalite",
"networkRate": "Bit Hızı",
"networkRate": "Bit Oranı",
"clientIP": "Alıcı"
},
"scrutiny": {
@@ -614,13 +611,13 @@
"total": "Toplam"
},
"pangolin": {
"orgs": "Kuruluşlar",
"sites": "Siteler",
"resources": "Kaynaklar",
"targets": "Hedefler",
"traffic": "Trafik",
"in": "Gelen",
"out": "Giden"
"orgs": "Orgs",
"sites": "Sites",
"resources": "Resources",
"targets": "Targets",
"traffic": "Traffic",
"in": "In",
"out": "Out"
},
"peanut": {
"battery_charge": "Pil Yüzdesi",
@@ -679,7 +676,7 @@
"wanStatus": "WAN Durumu",
"up": "Çalışıyor",
"down": "Çalışmayan",
"temp": "Sıcaklık",
"temp": "Temp",
"disk": "Disk Kullanımı",
"wanIP": "WAN IP"
},
@@ -700,7 +697,7 @@
"down": "Çalışmayan site",
"uptime": "Çalışma süresi",
"incident": "Olay",
"m": "dk"
"m": "m"
},
"atsumeru": {
"series": "Diziler",
@@ -719,8 +716,8 @@
"volumeAvailable": "Uygun"
},
"dispatcharr": {
"channels": "Kanallar",
"streams": "Akışlar"
"channels": "Channels",
"streams": "Streams"
},
"mylar": {
"series": "Diziler",
@@ -774,12 +771,12 @@
"nodes": "Düğümler"
},
"prometheus": {
"targets_up": "Çalışan Hedef",
"targets_up": "Hedef Çalışıyor",
"targets_down": "Çalışmayan hedef",
"targets_total": "Toplam Hedef"
},
"gatus": {
"up": "Çalışan Siteler",
"up": "Sites Up",
"down": "Çalışmayan site",
"uptime": "Çalışma süresi"
},
@@ -787,7 +784,7 @@
"gross_percent_today": "Bugün",
"gross_percent_1y": "Bir yıl",
"gross_percent_max": "Tüm zaman",
"net_worth": "Net Değer"
"net_worth": "Net Worth"
},
"audiobookshelf": {
"podcasts": "Podcast",
@@ -808,13 +805,13 @@
"books": "Kitaplar",
"authors": "Yazarlar",
"categories": "Kategoriler",
"series": "Diziler"
"series": "Seriler"
},
"booklore": {
"libraries": "Kütüphaneler",
"books": "Kitaplar",
"reading": "Okunuyor",
"finished": "Bitti"
"libraries": "Libraries",
"books": "Books",
"reading": "Reading",
"finished": "Finished"
},
"jdownloader": {
"downloadCount": "Kuyruk",
@@ -823,7 +820,7 @@
"downloadSpeed": "Hız"
},
"kavita": {
"seriesCount": "Diziler",
"seriesCount": "Seriler",
"totalFiles": "Dosyalar"
},
"azuredevops": {
@@ -868,7 +865,7 @@
"total": "Toplam",
"running": "Çalışıyor",
"stopped": "Durdu",
"passed": "Başarılı",
"passed": "Passed",
"failed": "Başarısız"
},
"openwrt": {
@@ -877,7 +874,7 @@
"up": "Çalışıyor",
"down": "Çalışmayan",
"bytesTx": "İletilen",
"bytesRx": "Alınan"
"bytesRx": "Received"
},
"uptimerobot": {
"status": "Durum",
@@ -927,7 +924,7 @@
},
"gitea": {
"notifications": "Bildirimler",
"issues": "Sorunlar",
"issues": "Issues",
"pulls": "Değişiklik İstekleri",
"repositories": "Depolar"
},
@@ -1009,21 +1006,21 @@
"lubelogger": {
"vehicle": "Taşıt",
"vehicles": "Taşıtlar",
"serviceRecords": "Servis Kayıtları",
"serviceRecords": "Service Records",
"reminders": "Hatırlatıcılar",
"nextReminder": "Sonraki hatırlatıcı",
"none": "Hiçbiri"
"none": "None"
},
"vikunja": {
"projects": "Etkin projeler",
"tasks7d": "Bitişi Bu Hafta Olan Görevler",
"tasksOverdue": "Gecikmiş Görevler",
"tasksInProgress": "Devam Eden Görevler"
"tasksOverdue": "Overdue Tasks",
"tasksInProgress": "Tasks In Progress"
},
"headscale": {
"name": "Ad",
"address": "Adres",
"last_seen": "Son Görülme",
"last_seen": "Last Seen",
"status": "Durum",
"online": "Çevrimiçi",
"offline": "Çevrimdışı"
@@ -1034,21 +1031,21 @@
"up": "Çalışıyor",
"down": "Çalışmayan",
"paused": "Durduruldu",
"pending": "Beklemede",
"pending": "Pending",
"status": "Durum",
"updated": "Güncellendi",
"cpu": "İşlemci",
"memory": "Bellek",
"disk": "Depolama",
"disk": "Disk",
"network": "NET"
},
"argocd": {
"apps": "Uygulamalar",
"synced": "Senkron",
"outOfSync": "Senkron Değil",
"synced": "Synced",
"outOfSync": "Out Of Sync",
"healthy": "Sağlıklı",
"degraded": "Sorunlu",
"progressing": "Uygulanıyor",
"degraded": "Degraded",
"progressing": "Progressing",
"missing": "Eksik",
"suspended": "Askıya Alındı"
},
@@ -1056,22 +1053,22 @@
"loading": "Yükleniyor"
},
"gitlab": {
"groups": "Gruplar",
"issues": "Sorunlar",
"merges": "Birleştirme İstekleri",
"projects": "Projeler"
"groups": "Groups",
"issues": "Issues",
"merges": "Merge Requests",
"projects": "Projects"
},
"apcups": {
"status": "Durum",
"load": "Yük",
"bcharge": "Pil Yüzdesi",
"load": "Load",
"bcharge": "Battery Charge",
"timeleft": "Kalan zaman"
},
"karakeep": {
"bookmarks": "Yer imleri",
"favorites": "Gözdeler",
"archived": "Arşivlenen",
"highlights": "Öne Çıkanlar",
"archived": "Archived",
"highlights": "Highlights",
"lists": "Listeler",
"tags": "Etiketler"
},
@@ -1087,14 +1084,14 @@
"sharedFiles": "Dosyalar"
},
"jellystat": {
"songs": "Şarkı",
"movies": "Film",
"episodes": "Bölüm",
"songs": "Şarkılar",
"movies": "Filmler",
"episodes": "Bölümler",
"other": "Diğer"
},
"checkmk": {
"serviceErrors": "Hizmet Sorunları",
"hostErrors": "Sunucu Sorunları"
"serviceErrors": "Service issues",
"hostErrors": "Host issues"
},
"komodo": {
"total": "Toplam",
@@ -1104,8 +1101,8 @@
"unhealthy": "Sağlıksız",
"unknown": "Bilinmeyen",
"servers": "Sunucular",
"stacks": "Yığınlar",
"containers": "Konteynerler"
"stacks": "Stacks",
"containers": "Containers"
},
"filebrowser": {
"available": "Uygun",
@@ -1123,11 +1120,11 @@
"STARTED": "Başladı",
"STOPPED": "Durdu",
"NEW_ARRAY": "Yeni dizi",
"RECON_DISK": "Disk Yeniden Oluşturuluyor",
"RECON_DISK": "Reconstructing Disk",
"DISABLE_DISK": "Disk devre dışı",
"SWAP_DSBL": "Swap devre dışı",
"INVALID_EXPANSION": "Geçersiz Genişletme",
"PARITY_NOT_BIGGEST": "Parity En Büyük Disk Değil",
"INVALID_EXPANSION": "Invalid Expansion",
"PARITY_NOT_BIGGEST": "Parity Not Biggest",
"TOO_MANY_MISSING_DISKS": "Çok fazla disk eksik",
"NEW_DISK_TOO_SMALL": "Yeni disk çok küçük",
"NO_DATA_DISKS": "Veri diski yok",
@@ -1142,43 +1139,37 @@
"poolFree": "{{pool}} boş"
},
"backrest": {
"num_plans": "Planlar",
"num_success_30": "Başarılılar",
"num_failure_30": "Başarısızlıklar",
"num_success_latest": "Başarılı",
"num_failure_latest": "Başarısız",
"bytes_added_30": "Eklenen Veri"
"num_plans": "Plans",
"num_success_30": "Successes",
"num_failure_30": "Failures",
"num_success_latest": "Succeeding",
"num_failure_latest": "Failing",
"bytes_added_30": "Bytes Added"
},
"yourspotify": {
"songs": "Şarkılar",
"time": "Zaman",
"artists": "Sanatçılar"
"songs": "Songs",
"time": "Time",
"artists": "Artists"
},
"arcane": {
"containers": "Konteynerler",
"images": "İmajlar",
"image_updates": "İmaj Güncellemeleri",
"images_unused": "Kullanılmayan İmajlar",
"environment_required": "Ortam Kimliği Gerekli"
"containers": "Containers",
"images": "Images",
"image_updates": "Image Updates",
"images_unused": "Unused",
"environment_required": "Environment ID Required"
},
"dockhand": {
"running": "Çalışan",
"stopped": "Durdurulan",
"cpu": "İşlemci",
"memory": "Bellek",
"images": "İmajlar",
"volumes": "Birimler",
"events_today": "Bugünkü Olaylar",
"pending_updates": "Bekleyen Güncellemeler",
"stacks": "Yığınlar",
"paused": "Duraklatılan",
"total": "Toplam",
"environment_not_found": "Ortam Bulunamadı"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
"running": "Running",
"stopped": "Stopped",
"cpu": "CPU",
"memory": "Memory",
"images": "Images",
"volumes": "Volumes",
"events_today": "Events Today",
"pending_updates": "Pending Updates",
"stacks": "Stacks",
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "Немає активних потоків",
"plex_connection_error": "Перевірте з'єднання Plex"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Підключені точки доступу",
"activeUser": "Активні пристрої",
@@ -289,13 +282,17 @@
"approved": "Затверджено",
"available": "Доступно"
},
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
"jellyseerr": {
"pending": "Очікує",
"approved": "Схвалено",
"available": "Доступно",
"issues": "Проблеми до усунення"
},
"overseerr": {
"pending": "Очікує",
"processing": "Обробка",
"approved": "Схвалено",
"available": "Доступно"
},
"netalertx": {
"total": "Усього",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,13 +184,6 @@
"no_active": "No Active Streams",
"plex_connection_error": "Check Plex Connection"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Connected APs",
"activeUser": "Active devices",
@@ -289,14 +282,18 @@
"approved": "Đã duyệt",
"available": "Available"
},
"seerr": {
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Processing",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -108,14 +108,14 @@
"songs": "曲目"
},
"jellyfin": {
"playing": "正在播放",
"transcoding": "轉碼",
"bitrate": "位元率",
"no_active": "無播放活動",
"movies": "電影",
"series": "系列",
"episodes": "劇集",
"songs": "曲目"
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"movies": "Movies",
"series": "Series",
"episodes": "Episodes",
"songs": "Songs"
},
"esphome": {
"offline": "Offline",
@@ -184,13 +184,6 @@
"no_active": "No Active Streams",
"plex_connection_error": "檢查Plex的連接狀態"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "已連接的存取點",
"activeUser": "在線裝置",
@@ -289,14 +282,18 @@
"approved": "批准",
"available": "可用"
},
"seerr": {
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "處理中",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -321,9 +318,9 @@
"ping": "Ping"
},
"portainer": {
"running": "執行中",
"running": "Running",
"stopped": "暫停",
"total": "全部"
"total": "Total"
},
"suwayomi": {
"download": "Downloaded",
@@ -386,7 +383,7 @@
"npm": {
"enabled": "啟用",
"disabled": "停用咗",
"total": "全部"
"total": "Total"
},
"coinmarketcap": {
"configure": "配置一個或多個加密貨幣以進行跟蹤",
@@ -451,19 +448,19 @@
},
"glances": {
"cpu": "CPU",
"load": "負載",
"wait": "請稍候",
"temp": "溫度",
"load": "Load",
"wait": "Please wait",
"temp": "TEMP",
"_temp": "溫度",
"warn": "警告",
"uptime": "運作時間",
"total": "全部",
"free": "剩餘",
"used": "已使用",
"days": "",
"hours": "",
"uptime": "UP",
"total": "Total",
"free": "Free",
"used": "Used",
"days": "d",
"hours": "h",
"crit": "重大的",
"read": "已讀",
"read": "Read",
"write": "寫入",
"gpu": "GPU",
"mem": "記憶體",
@@ -1087,10 +1084,10 @@
"sharedFiles": "Files"
},
"jellystat": {
"songs": "曲目",
"movies": "電影",
"episodes": "劇集",
"other": "其它"
"songs": "Songs",
"movies": "Movies",
"episodes": "Episodes",
"other": "Other"
},
"checkmk": {
"serviceErrors": "Service issues",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -61,7 +61,7 @@
"wlan_devices": "无线局域网设备",
"lan_users": "局域网用户",
"wlan_users": "无线局域网用户",
"up": "在线",
"up": "UP",
"down": "离线",
"wait": "请稍候",
"empty_data": "子系统状态未知"
@@ -108,21 +108,21 @@
"songs": "歌曲"
},
"jellyfin": {
"playing": "播放中",
"transcoding": "转码",
"bitrate": "比特率",
"no_active": "暂无播放",
"movies": "电影",
"series": "系列",
"episodes": "剧集",
"songs": "歌曲"
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"movies": "Movies",
"series": "Series",
"episodes": "Episodes",
"songs": "Songs"
},
"esphome": {
"offline": "离线",
"offline_alt": "离线",
"online": "在线的",
"total": "总计",
"unknown": "未知"
"total": "Total",
"unknown": "Unknown"
},
"evcc": {
"pv_power": "正式环境",
@@ -143,7 +143,7 @@
"unread": "未读"
},
"fritzbox": {
"connectionStatus": "状态",
"connectionStatus": "Status",
"connectionStatusUnconfigured": "未配置",
"connectionStatusConnecting": "连接中",
"connectionStatusAuthenticating": "认证中",
@@ -151,11 +151,11 @@
"connectionStatusDisconnecting": "正在断开连接",
"connectionStatusDisconnected": "未连接",
"connectionStatusConnected": "已连接",
"uptime": "运行时间",
"uptime": "Uptime",
"maxDown": "最大下载速度",
"maxUp": "最大上传速度",
"down": "离线",
"up": "在线",
"down": "Down",
"up": "Up",
"received": "已接收",
"sent": "已发送",
"externalIPAddress": "外部IP",
@@ -178,24 +178,17 @@
"passes": "通行证"
},
"tautulli": {
"playing": "播放中",
"transcoding": "转码",
"bitrate": "比特率",
"no_active": "暂无播放",
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"plex_connection_error": "Check Plex Connection"
},
"tracearr": {
"no_active": "暂无播放",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "比特率"
},
"omada": {
"connectedAp": "连接中的AP",
"activeUser": "活跃设备",
"alerts": "警报",
"connectedGateways": "已连接网关",
"connectedGateways": "Connected gateways",
"connectedSwitches": "已连接开关"
},
"nzbget": {
@@ -210,13 +203,13 @@
"tv": "电视节目"
},
"sabnzbd": {
"rate": "速率",
"rate": "Rate",
"queue": "队列",
"timeleft": "剩余时间"
},
"rutorrent": {
"active": "活动中",
"upload": "上传",
"upload": "Upload",
"download": "下载"
},
"transmission": {
@@ -233,7 +226,7 @@
},
"qnap": {
"cpuUsage": "处理器",
"memUsage": "内存使用",
"memUsage": "内存",
"systemTempC": "系统温度",
"poolUsage": "存储池",
"volumeUsage": "Volume Usage",
@@ -252,7 +245,7 @@
"downloadstation": {
"download": "Download",
"upload": "Upload",
"leech": "",
"leech": "Leech",
"seed": "做种"
},
"sonarr": {
@@ -289,14 +282,18 @@
"approved": "已批准",
"available": "可用"
},
"seerr": {
"pending": "Pending",
"jellyseerr": {
"pending": "待办的",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "处理中",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -321,9 +318,9 @@
"ping": "Ping"
},
"portainer": {
"running": "运行中",
"running": "Running",
"stopped": "停止",
"total": "总计"
"total": "Total"
},
"suwayomi": {
"download": "Downloaded",
@@ -380,13 +377,13 @@
"unknown": "未知"
},
"navidrome": {
"nothing_streaming": "暂无播放",
"nothing_streaming": "",
"please_wait": "请等待"
},
"npm": {
"enabled": "已启用",
"disabled": "禁用",
"total": "总计"
"total": "Total"
},
"coinmarketcap": {
"configure": "配置一个或多个需要追踪的加密",
@@ -409,7 +406,7 @@
},
"jackett": {
"configured": "已配置",
"errored": "出错"
"errored": "Errored"
},
"strelaysrv": {
"numActiveSessions": "会话",
@@ -423,7 +420,7 @@
"domain_count": "域"
},
"medusa": {
"wanted": "",
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
@@ -444,7 +441,7 @@
"failedLoginsLast24H": "登录失败 (24h)"
},
"proxmox": {
"mem": "内存",
"mem": "MEM",
"cpu": "CPU",
"lxc": "容器",
"vms": "虚拟机"
@@ -453,7 +450,7 @@
"cpu": "CPU",
"load": "负载",
"wait": "请稍候",
"temp": "转速",
"temp": "温度",
"_temp": "Temp",
"warn": "Warn",
"uptime": "运行时间",
@@ -463,7 +460,7 @@
"days": "日",
"hours": "时",
"crit": "Crit",
"read": "读取",
"read": "Read",
"write": "写入",
"gpu": "GPU",
"mem": "Mem",
@@ -484,57 +481,57 @@
"1-day": "主要是晴天",
"1-night": "大部晴朗",
"2-day": "多云",
"2-night": "多云",
"2-night": "Partly Cloudy",
"3-day": "阴天",
"3-night": "阴天",
"3-night": "Cloudy",
"45-day": "有雾",
"45-night": "",
"48-day": "",
"48-night": "",
"45-night": "Foggy",
"48-day": "Foggy",
"48-night": "Foggy",
"51-day": "小雨",
"51-night": "小细雨",
"51-night": "Light Drizzle",
"53-day": "小雨",
"53-night": "细雨",
"53-night": "Drizzle",
"55-day": "毛毛雨",
"55-night": "大细雨",
"55-night": "Heavy Drizzle",
"56-day": "小冻毛雨",
"56-night": "小冻毛雨",
"56-night": "Light Freezing Drizzle",
"57-day": "冻毛雨",
"57-night": "冻毛雨",
"57-night": "Freezing Drizzle",
"61-day": "小雨",
"61-night": "小雨",
"61-night": "Light Rain",
"63-day": "雨",
"63-night": "雨天",
"63-night": "Rain",
"65-day": "大雨",
"65-night": "大雨",
"65-night": "Heavy Rain",
"66-day": "冻雨",
"66-night": "冻雨",
"67-day": "冻雨",
"67-night": "冻雨",
"66-night": "Freezing Rain",
"67-day": "Freezing Rain",
"67-night": "Freezing Rain",
"71-day": "小雪",
"71-night": "小雪",
"71-night": "Light Snow",
"73-day": "中雪",
"73-night": "中雪",
"73-night": "Snow",
"75-day": "大雪",
"75-night": "大雪",
"75-night": "Heavy Snow",
"77-day": "雪粒",
"77-night": "雪粒",
"77-night": "Snow Grains",
"80-day": "微阵雨",
"80-night": "小阵雨",
"80-night": "Light Showers",
"81-day": "阵雨",
"81-night": "阵雨",
"81-night": "Showers",
"82-day": "强阵雨",
"82-night": "强阵雨",
"82-night": "Heavy Showers",
"85-day": "阵雪",
"85-night": "阵雪",
"86-day": "阵雪",
"86-night": "阵雪",
"85-night": "Snow Showers",
"86-day": "Snow Showers",
"86-night": "Snow Showers",
"95-day": "雷雨",
"95-night": "雷雨",
"95-night": "Thunderstorm",
"96-day": "雷雨伴随冰雹",
"96-night": "雷雨伴随冰雹",
"99-day": "雷雨伴随冰雹",
"99-night": "雷雨伴随冰雹"
"96-night": "Thunderstorm With Hail",
"99-day": "Thunderstorm With Hail",
"99-night": "Thunderstorm With Hail"
},
"homebridge": {
"available_update": "System",
@@ -690,9 +687,9 @@
"memory_usage": "内存"
},
"immich": {
"users": "用户",
"users": "Users",
"photos": "照片",
"videos": "影片",
"videos": "Videos",
"storage": "储存空间"
},
"uptimekuma": {
@@ -990,8 +987,8 @@
},
"frigate": {
"cameras": "摄像头",
"uptime": "运行时间",
"version": "版本"
"uptime": "Uptime",
"version": "Version"
},
"linkwarden": {
"links": "链接",
@@ -1038,7 +1035,7 @@
"status": "Status",
"updated": "Updated",
"cpu": "CPU",
"memory": "内存",
"memory": "MEM",
"disk": "磁盘",
"network": "网络"
},
@@ -1062,10 +1059,10 @@
"projects": "项目"
},
"apcups": {
"status": "状态",
"load": "负载",
"bcharge": "电池电量",
"timeleft": "剩余供电时间"
"status": "Status",
"load": "Load",
"bcharge": "Battery Charge",
"timeleft": "Time Left"
},
"karakeep": {
"bookmarks": "书签",
@@ -1087,9 +1084,9 @@
"sharedFiles": "Files"
},
"jellystat": {
"songs": "歌曲",
"movies": "电影",
"episodes": "剧集",
"songs": "Songs",
"movies": "Movies",
"episodes": "Episodes",
"other": "其他"
},
"checkmk": {
@@ -1134,8 +1131,8 @@
"notifications": "Notifications",
"status": "Status",
"cpu": "CPU",
"memoryUsed": "已用内存",
"memoryAvailable": "可用内存",
"memoryUsed": "Memory Used",
"memoryAvailable": "Memory Available",
"arrayUsed": "Array Used",
"arrayFree": "Array Free",
"poolUsed": "{{pool}} Used",
@@ -1162,11 +1159,11 @@
"environment_required": "Environment ID Required"
},
"dockhand": {
"running": "运行中",
"stopped": "停止",
"running": "Running",
"stopped": "Stopped",
"cpu": "CPU",
"memory": "内存",
"images": "图片",
"memory": "Memory",
"images": "Images",
"volumes": "Volumes",
"events_today": "Events Today",
"pending_updates": "Pending Updates",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -108,14 +108,14 @@
"songs": "曲目"
},
"jellyfin": {
"playing": "正在播放",
"transcoding": "轉碼",
"bitrate": "位元率",
"no_active": "無播放活動",
"movies": "電影",
"series": "系列",
"episodes": "劇集",
"songs": "曲目"
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"movies": "Movies",
"series": "Series",
"episodes": "Episodes",
"songs": "Songs"
},
"esphome": {
"offline": "Offline",
@@ -184,13 +184,6 @@
"no_active": "No Active Streams",
"plex_connection_error": "檢查Plex的連線狀態"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "已連線的無線網路",
"activeUser": "上線裝置",
@@ -289,14 +282,18 @@
"approved": "已核准",
"available": "可觀看"
},
"seerr": {
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "處理中",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -321,9 +318,9 @@
"ping": "Ping"
},
"portainer": {
"running": "執行中",
"running": "Running",
"stopped": "已停止",
"total": "全部"
"total": "Total"
},
"suwayomi": {
"download": "Downloaded",
@@ -386,7 +383,7 @@
"npm": {
"enabled": "已啟用",
"disabled": "已停用",
"total": "全部"
"total": "Total"
},
"coinmarketcap": {
"configure": "請設定一個或多個欲追蹤的加密貨幣",
@@ -451,19 +448,19 @@
},
"glances": {
"cpu": "CPU",
"load": "負載",
"wait": "請稍候",
"temp": "溫度",
"load": "Load",
"wait": "Please wait",
"temp": "TEMP",
"_temp": "溫度",
"warn": "警告",
"uptime": "運作時間",
"total": "全部",
"free": "剩餘",
"used": "已使用",
"days": "",
"hours": "",
"uptime": "UP",
"total": "Total",
"free": "Free",
"used": "Used",
"days": "d",
"hours": "h",
"crit": "重大的",
"read": "已讀",
"read": "Read",
"write": "寫入",
"gpu": "GPU",
"mem": "記憶體",
@@ -1087,10 +1084,10 @@
"sharedFiles": "Files"
},
"jellystat": {
"songs": "曲目",
"movies": "電影",
"episodes": "劇集",
"other": "其它"
"songs": "Songs",
"movies": "Movies",
"episodes": "Episodes",
"other": "Other"
},
"checkmk": {
"serviceErrors": "Service issues",
@@ -1174,11 +1171,5 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -1,6 +1,6 @@
// @vitest-environment jsdom
import { act, fireEvent, screen } from "@testing-library/react";
import { fireEvent, screen } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import { renderWithProviders } from "test-utils/render-with-providers";
@@ -188,9 +188,7 @@ describe("components/services/item", () => {
// Still rendered while the close animation runs.
expect(screen.getByTestId("docker-widget")).toBeInTheDocument();
act(() => {
vi.advanceTimersByTime(300);
});
await vi.advanceTimersByTimeAsync(300);
expect(screen.queryByTestId("docker-widget")).not.toBeInTheDocument();
vi.useRealTimers();

View File

@@ -6,7 +6,7 @@ import { BlockHighlightContext } from "./highlight-context";
import { evaluateHighlight, getHighlightClass } from "utils/highlights";
export default function Block({ value, highlightValue, label, field }) {
export default function Block({ value, label, field }) {
const { t } = useTranslation();
const highlightConfig = useContext(BlockHighlightContext);
@@ -20,12 +20,12 @@ export default function Block({ value, highlightValue, label, field }) {
}
for (const candidate of candidates) {
const result = evaluateHighlight(candidate, highlightValue ?? value, highlightConfig);
const result = evaluateHighlight(candidate, value, highlightConfig);
if (result) return result;
}
return null;
}, [field, label, value, highlightValue, highlightConfig]);
}, [field, label, value, highlightConfig]);
const highlightClass = useMemo(() => {
if (!highlight?.level) return undefined;

View File

@@ -38,27 +38,4 @@ describe("components/services/widget/block", () => {
expect(el.getAttribute("data-highlight-level")).toBe("danger");
expect(el.className).toContain("danger-class");
});
it("prefers highlightValue over the rendered value for numeric highlighting", () => {
const highlightConfig = {
levels: { warn: "warn-class" },
fields: {
foo: {
numeric: { when: "gt", value: 5, level: "warn" },
},
},
};
const { container } = renderWithProviders(
<BlockHighlightContext.Provider value={highlightConfig}>
<Block label="foo.label" field="foo" value="5.791 ms" highlightValue={5.791} />
</BlockHighlightContext.Provider>,
{ settings: {} },
);
const el = container.querySelector(".service-block");
expect(el).not.toBeNull();
expect(el.getAttribute("data-highlight-level")).toBe("warn");
expect(el.className).toContain("warn-class");
});
});

View File

@@ -1,6 +1,6 @@
// @vitest-environment jsdom
import { act, screen } from "@testing-library/react";
import { screen } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import { renderWithProviders } from "test-utils/render-with-providers";
@@ -21,9 +21,7 @@ describe("components/widgets/datetime", () => {
// `render` wraps in `act`, so effects should flush synchronously.
expect(screen.getByText(expected0)).toBeInTheDocument();
act(() => {
vi.advanceTimersByTime(1000);
});
await vi.advanceTimersByTimeAsync(1000);
const expected1 = new Intl.DateTimeFormat("en-US", format).format(new Date());
expect(screen.getByText(expected1)).toBeInTheDocument();

View File

@@ -619,19 +619,7 @@ export function cleanServiceGroups(groups) {
if (refreshInterval) widget.refreshInterval = refreshInterval;
}
if (type === "calendar") {
if (integrations) {
if (Array.isArray(integrations)) {
widget.integrations = integrations.map((integration) => {
if (!integration || typeof integration !== "object") {
return integration;
}
const { url, ...integrationWithoutUrl } = integration;
return integrationWithoutUrl;
});
} else {
widget.integrations = integrations;
}
}
if (integrations) widget.integrations = integrations;
if (firstDayInWeek) widget.firstDayInWeek = firstDayInWeek;
if (view) widget.view = view;
if (maxEvents) widget.maxEvents = maxEvents;

View File

@@ -369,47 +369,6 @@ describe("utils/config/service-helpers", () => {
expect(widgets.find((w) => w.type === "lubelogger")).toEqual(expect.objectContaining({ vehicleID: 12 }));
});
it("cleanServiceGroups removes calendar integration urls from frontend widget payload", async () => {
const mod = await import("./service-helpers");
const { cleanServiceGroups } = mod;
const rawGroups = [
{
name: "Core",
services: [
{
name: "Calendar",
weight: 100,
widgets: [
{
type: "calendar",
integrations: [
{
type: "ical",
name: "EPL Fixtures",
url: "https://calendar.google.com/calendar/ical/example/public/basic.ics",
color: "purple",
},
],
},
],
},
],
groups: [],
},
];
const cleaned = cleanServiceGroups(rawGroups);
const calendarWidget = cleaned[0].services[0].widgets[0];
expect(calendarWidget.integrations).toEqual([
{
type: "ical",
name: "EPL Fixtures",
color: "purple",
},
]);
});
it("findGroupByName deep-searches and annotates parent", async () => {
const mod = await import("./service-helpers");
const { findGroupByName } = mod;

View File

@@ -1,116 +0,0 @@
import cache from "memory-cache";
import createLogger from "utils/logger";
import { formatApiCall } from "utils/proxy/api-helpers";
import { addCookieToJar, setCookieHeader } from "utils/proxy/cookie-jar";
import { httpProxy } from "utils/proxy/http";
import widgets from "widgets/widgets";
function isSuccessfulLoginResponse(data) {
const json = JSON.parse(data.toString());
return json?.meta?.rc === "ok" || json?.login_time || json?.update_time;
}
async function login({ widget, api, endpoint, csrfToken }) {
const loginUrl = new URL(formatApiCall(api.replace("{prefix}", ""), { endpoint, ...widget }));
const headers = { "Content-Type": "application/json" };
if (csrfToken) {
headers["X-CSRF-TOKEN"] = csrfToken;
}
return httpProxy(loginUrl, {
method: "POST",
body: JSON.stringify({ username: widget.username, password: widget.password, remember: true, rememberMe: true }),
headers,
});
}
export default function createUnifiProxyHandler({
proxyName,
resolveWidget,
resolveRequestContext,
getLoginEndpoint = () => "auth/login",
shouldAttemptLogin = ({ widget }) => !widget.key,
}) {
const prefixCacheKey = `${proxyName}__prefix`;
const logger = createLogger(proxyName);
return async function unifiProxyHandler(req, res) {
const widget = await resolveWidget(req, logger);
const { service, endpoint } = req.query;
if (!widget) {
return res.status(400).json({ error: "Invalid proxy service type" });
}
const api = widgets?.[widget.type]?.api;
if (!api) {
return res.status(403).json({ error: "Service does not support API calls" });
}
const cachedPrefix = cache.get(`${prefixCacheKey}.${service}`);
const {
prefix,
headers = {},
csrfToken: initialCsrfToken,
} = await resolveRequestContext({
cachedPrefix,
logger,
req,
service,
widget,
});
let csrfToken = initialCsrfToken;
cache.put(`${prefixCacheKey}.${service}`, prefix);
widget.prefix = prefix;
const url = new URL(formatApiCall(api, { endpoint, ...widget }));
const params = { method: "GET", headers };
setCookieHeader(url, params);
let [status, contentType, data, responseHeaders] = await httpProxy(url, params);
if (status === 401 && shouldAttemptLogin({ widget, req, responseHeaders })) {
logger.debug("UniFi request was rejected, attempting login.");
if (responseHeaders?.["x-csrf-token"]) {
csrfToken = responseHeaders["x-csrf-token"];
}
[status, contentType, data, responseHeaders] = await login({
api,
csrfToken,
endpoint: getLoginEndpoint({ prefix, req, widget }),
widget,
});
if (status !== 200) {
logger.error("HTTP %d logging in to UniFi. Data: %s", status, data);
return res.status(status).json({ error: { message: `HTTP Error ${status}`, url, data } });
}
if (!isSuccessfulLoginResponse(data)) {
logger.error("Error logging in to UniFi: Data: %s", data);
return res.status(401).end(data);
}
addCookieToJar(url, responseHeaders);
setCookieHeader(url, params);
[status, contentType, data, responseHeaders] = await httpProxy(url, params);
}
if (status !== 200) {
logger.error("HTTP %d getting data from UniFi endpoint %s. Data: %s", status, url.href, data);
return res.status(status).json({ error: { message: `HTTP Error ${status}`, url, data } });
}
if (contentType) {
res.setHeader("Content-Type", contentType);
}
return res.status(status).send(data);
};
}

View File

@@ -37,7 +37,6 @@ export default function Component({ service }) {
<Block
label="adguard.latency"
value={t("common.ms", { value: adguardData.avg_processing_time * 1000, style: "unit", unit: "millisecond" })}
highlightValue={adguardData.avg_processing_time * 1000}
/>
</Container>
);

View File

@@ -51,26 +51,10 @@ export default function Component({ service }) {
<Block label="beszel.name" value={system.name} />
<Block label="beszel.status" value={t(`beszel.${system.status}`)} />
<Block label="beszel.updated" value={t("common.relativeDate", { value: system.updated })} />
<Block
label="beszel.cpu"
value={t("common.percent", { value: system.info.cpu, maximumFractionDigits: 2 })}
highlightValue={system.info.cpu}
/>
<Block
label="beszel.memory"
value={t("common.percent", { value: system.info.mp, maximumFractionDigits: 2 })}
highlightValue={system.info.mp}
/>
<Block
label="beszel.disk"
value={t("common.percent", { value: system.info.dp, maximumFractionDigits: 2 })}
highlightValue={system.info.dp}
/>
<Block
label="beszel.network"
value={t("common.byterate", { value: system.info.bb, maximumFractionDigits: 2 })}
highlightValue={system.info.bb}
/>
<Block label="beszel.cpu" value={t("common.percent", { value: system.info.cpu, maximumFractionDigits: 2 })} />
<Block label="beszel.memory" value={t("common.percent", { value: system.info.mp, maximumFractionDigits: 2 })} />
<Block label="beszel.disk" value={t("common.percent", { value: system.info.dp, maximumFractionDigits: 2 })} />
<Block label="beszel.network" value={t("common.percent", { value: system.info.b, maximumFractionDigits: 2 })} />
</Container>
);
}

View File

@@ -76,35 +76,6 @@ describe("widgets/beszel/component", () => {
expect(screen.queryByText("beszel.updated")).toBeNull();
});
it("renders optional fields", () => {
useWidgetAPI.mockReturnValue({
data: {
totalItems: 1,
items: [
{
id: "sys1",
name: "MySystem",
status: "up",
updated: 123,
info: { cpu: 10, mp: 20, dp: 30, b: 40, bb: 14.5 },
},
],
},
error: undefined,
});
const service = {
widget: { type: "beszel", systemId: "sys1", fields: ["name", "disk", "network"] },
};
const { container } = renderWithProviders(<Component service={service} />, { settings: { hideErrors: false } });
expect(service.widget.fields).toEqual(["name", "disk", "network"]);
expect(container.querySelectorAll(".service-block")).toHaveLength(3);
expectBlockValue(container, "beszel.name", "MySystem");
expectBlockValue(container, "beszel.disk", 30);
expectBlockValue(container, "beszel.network", 14.5);
});
it("renders error when systemId is not found", () => {
useWidgetAPI.mockReturnValue({
data: { totalItems: 1, items: [{ id: "sys1", name: "MySystem", status: "up", info: {} }] },

View File

@@ -73,13 +73,7 @@ export default function Component({ service }) {
?.filter((integration) => integration?.type)
.map((integration) => ({
// Include the extension so Vite/Vitest can statically validate the import base.
service: dynamic(
() =>
import(
/* webpackExclude: /\.test\.jsx$/ */
`./integrations/${integration.type}.jsx`
),
),
service: dynamic(() => import(`./integrations/${integration.type}.jsx`)),
widget: { ...widget, ...integration },
})) ?? [],
[widget],

View File

@@ -25,25 +25,13 @@ async function login(widget, service) {
}),
});
let dataParsed;
try {
dataParsed = JSON.parse(data);
} catch {
logger.error("Failed to parse Crowdsec login response, status: %d", status);
cache.del(`${sessionTokenCacheKey}.${service}`);
return null;
}
const dataParsed = JSON.parse(data);
if (status !== 200 || !dataParsed.token) {
if (!(status === 200) || !dataParsed.token) {
logger.error("Failed to login to Crowdsec API, status: %d", status);
cache.del(`${sessionTokenCacheKey}.${service}`);
return null;
}
const ttl = Math.max(new Date(dataParsed.expire) - new Date(), 1);
cache.put(`${sessionTokenCacheKey}.${service}`, dataParsed.token, ttl);
return dataParsed.token;
cache.put(`${sessionTokenCacheKey}.${service}`, dataParsed.token, new Date(dataParsed.expire) - new Date());
}
export default async function crowdsecProxyHandler(req, res) {
@@ -60,10 +48,11 @@ export default async function crowdsecProxyHandler(req, res) {
return res.status(400).json({ error: "Invalid widget configuration" });
}
let token = cache.get(`${sessionTokenCacheKey}.${service}`);
if (!token) {
token = await login(widget, service);
if (!cache.get(`${sessionTokenCacheKey}.${service}`)) {
await login(widget, service);
}
const token = cache.get(`${sessionTokenCacheKey}.${service}`);
if (!token) {
return res.status(500).json({ error: "Failed to authenticate with Crowdsec" });
}
@@ -82,20 +71,7 @@ export default async function crowdsecProxyHandler(req, res) {
logger.debug("Calling Crowdsec API endpoint: %s", endpoint);
let [status, , data] = await httpProxy(url, params);
if (status === 401) {
logger.debug("Crowdsec API returned 401, refreshing token and retrying request");
cache.del(`${sessionTokenCacheKey}.${service}`);
const refreshedToken = await login(widget, service);
if (!refreshedToken) {
return res.status(500).json({ error: "Failed to authenticate with Crowdsec" });
}
params.headers.Authorization = `Bearer ${refreshedToken}`;
[status, , data] = await httpProxy(url, params);
}
const [status, , data] = await httpProxy(url, params);
if (status !== 200) {
logger.error("Error calling Crowdsec API: %d. Data: %s", status, data);

View File

@@ -89,76 +89,4 @@ describe("widgets/crowdsec/proxy", () => {
expect(res.statusCode).toBe(500);
expect(res.body).toEqual({ error: "Failed to authenticate with Crowdsec" });
});
it("re-authenticates and retries once when API returns 401", async () => {
getServiceWidget.mockResolvedValue({
type: "crowdsec",
url: "http://cs",
username: "machine",
password: "pw",
});
httpProxy
.mockResolvedValueOnce([
200,
"application/json",
JSON.stringify({ token: "tok-old", expire: new Date(Date.now() + 60_000).toISOString() }),
])
.mockResolvedValueOnce([401, "application/json", Buffer.from("bad token")])
.mockResolvedValueOnce([
200,
"application/json",
JSON.stringify({ token: "tok-new", expire: new Date(Date.now() + 60_000).toISOString() }),
])
.mockResolvedValueOnce([200, "application/json", Buffer.from("data")]);
const req = { query: { group: "g", service: "svc", endpoint: "alerts", index: "0" } };
const res = createMockRes();
await crowdsecProxyHandler(req, res);
expect(httpProxy).toHaveBeenCalledTimes(4);
expect(httpProxy.mock.calls[3][1].headers.Authorization).toBe("Bearer tok-new");
expect(res.statusCode).toBe(200);
expect(res.body).toEqual(Buffer.from("data"));
});
it("returns 500 when 401 refresh fails to get a new token", async () => {
getServiceWidget.mockResolvedValue({
type: "crowdsec",
url: "http://cs",
username: "machine",
password: "pw",
});
httpProxy
.mockResolvedValueOnce([
200,
"application/json",
JSON.stringify({ token: "tok-old", expire: new Date(Date.now() + 60_000).toISOString() }),
])
.mockResolvedValueOnce([401, "application/json", Buffer.from("bad token")])
.mockResolvedValueOnce([500, "application/json", JSON.stringify({ error: "no token" })]);
const req = { query: { group: "g", service: "svc", endpoint: "alerts", index: "0" } };
const res = createMockRes();
await crowdsecProxyHandler(req, res);
expect(res.statusCode).toBe(500);
expect(res.body).toEqual({ error: "Failed to authenticate with Crowdsec" });
});
it("returns 500 when login response is not JSON", async () => {
getServiceWidget.mockResolvedValue({ type: "crowdsec", url: "http://cs", username: "machine", password: "pw" });
httpProxy.mockResolvedValueOnce([200, "text/plain", "not-json"]);
const req = { query: { group: "g", service: "svc", endpoint: "alerts", index: "0" } };
const res = createMockRes();
await crowdsecProxyHandler(req, res);
expect(res.statusCode).toBe(500);
expect(res.body).toEqual({ error: "Failed to authenticate with Crowdsec" });
});
});

View File

@@ -52,9 +52,9 @@ export default function Component({ service }) {
<>
<Container service={service}>
<Block label="deluge.leech" value={t("common.number", { value: leech })} />
<Block label="deluge.download" value={t("common.byterate", { value: rateDl })} highlightValue={rateDl} />
<Block label="deluge.download" value={t("common.byterate", { value: rateDl })} />
<Block label="deluge.seed" value={t("common.number", { value: completed })} />
<Block label="deluge.upload" value={t("common.byterate", { value: rateUl })} highlightValue={rateUl} />
<Block label="deluge.upload" value={t("common.byterate", { value: rateUl })} />
</Container>
{widget?.enableLeechProgress &&
leechTorrents.map((queueEntry) => (

View File

@@ -41,19 +41,17 @@ export default function Component({ service }) {
}
const { rxBytes, txBytes } = calculateThroughput(statsData.stats);
const cpuPercent = calculateCPUPercent(statsData.stats);
const usedMemory = calculateUsedMemory(statsData.stats);
return (
<Container service={service}>
<Block label="docker.cpu" value={t("common.percent", { value: cpuPercent })} highlightValue={cpuPercent} />
<Block label="docker.cpu" value={t("common.percent", { value: calculateCPUPercent(statsData.stats) })} />
{statsData.stats.memory_stats.usage && (
<Block label="docker.mem" value={t("common.bytes", { value: usedMemory })} highlightValue={usedMemory} />
<Block label="docker.mem" value={t("common.bytes", { value: calculateUsedMemory(statsData.stats) })} />
)}
{statsData.stats.networks && (
<>
<Block label="docker.rx" value={t("common.bytes", { value: rxBytes })} highlightValue={rxBytes} />
<Block label="docker.tx" value={t("common.bytes", { value: txBytes })} highlightValue={txBytes} />
<Block label="docker.rx" value={t("common.bytes", { value: rxBytes })} />
<Block label="docker.tx" value={t("common.bytes", { value: txBytes })} />
</>
)}
</Container>

View File

@@ -105,16 +105,8 @@ export default function Component({ service }) {
<Block label="dockhand.paused" value={t("common.number", { value: paused ?? 0 })} />
<Block label="dockhand.pending_updates" value={t("common.number", { value: pendingUpdates ?? 0 })} />
<Block label="dockhand.total" value={t("common.number", { value: totalContainers })} />
<Block
label="dockhand.cpu"
value={t("common.percent", { value: cpuPercent, maximumFractionDigits: 1 })}
highlightValue={cpuPercent}
/>
<Block
label="dockhand.memory"
value={t("common.percent", { value: memoryPercent, maximumFractionDigits: 1 })}
highlightValue={memoryPercent}
/>
<Block label="dockhand.cpu" value={t("common.percent", { value: cpuPercent, maximumFractionDigits: 1 })} />
<Block label="dockhand.memory" value={t("common.percent", { value: memoryPercent, maximumFractionDigits: 1 })} />
<Block label="dockhand.images" value={t("common.number", { value: imagesTotal ?? 0 })} />
<Block label="dockhand.volumes" value={t("common.number", { value: volumesTotal ?? 0 })} />
<Block

View File

@@ -33,9 +33,9 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block label="downloadstation.leech" value={t("common.number", { value: leech })} />
<Block label="downloadstation.download" value={t("common.byterate", { value: rateDl })} highlightValue={rateDl} />
<Block label="downloadstation.download" value={t("common.byterate", { value: rateDl })} />
<Block label="downloadstation.seed" value={t("common.number", { value: completed })} />
<Block label="downloadstation.upload" value={t("common.byterate", { value: rateUl })} highlightValue={rateUl} />
<Block label="downloadstation.upload" value={t("common.byterate", { value: rateUl })} />
</Container>
);
}

View File

@@ -25,21 +25,14 @@ export default function Component({ service }) {
);
}
const available = (usage?.total ?? 0) - (usage?.used ?? 0);
return (
<Container service={service}>
<Block label="filebrowser.available" value={t("common.bytes", { value: available })} highlightValue={available} />
<Block
label="filebrowser.used"
value={t("common.bytes", { value: usage?.used ?? 0 })}
highlightValue={usage?.used ?? 0}
/>
<Block
label="filebrowser.total"
value={t("common.bytes", { value: usage?.total ?? 0 })}
highlightValue={usage?.total ?? 0}
label="filebrowser.available"
value={t("common.bytes", { value: (usage?.total ?? 0) - (usage?.used ?? 0) })}
/>
<Block label="filebrowser.used" value={t("common.bytes", { value: usage?.used ?? 0 })} />
<Block label="filebrowser.total" value={t("common.bytes", { value: usage?.total ?? 0 })} />
</Container>
);
}

View File

@@ -45,9 +45,9 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block label="flood.leech" value={t("common.number", { value: leech })} />
<Block label="flood.download" value={t("common.byterate", { value: rateDl })} highlightValue={rateDl} />
<Block label="flood.download" value={t("common.byterate", { value: rateDl })} />
<Block label="flood.seed" value={t("common.number", { value: completed })} />
<Block label="flood.upload" value={t("common.byterate", { value: rateUl })} highlightValue={rateUl} />
<Block label="flood.upload" value={t("common.byterate", { value: rateUl })} />
</Container>
);
}

View File

@@ -47,36 +47,12 @@ export default function Component({ service }) {
<Container service={service}>
<Block label="fritzbox.connectionStatus" value={t(`fritzbox.connectionStatus${fritzboxData.connectionStatus}`)} />
<Block label="fritzbox.uptime" value={t("common.duration", { value: fritzboxData.uptime })} />
<Block
label="fritzbox.maxDown"
value={t("common.byterate", { value: fritzboxData.maxDown / 8, decimals: 1 })}
highlightValue={fritzboxData.maxDown / 8}
/>
<Block
label="fritzbox.maxUp"
value={t("common.byterate", { value: fritzboxData.maxUp / 8, decimals: 1 })}
highlightValue={fritzboxData.maxUp / 8}
/>
<Block
label="fritzbox.down"
value={t("common.byterate", { value: fritzboxData.down, decimals: 1 })}
highlightValue={fritzboxData.down}
/>
<Block
label="fritzbox.up"
value={t("common.byterate", { value: fritzboxData.up, decimals: 1 })}
highlightValue={fritzboxData.up}
/>
<Block
label="fritzbox.received"
value={t("common.bytes", { value: fritzboxData.received })}
highlightValue={fritzboxData.received}
/>
<Block
label="fritzbox.sent"
value={t("common.bytes", { value: fritzboxData.sent })}
highlightValue={fritzboxData.sent}
/>
<Block label="fritzbox.maxDown" value={t("common.byterate", { value: fritzboxData.maxDown / 8, decimals: 1 })} />
<Block label="fritzbox.maxUp" value={t("common.byterate", { value: fritzboxData.maxUp / 8, decimals: 1 })} />
<Block label="fritzbox.down" value={t("common.byterate", { value: fritzboxData.down, decimals: 1 })} />
<Block label="fritzbox.up" value={t("common.byterate", { value: fritzboxData.up, decimals: 1 })} />
<Block label="fritzbox.received" value={t("common.bytes", { value: fritzboxData.received })} />
<Block label="fritzbox.sent" value={t("common.bytes", { value: fritzboxData.sent })} />
<Block label="fritzbox.externalIPAddress" value={fritzboxData.externalIPAddress} />
<Block label="fritzbox.externalIPv6Address" value={fritzboxData.externalIPv6Address} />
<Block label="fritzbox.externalIPv6Prefix" value={fritzboxData.externalIPv6Prefix} />

View File

@@ -58,7 +58,7 @@ export default function Component({ service }) {
<Block label="gamedig.players" value={players} />
<Block label="gamedig.maxPlayers" value={maxPlayers} />
<Block label="gamedig.bots" value={bots} />
<Block label="gamedig.ping" value={ping} highlightValue={serverData.online ? serverData.ping : undefined} />
<Block label="gamedig.ping" value={ping} />
</Container>
);
}

View File

@@ -45,7 +45,7 @@ export default function Component({ service }) {
<Container service={service}>
<Block label="gatus.up" value={t("common.number", { value: sitesUp })} />
<Block label="gatus.down" value={t("common.number", { value: sitesDown })} />
<Block label="gatus.uptime" value={t("common.percent", { value: uptime })} highlightValue={Number(uptime)} />
<Block label="gatus.uptime" value={t("common.percent", { value: uptime })} />
</Container>
);
}

View File

@@ -31,21 +31,12 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block label="jdownloader.downloadCount" value={t("common.number", { value: jdownloaderData.downloadCount })} />
<Block
label="jdownloader.downloadTotalBytes"
value={t("common.bytes", { value: jdownloaderData.totalBytes })}
highlightValue={jdownloaderData.totalBytes}
/>
<Block label="jdownloader.downloadTotalBytes" value={t("common.bytes", { value: jdownloaderData.totalBytes })} />
<Block
label="jdownloader.downloadBytesRemaining"
value={t("common.bytes", { value: jdownloaderData.bytesRemaining })}
highlightValue={jdownloaderData.bytesRemaining}
/>
<Block
label="jdownloader.downloadSpeed"
value={t("common.byterate", { value: jdownloaderData.totalSpeed })}
highlightValue={jdownloaderData.totalSpeed}
/>
<Block label="jdownloader.downloadSpeed" value={t("common.byterate", { value: jdownloaderData.totalSpeed })} />
</Container>
);
}

View File

@@ -43,23 +43,14 @@ export default function Component({ service }) {
return (
<Container service={service}>
{(statsData.stats.cpuLimit && (
<Block
label="docker.cpu"
value={t("common.percent", { value: statsData.stats.cpuUsage })}
highlightValue={statsData.stats.cpuUsage}
/>
<Block label="docker.cpu" value={t("common.percent", { value: statsData.stats.cpuUsage })} />
)) || (
<Block
label="docker.cpu"
value={t("common.number", { value: statsData.stats.cpu, maximumFractionDigits: 4 })}
highlightValue={statsData.stats.cpu}
/>
)}
<Block
label="docker.mem"
value={t("common.bytes", { value: statsData.stats.mem })}
highlightValue={statsData.stats.mem}
/>
<Block label="docker.mem" value={t("common.bytes", { value: statsData.stats.mem })} />
</Container>
);
}

View File

@@ -35,16 +35,8 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block label="mikrotik.uptime" value={statsData.uptime} />
<Block
label="mikrotik.cpuLoad"
value={t("common.percent", { value: statsData["cpu-load"] })}
highlightValue={statsData["cpu-load"]}
/>
<Block
label="mikrotik.memoryUsed"
value={t("common.percent", { value: memoryUsed })}
highlightValue={memoryUsed}
/>
<Block label="mikrotik.cpuLoad" value={t("common.percent", { value: statsData["cpu-load"] })} />
<Block label="mikrotik.memoryUsed" value={t("common.percent", { value: memoryUsed })} />
<Block label="mikrotik.numberOfLeases" value={t("common.number", { value: numberOfLeases })} />
</Container>
);

View File

@@ -54,7 +54,6 @@ export default function Component({ service }) {
style: "unit",
unit: "millisecond",
})}
highlightValue={data[0].ping}
/>
</Container>
);

View File

@@ -56,23 +56,12 @@ export default function Component({ service }) {
return (
<Container service={service}>
{showCpuLoad && (
<Block
label="nextcloud.cpuload"
value={t("common.percent", { value: nextcloudInfo.system.cpuload[0] })}
highlightValue={nextcloudInfo.system.cpuload[0]}
/>
)}
{showMemoryUsage && (
<Block
label="nextcloud.memoryusage"
value={t("common.percent", { value: memoryUsage })}
highlightValue={memoryUsage}
/>
<Block label="nextcloud.cpuload" value={t("common.percent", { value: nextcloudInfo.system.cpuload[0] })} />
)}
{showMemoryUsage && <Block label="nextcloud.memoryusage" value={t("common.percent", { value: memoryUsage })} />}
<Block
label="nextcloud.freespace"
value={t("common.bbytes", { value: nextcloudInfo.system.freespace, maximumFractionDigits: 1 })}
highlightValue={nextcloudInfo.system.freespace}
/>
<Block label="nextcloud.activeusers" value={t("common.number", { value: activeUsers.last24hours })} />
<Block label="nextcloud.numfiles" value={t("common.number", { value: nextcloudInfo.storage.num_files })} />

View File

@@ -27,20 +27,11 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block
label="nzbget.rate"
value={t("common.byterate", { value: statusData.DownloadRate })}
highlightValue={statusData.DownloadRate}
/>
<Block
label="nzbget.remaining"
value={t("common.bytes", { value: statusData.RemainingSizeMB * 1024 * 1024 })}
highlightValue={statusData.RemainingSizeMB * 1024 * 1024}
/>
<Block label="nzbget.rate" value={t("common.byterate", { value: statusData.DownloadRate })} />
<Block label="nzbget.remaining" value={t("common.bytes", { value: statusData.RemainingSizeMB * 1024 * 1024 })} />
<Block
label="nzbget.downloaded"
value={t("common.bytes", { value: statusData.DownloadedSizeMB * 1024 * 1024 })}
highlightValue={statusData.DownloadedSizeMB * 1024 * 1024}
/>
</Container>
);

View File

@@ -6,6 +6,40 @@ const proxyName = "omadaProxyHandler";
const logger = createLogger(proxyName);
function parseOmadaJson(data, { step, status, contentType, url }) {
const body = Buffer.isBuffer(data) ? data.toString() : String(data ?? "");
try {
return JSON.parse(body);
} catch (error) {
logger.debug(
"Failed parsing Omada %s response as JSON (HTTP %d, content-type: %s, url: %s). Body: %s",
step,
status,
contentType ?? "unknown",
url,
body,
);
throw error;
}
}
function isLikelyHtmlResponse(contentType, data) {
const body = Buffer.isBuffer(data) ? data.toString() : String(data ?? "");
return contentType?.includes("text/html") || body.startsWith("<!DOCTYPE") || body.startsWith("<html");
}
function extractCookieHeader(responseHeaders) {
const setCookieHeader = responseHeaders?.["set-cookie"];
if (!setCookieHeader) return undefined;
if (Array.isArray(setCookieHeader)) {
return setCookieHeader.map((cookie) => cookie.split(";")[0]).join("; ");
}
return String(setCookieHeader).split(";")[0];
}
async function login(loginUrl, username, password, controllerVersionMajor) {
const params = {
username,
@@ -20,15 +54,17 @@ async function login(loginUrl, username, password, controllerVersionMajor) {
};
}
const [status, contentType, data] = await httpProxy(loginUrl, {
const [status, contentType, data, responseHeaders] = await httpProxy(loginUrl, {
method: "POST",
cookieHeader: "X-Bypass-Cookie",
body: JSON.stringify(params),
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
});
return [status, JSON.parse(data.toString())];
return [status, contentType, data, extractCookieHeader(responseHeaders)];
}
export default async function omadaProxyHandler(req, res) {
@@ -86,12 +122,18 @@ export default async function omadaProxyHandler(req, res) {
break;
}
const [loginStatus, loginResponseData] = await login(
const [loginStatus, loginContentType, loginData, loginCookieHeader] = await login(
loginUrl,
widget.username,
widget.password,
controllerVersionMajor,
);
const loginResponseData = parseOmadaJson(loginData, {
step: "login",
status: loginStatus,
contentType: loginContentType,
url: loginUrl,
});
if (loginStatus !== 200 || loginResponseData.errorCode > 0) {
return res
@@ -100,11 +142,13 @@ export default async function omadaProxyHandler(req, res) {
}
const { token } = loginResponseData.result;
let omadaCookieHeader = loginCookieHeader;
let sitesUrl;
let body = {};
let params = { token };
let headers = { "Csrf-Token": token };
if (omadaCookieHeader) headers.Cookie = omadaCookieHeader;
let method = "GET";
switch (controllerVersionMajor) {
@@ -134,9 +178,72 @@ export default async function omadaProxyHandler(req, res) {
params,
body: JSON.stringify(body),
headers,
cookieHeader: "X-Bypass-Cookie",
});
const sitesResponseData = JSON.parse(data);
let sitesResponseData;
try {
sitesResponseData = parseOmadaJson(data, {
step: "sites list",
status,
contentType,
url: sitesUrl,
});
} catch (parseError) {
if (!isLikelyHtmlResponse(contentType, data)) {
throw parseError;
}
logger.debug("Received HTML response for Omada sites list; retrying with a fresh login.");
const [retryLoginStatus, retryLoginContentType, retryLoginData, retryLoginCookieHeader] = await login(
loginUrl,
widget.username,
widget.password,
controllerVersionMajor,
);
const retryLoginResponseData = parseOmadaJson(retryLoginData, {
step: "login (retry)",
status: retryLoginStatus,
contentType: retryLoginContentType,
url: loginUrl,
});
if (retryLoginStatus !== 200 || retryLoginResponseData.errorCode > 0) {
return res.status(retryLoginStatus).json({
error: {
message: "Error re-authenticating to Omada controller",
url: loginUrl,
data: retryLoginResponseData,
},
});
}
const retryToken = retryLoginResponseData.result?.token;
omadaCookieHeader = retryLoginCookieHeader;
const retrySitesUrlObj = new URL(sitesUrl);
retrySitesUrlObj.searchParams.set("token", retryToken);
const retrySitesUrl = retrySitesUrlObj.toString();
[status, contentType, data] = await httpProxy(retrySitesUrl, {
method,
params: { token: retryToken },
body: JSON.stringify(body),
headers: {
...headers,
"Csrf-Token": retryToken,
...(omadaCookieHeader ? { Cookie: omadaCookieHeader } : {}),
},
cookieHeader: "X-Bypass-Cookie",
});
sitesResponseData = parseOmadaJson(data, {
step: "sites list (retry)",
status,
contentType,
url: retrySitesUrl,
});
}
if (status !== 200 || sitesResponseData.errorCode > 0) {
logger.debug(`HTTP ${status} getting sites list: ${sitesResponseData.msg}`);
@@ -174,6 +281,7 @@ export default async function omadaProxyHandler(req, res) {
},
};
headers = { "Content-Type": "application/json" };
if (omadaCookieHeader) headers.Cookie = omadaCookieHeader;
params = { token };
[status, contentType, data] = await httpProxy(switchUrl, {
@@ -181,9 +289,15 @@ export default async function omadaProxyHandler(req, res) {
params,
body: JSON.stringify(body),
headers,
cookieHeader: "X-Bypass-Cookie",
});
const switchResponseData = JSON.parse(data);
const switchResponseData = parseOmadaJson(data, {
step: "switch site",
status,
contentType,
url: switchUrl,
});
if (status !== 200 || switchResponseData.errorCode > 0) {
logger.error(`HTTP ${status} getting sites list: ${data}`);
return res.status(status).json({ error: { message: "Error switching site", url: switchUrl, data } });
@@ -197,9 +311,15 @@ export default async function omadaProxyHandler(req, res) {
method: "getGlobalStat",
}),
headers,
cookieHeader: "X-Bypass-Cookie",
});
siteResponseData = JSON.parse(data);
siteResponseData = parseOmadaJson(data, {
step: "global stats",
status,
contentType,
url: statsUrl,
});
if (status !== 200 || siteResponseData.errorCode > 0) {
return res.status(status).json({ error: { message: "Error getting stats", url: statsUrl, data } });
@@ -218,10 +338,17 @@ export default async function omadaProxyHandler(req, res) {
[status, contentType, data] = await httpProxy(siteStatsUrl, {
headers: {
"Csrf-Token": token,
...(omadaCookieHeader ? { Cookie: omadaCookieHeader } : {}),
},
cookieHeader: "X-Bypass-Cookie",
});
siteResponseData = JSON.parse(data);
siteResponseData = parseOmadaJson(data, {
step: "overview stats",
status,
contentType,
url: siteStatsUrl,
});
if (status !== 200 || siteResponseData.errorCode > 0) {
logger.debug(`HTTP ${status} getting stats for site ${widget.site} with message ${siteResponseData.msg}`);
@@ -242,9 +369,16 @@ export default async function omadaProxyHandler(req, res) {
[status, contentType, data] = await httpProxy(alertUrl, {
headers: {
"Csrf-Token": token,
...(omadaCookieHeader ? { Cookie: omadaCookieHeader } : {}),
},
cookieHeader: "X-Bypass-Cookie",
});
const alertResponseData = parseOmadaJson(data, {
step: "alerts",
status,
contentType,
url: alertUrl,
});
const alertResponseData = JSON.parse(data);
activeUser = siteResponseData.result.totalClientNum;
connectedAp = siteResponseData.result.connectedApNum;

View File

@@ -324,4 +324,73 @@ describe("widgets/omada/proxy", () => {
},
});
});
it("retries login when sites list returns HTML", async () => {
getServiceWidget.mockResolvedValue({ url: "http://omada", username: "u", password: "p", site: "Default" });
httpProxy
.mockResolvedValueOnce([
200,
"application/json",
JSON.stringify({ result: { omadacId: "cid", controllerVer: "5.0.0" } }),
])
// initial login
.mockResolvedValueOnce([
200,
"application/json",
Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t1" } })),
])
// sites list unexpectedly returns HTML
.mockResolvedValueOnce([200, "text/html;charset=utf-8", "<!DOCTYPE html><html><body>login</body></html>"])
// retry login
.mockResolvedValueOnce([
200,
"application/json",
Buffer.from(JSON.stringify({ errorCode: 0, result: { token: "t2" } })),
])
// retry sites list works
.mockResolvedValueOnce([
200,
"application/json",
JSON.stringify({ errorCode: 0, result: { data: [{ name: "Default", id: "siteid" }] } }),
])
// overview works
.mockResolvedValueOnce([
200,
"application/json",
JSON.stringify({
errorCode: 0,
result: {
totalClientNum: 11,
connectedApNum: 3,
connectedGatewayNum: 1,
connectedSwitchNum: 2,
},
}),
])
// alerts works
.mockResolvedValueOnce([200, "application/json", JSON.stringify({ errorCode: 0, result: { alertNum: 5 } })]);
const req = { query: { group: "g", service: "svc", index: "0" } };
const res = createMockRes();
await omadaProxyHandler(req, res);
expect(logger.debug).toHaveBeenCalledWith(
"Received HTML response for Omada sites list; retrying with a fresh login.",
);
expect(httpProxy.mock.calls[1][1].cookieHeader).toBe("X-Bypass-Cookie");
expect(httpProxy.mock.calls[2][1].cookieHeader).toBe("X-Bypass-Cookie");
expect(httpProxy.mock.calls[3][1].cookieHeader).toBe("X-Bypass-Cookie");
expect(httpProxy.mock.calls[4][1].cookieHeader).toBe("X-Bypass-Cookie");
expect(res.body).toBe(
JSON.stringify({
connectedAp: 3,
activeUser: 11,
alerts: 5,
connectedGateways: 1,
connectedSwitches: 2,
}),
);
});
});

View File

@@ -21,8 +21,8 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block label="widget.status" value={up ? t("openwrt.up") : t("openwrt.down")} />
<Block label="openwrt.bytesTx" value={t("common.bytes", { value: bytesTx })} highlightValue={bytesTx} />
<Block label="openwrt.bytesRx" value={t("common.bytes", { value: bytesRx })} highlightValue={bytesRx} />
<Block label="openwrt.bytesTx" value={t("common.bytes", { value: bytesTx })} />
<Block label="openwrt.bytesRx" value={t("common.bytes", { value: bytesRx })} />
</Container>
);
}

View File

@@ -36,22 +36,10 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block label="opnsense.cpu" value={t("common.percent", { value: cpu.toFixed(2) })} highlightValue={cpu} />
<Block label="opnsense.cpu" value={t("common.percent", { value: cpu.toFixed(2) })} />
<Block label="opnsense.memory" value={memory} />
{wan && (
<Block
label="opnsense.wanUpload"
value={t("common.bytes", { value: wan["bytes transmitted"] })}
highlightValue={wan["bytes transmitted"]}
/>
)}
{wan && (
<Block
label="opnsense.wanDownload"
value={t("common.bytes", { value: wan["bytes received"] })}
highlightValue={wan["bytes received"]}
/>
)}
{wan && <Block label="opnsense.wanUpload" value={t("common.bytes", { value: wan["bytes transmitted"] })} />}
{wan && <Block label="opnsense.wanDownload" value={t("common.bytes", { value: wan["bytes received"] })} />}
</Container>
);
}

View File

@@ -52,16 +52,8 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block
label="peanut.battery_charge"
value={t("common.percent", { value: upsData.battery_charge })}
highlightValue={upsData.battery_charge}
/>
<Block
label="peanut.ups_load"
value={t("common.percent", { value: upsData.ups_load })}
highlightValue={upsData.ups_load}
/>
<Block label="peanut.battery_charge" value={t("common.percent", { value: upsData.battery_charge })} />
<Block label="peanut.ups_load" value={t("common.percent", { value: upsData.ups_load })} />
<Block label="peanut.ups_status" value={status} />
</Container>
);

View File

@@ -51,25 +51,14 @@ export default function Component({ service }) {
label="pfsense.load"
value={version === 1 ? systemData.data.load_avg[0] : systemData.data.cpu_load_avg[0]}
/>
<Block
label="pfsense.memory"
value={t("common.percent", { value: memUsage.toFixed(2) })}
highlightValue={memUsage}
/>
<Block label="pfsense.memory" value={t("common.percent", { value: memUsage.toFixed(2) })} />
<Block
label="pfsense.temp"
value={t("common.number", { value: systemData.data.temp_c, style: "unit", unit: "celsius" })}
highlightValue={systemData.data.temp_c}
/>
<Block label="pfsense.wanStatus" value={wan.status === "up" ? t("pfsense.up") : t("pfsense.down")} />
{showWanIP && <Block label="pfsense.wanIP" value={wan.ipaddr} />}
{showDiskUsage && (
<Block
label="pfsense.disk"
value={t("common.percent", { value: diskUsage.toFixed(2) })}
highlightValue={diskUsage}
/>
)}
{showDiskUsage && <Block label="pfsense.disk" value={t("common.percent", { value: diskUsage.toFixed(2) })} />}
</Container>
);
}

View File

@@ -67,16 +67,8 @@ export default function Component({ service }) {
<Container service={service}>
<Block label="proxmox.vms" value={`${runningVMs} / ${vms.length}`} />
<Block label="proxmox.lxc" value={`${runningLXC} / ${lxc.length}`} />
<Block
label="resources.cpu"
value={t("common.percent", { value: (usedCpu / maxCpu) * 100 })}
highlightValue={(usedCpu / maxCpu) * 100}
/>
<Block
label="resources.mem"
value={t("common.percent", { value: (usedMemory / maxMemory) * 100 })}
highlightValue={(usedMemory / maxMemory) * 100}
/>
<Block label="resources.cpu" value={t("common.percent", { value: (usedCpu / maxCpu) * 100 })} />
<Block label="resources.mem" value={t("common.percent", { value: (usedMemory / maxMemory) * 100 })} />
</Container>
);
}

View File

@@ -47,22 +47,10 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block
label="proxmoxbackupserver.datastore_usage"
value={t("common.percent", { value: datastoreUsage })}
highlightValue={datastoreUsage}
/>
<Block label="proxmoxbackupserver.datastore_usage" value={t("common.percent", { value: datastoreUsage })} />
<Block label="proxmoxbackupserver.failed_tasks_24h" value={failedTasks} />
<Block
label="proxmoxbackupserver.cpu_usage"
value={t("common.percent", { value: cpuUsage })}
highlightValue={cpuUsage}
/>
<Block
label="proxmoxbackupserver.memory_usage"
value={t("common.percent", { value: memoryUsage })}
highlightValue={memoryUsage}
/>
<Block label="proxmoxbackupserver.cpu_usage" value={t("common.percent", { value: cpuUsage })} />
<Block label="proxmoxbackupserver.memory_usage" value={t("common.percent", { value: memoryUsage })} />
</Container>
);
}

View File

@@ -25,12 +25,8 @@ export default function ProxmoxVM({ service }) {
return (
<Container service={service}>
<Block
label="resources.cpu"
value={t("common.percent", { value: data.cpu * 100 })}
highlightValue={data.cpu * 100}
/>
<Block label="resources.mem" value={t("common.bytes", { value: data.mem })} highlightValue={data.mem} />
<Block label="resources.cpu" value={t("common.percent", { value: data.cpu * 100 })} />
<Block label="resources.mem" value={t("common.bytes", { value: data.mem })} />
</Container>
);
}

View File

@@ -26,11 +26,7 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block
label="pyload.speed"
value={t("common.byterate", { value: pyloadData.speed })}
highlightValue={pyloadData.speed}
/>
<Block label="pyload.speed" value={t("common.byterate", { value: pyloadData.speed })} />
<Block label="pyload.active" value={t("common.number", { value: pyloadData.active })} />
<Block label="pyload.queue" value={t("common.number", { value: pyloadData.queue })} />
<Block label="pyload.total" value={t("common.number", { value: pyloadData.total })} />

View File

@@ -55,6 +55,7 @@ export default function Component({ service }) {
"queuedDL",
"pausedDL",
];
leechTorrents.sort((firstTorrent, secondTorrent) => {
const firstStateIndex = statePriority.indexOf(firstTorrent.state);
const secondStateIndex = statePriority.indexOf(secondTorrent.state);
@@ -68,17 +69,9 @@ export default function Component({ service }) {
<>
<Container service={service}>
<Block label="qbittorrent.leech" value={t("common.number", { value: leech })} />
<Block
label="qbittorrent.download"
value={t("common.bibyterate", { value: rateDl, decimals: 1 })}
highlightValue={rateDl}
/>
<Block label="qbittorrent.download" value={t("common.bibyterate", { value: rateDl, decimals: 1 })} />
<Block label="qbittorrent.seed" value={t("common.number", { value: completed })} />
<Block
label="qbittorrent.upload"
value={t("common.bibyterate", { value: rateUl, decimals: 1 })}
highlightValue={rateUl}
/>
<Block label="qbittorrent.upload" value={t("common.bibyterate", { value: rateUl, decimals: 1 })} />
</Container>
{widget?.enableLeechProgress &&
leechTorrents.map((queueEntry) => (

View File

@@ -46,6 +46,7 @@ describe("widgets/qbittorrent/component", () => {
const service = { widget: { type: "qbittorrent", enableLeechProgress: true } };
const { container } = renderWithProviders(<Component service={service} />, { settings: { hideErrors: false } });
// total=2, completed=1 => leech=1
expectBlockValue(container, "qbittorrent.leech", 1);
expectBlockValue(container, "qbittorrent.seed", 1);
expectBlockValue(container, "qbittorrent.download", 15);

Some files were not shown because too many files have changed in this diff Show More