Merge remote-tracking branch 'forkorigin/main' into features/basic-docker-swarm

This commit is contained in:
Vinay Dawani 2022-12-11 02:42:22 -05:00
commit f51e755216
167 changed files with 7060 additions and 969 deletions

9
.all-contributorsrc Normal file
View File

@ -0,0 +1,9 @@
{
"projectName": "homepage",
"projectOwner": "benphelps",
"files": [
"README.md"
],
"imageSize": 100,
"contributors": []
}

6
.devcontainer/Dockerfile Normal file
View File

@ -0,0 +1,6 @@
ARG VARIANT="16-buster"
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:${VARIANT}
RUN npm install -g pnpm
ENV PATH="${PATH}:./node_modules/.bin"

View File

@ -0,0 +1,27 @@
{
"name": "homepage",
"build": {
"dockerfile": "Dockerfile",
"args": {
"VARIANT": "18-buster"
}
},
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"mhutchie.git-graph",
"streetsidesoftware.code-spell-checker",
],
"settings": {
"eslint.format.enable": true,
"eslint.lintTask.enable": true,
"eslint.packageManager": "pnpm"
}
}
},
"postCreateCommand": ".devcontainer/setup.sh",
"forwardPorts": [
3000
]
}

11
.devcontainer/setup.sh Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/env bash
# Install Node packages
pnpm install
# Copy in skeleton configuration if there is no existing configuration
if [ ! -d "config/" ]; then
echo "Adding skeleton config"
mkdir config/
cp -r src/skeleton/* config
fi

View File

@ -59,6 +59,16 @@ body:
label: Configuration label: Configuration
description: Please provide any relevant service, widget or otherwise related configuration here description: Please provide any relevant service, widget or otherwise related configuration here
render: yaml render: yaml
- type: textarea
id: container-logs
attributes:
label: Container Logs
description: Please review and provide any logs from the container, if relevant
- type: textarea
id: browser-logs
attributes:
label: Browser Logs
description: Please review and provide any relevant logs from the browser, if relevant
- type: textarea - type: textarea
id: other id: other
attributes: attributes:

View File

@ -43,7 +43,7 @@ jobs:
if: github.event_name != 'pull_request' if: github.event_name != 'pull_request'
uses: sigstore/cosign-installer@main uses: sigstore/cosign-installer@main
with: with:
cosign-release: 'v1.11.0' # optional cosign-release: 'v1.13.1' # optional
# Setup QEMU # Setup QEMU
# https://github.com/marketplace/actions/docker-setup-buildx#with-qemu # https://github.com/marketplace/actions/docker-setup-buildx#with-qemu
@ -100,7 +100,7 @@ jobs:
REVISION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }} REVISION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }}
# https://github.com/docker/setup-qemu-action#about # https://github.com/docker/setup-qemu-action#about
# platforms: linux/amd64,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6 # platforms: linux/amd64,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6
platforms: linux/amd64,linux/arm64,linux/arm/v7 platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6
cache-from: type=local,src=/tmp/.buildx-cache cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
@ -109,13 +109,13 @@ jobs:
# repository is public to avoid leaking data. If you would like to publish # repository is public to avoid leaking data. If you would like to publish
# transparency data even for private images, pass --force to cosign below. # transparency data even for private images, pass --force to cosign below.
# https://github.com/sigstore/cosign # https://github.com/sigstore/cosign
- name: Sign the published Docker image # - name: Sign the published Docker image
if: ${{ github.event_name != 'pull_request' }} # if: ${{ github.event_name != 'pull_request' }}
env: # env:
COSIGN_EXPERIMENTAL: "true" # COSIGN_EXPERIMENTAL: "true"
# This step uses the identity token to provision an ephemeral certificate # # This step uses the identity token to provision an ephemeral certificate
# against the sigstore community Fulcio instance. # # against the sigstore community Fulcio instance.
run: echo "${{ steps.meta.outputs.tags }}" | xargs -I {} cosign sign {}@${{ steps.build-and-push.outputs.digest }} # run: echo "${{ steps.meta.outputs.tags }}" | xargs -I {} cosign sign {}@${{ steps.build-and-push.outputs.digest }}
# Temp fix # Temp fix
# https://github.com/docker/build-push-action/issues/252 # https://github.com/docker/build-push-action/issues/252

View File

@ -1,7 +1,7 @@
# syntax = docker/dockerfile:latest # syntax = docker/dockerfile:latest
# Install dependencies only when needed # Install dependencies only when needed
FROM node:current-alpine AS deps FROM docker.io/node:18-alpine AS deps
WORKDIR /app WORKDIR /app
@ -19,7 +19,7 @@ RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store pnpm f
RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store pnpm install -r --offline RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store pnpm install -r --offline
# Rebuild the source code only when needed # Rebuild the source code only when needed
FROM node:current-alpine AS builder FROM docker.io/node:18-alpine AS builder
WORKDIR /app WORKDIR /app
ARG BUILDTIME ARG BUILDTIME
@ -37,7 +37,7 @@ RUN <<EOF
EOF EOF
# Production image, copy all the files and run next # Production image, copy all the files and run next
FROM node:current-alpine AS runner FROM docker.io/node:18-alpine AS runner
LABEL org.opencontainers.image.title "Homepage" LABEL org.opencontainers.image.title "Homepage"
LABEL org.opencontainers.image.description "A self-hosted services landing page, with docker and service integrations." LABEL org.opencontainers.image.description "A self-hosted services landing page, with docker and service integrations."
LABEL org.opencontainers.image.url="https://github.com/benphelps/homepage" LABEL org.opencontainers.image.url="https://github.com/benphelps/homepage"

View File

@ -38,7 +38,7 @@
- Images built for AMD64 (x86_64), ARM64, ARMv7 and ARMv6 - Images built for AMD64 (x86_64), ARM64, ARMv7 and ARMv6
- Supports all Raspberry Pi's, most SBCs & Apple Silicon - Supports all Raspberry Pi's, most SBCs & Apple Silicon
- Full i18n support with automatic language detection - Full i18n support with automatic language detection
- Translations for Catalan, Chinese, Dutch, Finnish, French, German, Hebrew, Hungarian, Norwegian Bokmål, Polish, Portuguese, Portuguese (Brazil), Romanian, Russian, Spanish, Swedish and Yue - Translations for Catalan, Chinese, Dutch, Finnish, French, German, Hebrew, Hungarian, Malay, Norwegian Bokmål, Polish, Portuguese, Portuguese (Brazil), Romanian, Russian, Spanish, Swedish and Yue
- Want to help translate? [Join the Weblate project](https://hosted.weblate.org/engage/homepage/) - Want to help translate? [Join the Weblate project](https://hosted.weblate.org/engage/homepage/)
- Service & Web Bookmarks - Service & Web Bookmarks
- Docker Integration - Docker Integration
@ -47,12 +47,12 @@
- Service Integration - Service Integration
- Sonarr, Radarr, Readarr, Prowlarr, Bazarr, Lidarr, Emby, Jellyfin, Tautulli (Plex) - Sonarr, Radarr, Readarr, Prowlarr, Bazarr, Lidarr, Emby, Jellyfin, Tautulli (Plex)
- Ombi, Overseerr, Jellyseerr, Jackett, NZBGet, SABnzbd, ruTorrent, Transmission, qBittorrent - Ombi, Overseerr, Jellyseerr, Jackett, NZBGet, SABnzbd, ruTorrent, Transmission, qBittorrent
- Portainer, Traefik, Speedtest Tracker, PiHole, AdGuard Home, Nginx Proxy Manager, Gotify, Syncthing Relay Server, Authentic, Proxmox - Portainer, Traefik, Speedtest Tracker, PiHole, AdGuard Home, Nginx Proxy Manager, Gotify, Syncthing Relay Server, Authentik, Proxmox
- Information Providers - Information Providers
- Coin Market Cap, Mastodon - Coin Market Cap, Mastodon
- Information & Utility Widgets - Information & Utility Widgets
- System Stats (Disk, CPU, Memory) - System Stats (Disk, CPU, Memory)
- Weather via WeatherAPI.com or OpenWeatherMap - Weather via [OpenWeatherMap](https://openweathermap.org/) or [Open-Meteo](https://open-meteo.com/)
- Search Bar - Search Bar
- Customizable - Customizable
- 21 theme colors with light and dark mode support - 21 theme colors with light and dark mode support
@ -144,47 +144,17 @@ This is a [Next.js](https://nextjs.org/) application, see their doucmentation fo
## Contributors ## Contributors
Huge thanks to the all the contributors who have helped make this project what it is today! In alphabetical order: <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
- [aidenpwnz](https://github.com/benphelps/homepage/commits?author=aidenpwnz) - Nginx Proxy Manager, Search Bar Widget <!-- markdownlint-restore -->
- [AlexFullmoon](https://github.com/benphelps/homepage/commits?author=AlexFullmoon) - OpenWeatherMap Widget <!-- prettier-ignore-end -->
- [andrii-kryvoviaz](https://github.com/benphelps/homepage/commits?author=andrii-kryvoviaz) - Background opacity option
- [DevPGSV](https://github.com/benphelps/homepage/commits?author=DevPGSV) - Syncthing Relay Server & Mastodon widgets
- [ilusi0n](https://github.com/benphelps/homepage/commits?author=ilusi0n) - Jellyseerr Integration
- [ItsJustMeChris](https://github.com/benphelps/homepage/commits?author=ItsJustMeChris) - Coin Market Cap Widget
- [JazzFisch](https://github.com/benphelps/homepage/commits?author=JazzFisch) - Readarr, Bazarr, Lidarr, SABnzbd, Transmission, qBittorrent, Proxmox Integrations & countless more improvements
- [josways](https://github.com/benphelps/homepage/commits?author=josways) - Baidu search provider
- [mauricio-kalil](https://github.com/benphelps/homepage/commits?author=mauricio-kalil) - Portuguese (Brazil)
- [modem7](https://github.com/benphelps/homepage/commits?author=modem7) - Impvoed Docker Image
- [MountainGod2](https://github.com/benphelps/homepage/discussions/243) - Homepage Logo
- [quod](https://github.com/benphelps/homepage/commits?author=quod) - Fixed Typos
- [schklom](https://github.com/benphelps/homepage/commits?author=schklom) - ARM64, ARMv7 and ARMv6
- [xicopitz](https://github.com/benphelps/homepage/commits?author=xicopitz) - Gotify & Prowlarr Integration
### Translators <!-- ALL-CONTRIBUTORS-LIST:END -->
- [3vilson](https://github.com/benphelps/homepage/commits?author=3vilson) - German
- [4lenz1](https://github.com/benphelps/homepage/commits?author=4lenz1) - Chinese
- [AmadeusGraves](https://github.com/benphelps/homepage/commits?author=AmadeusGraves) - Spanish <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
- [boerniee](https://github.com/benphelps/homepage/commits?author=boerniee) - German [![All Contributors](https://img.shields.io/badge/all_contributors-13-orange.svg?style=flat-square)](#contributors)
- [brunoccr](https://github.com/benphelps/homepage/commits?author=brunoccr) - Portuguese (Brazil) <!-- ALL-CONTRIBUTORS-BADGE:END -->
- [C8opmBM](https://github.com/benphelps/homepage/commits?author=C8opmBM) - Romainian
- [comradekingu](https://github.com/benphelps/homepage/commits?author=comradekingu) - Norwegian Bokmål
- Daniel Varga - German & Hungarian
- [deffcolony](https://github.com/benphelps/homepage/commits?author=deffcolony) - Dutch
- [desolaris](https://github.com/benphelps/homepage/commits?author=desolaris) - Russian
- [ericlokz](https://github.com/benphelps/homepage/commits?author=ericlokz) - Yue
- [FunsKiTo](https://github.com/benphelps/homepage/commits?author=FunsKiTo) - Spanish
- [jackblk](https://github.com/benphelps/homepage/commits?author=jackblk) - Vietnamese
- [juanmanuelbc](https://github.com/benphelps/homepage/commits?author=juanmanuelbc) - Spanish and Catalan
- [ling0412](https://github.com/benphelps/homepage/commits?author=ling0412) - Chinese
- [milotype](https://github.com/benphelps/homepage/commits?author=milotype) - Croatian
- [nicedc](https://github.com/benphelps/homepage/commits?author=nicedc) - Chinese
- [Nonoss117](https://github.com/benphelps/homepage/commits?author=Nonoss117) - French
- [pacoculebras](https://github.com/benphelps/homepage/commits?author=pacoculebras) - Catalan
- [Prilann](https://github.com/benphelps/homepage/commits?author=Prilann) - German
- [psychodracon](https://github.com/benphelps/homepage/commits?author=psychodracon) - Polish
- Sascha Jelinek - German
- [ShlomiPorush](https://github.com/benphelps/homepage/commits?author=ShlomiPorush) - Hebrew
- [SuperDOS](https://github.com/benphelps/homepage/commits?author=SuperDOS) - Swedish
- [kaihu](https://github.com/benphelps/homepage/commits?author=kaihu) - Finnish

View File

@ -103,7 +103,7 @@ module.exports = {
const bits = options.bits ? value : value / 8; const bits = options.bits ? value : value / 8;
const k = 1024; const k = 1024;
const dm = options.decimals ? options.decimals : 0; const dm = options.decimals ? options.decimals : 0;
const sizes = ["Bps", "Kbps", "Mbps", "Gbps", "Tbps", "Pbps", "Ebps", "Zbps", "Ybps"]; const sizes = ["Bps", "KiBps", "MiBps", "GiBps", "TiBps", "PiBps", "EiBps", "ZiBps", "YiBps"];
const i = Math.floor(Math.log(bits) / Math.log(k)); const i = Math.floor(Math.log(bits) / Math.log(k));

View File

@ -0,0 +1,365 @@
{
"widget": {
"missing_type": "نوع القطعة مفقود: {{type}}",
"api_error": "API خطأ",
"status": "الحالة",
"information": "Information",
"url": "URL",
"raw_error": "Raw Error",
"response_data": "Response Data"
},
"weather": {
"current": "الموقع الحالي",
"allow": "اضغط للسماح",
"updating": "جاري التحديث",
"wait": "الرجاء الانتظار"
},
"search": {
"placeholder": "بحث …"
},
"resources": {
"cpu": "المعالج",
"total": "المجموع",
"free": "متاح",
"used": "مستخدم",
"load": "الضغط"
},
"unifi": {
"users": "المستخدمون",
"uptime": "مدة تشغيل النظام",
"days": "ايام",
"wan": "WAN",
"lan": "LAN",
"wlan": "WLAN",
"devices": "الاجهزة",
"lan_devices": "LAN اجهزة",
"wlan_devices": "WLAN احهزة",
"lan_users": "LAN مستخدمين",
"wlan_users": "WLAN مستخدمين",
"up": "اعلي",
"down": "اسفل",
"wait": "الرجاء الانتظار"
},
"wmo": {
"73-day": "Snow",
"0-day": "Sunny",
"0-night": "Clear",
"1-day": "Mainly Sunny",
"1-night": "Mainly Clear",
"2-day": "Partly Cloudy",
"2-night": "Partly Cloudy",
"3-day": "Cloudy",
"3-night": "Cloudy",
"45-day": "Foggy",
"45-night": "Foggy",
"48-day": "Foggy",
"48-night": "Foggy",
"51-day": "Light Drizzle",
"51-night": "Light Drizzle",
"53-day": "Drizzle",
"53-night": "Drizzle",
"55-day": "Heavy Drizzle",
"55-night": "Heavy Drizzle",
"56-day": "Light Freezing Drizzle",
"56-night": "Light Freezing Drizzle",
"57-day": "Freezing Drizzle",
"57-night": "Freezing Drizzle",
"61-day": "Light Rain",
"61-night": "Light Rain",
"63-day": "Rain",
"63-night": "Rain",
"65-day": "Heavy Rain",
"65-night": "Heavy Rain",
"66-day": "Freezing Rain",
"66-night": "Freezing Rain",
"67-day": "Freezing Rain",
"67-night": "Freezing Rain",
"71-day": "Light Snow",
"71-night": "Light Snow",
"73-night": "Snow",
"75-day": "Heavy Snow",
"75-night": "Heavy Snow",
"77-day": "Snow Grains",
"77-night": "Snow Grains",
"80-day": "Light Showers",
"80-night": "Light Showers",
"81-day": "Showers",
"81-night": "Showers",
"82-day": "Heavy Showers",
"82-night": "Heavy Showers",
"85-day": "Snow Showers",
"85-night": "Snow Showers",
"86-day": "Snow Showers",
"86-night": "Snow Showers",
"95-day": "Thunderstorm",
"95-night": "Thunderstorm",
"96-day": "Thunderstorm With Hail",
"96-night": "Thunderstorm With Hail",
"99-day": "Thunderstorm With Hail",
"99-night": "Thunderstorm With Hail"
},
"docker": {
"rx": "RX",
"tx": "TX",
"mem": "الرام",
"cpu": "المعالج",
"offline": "غير متصل",
"error": "Error",
"unknown": "Unknown"
},
"emby": {
"playing": "يعمل الان",
"transcoding": "التحويل",
"bitrate": "معدل البت",
"no_active": "No Active Streams"
},
"changedetectionio": {
"totalObserved": "Total Observed",
"diffsDetected": "Diffs Detected"
},
"tautulli": {
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams"
},
"nzbget": {
"rate": "Rate",
"remaining": "Remaining",
"downloaded": "Downloaded"
},
"plex": {
"streams": "Active Streams",
"movies": "Movies",
"tv": "TV Shows"
},
"sabnzbd": {
"rate": "Rate",
"queue": "Queue",
"timeleft": "Time Left"
},
"rutorrent": {
"active": "Active",
"upload": "Upload",
"download": "Download"
},
"transmission": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"qbittorrent": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"sonarr": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"radarr": {
"wanted": "Wanted",
"missing": "Missing",
"queued": "Queued",
"movies": "Movies"
},
"lidarr": {
"wanted": "Wanted",
"queued": "Queued",
"albums": "Albums"
},
"readarr": {
"wanted": "Wanted",
"queued": "Queued",
"books": "Books"
},
"bazarr": {
"missingEpisodes": "Missing Episodes",
"missingMovies": "Missing Movies"
},
"ombi": {
"pending": "Pending",
"approved": "Approved",
"available": "Available"
},
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available"
},
"overseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"processing": "Processing"
},
"pihole": {
"queries": "Queries",
"blocked": "Blocked",
"gravity": "Gravity"
},
"adguard": {
"queries": "Queries",
"blocked": "Blocked",
"filtered": "Filtered",
"latency": "Latency"
},
"speedtest": {
"upload": "Upload",
"download": "Download",
"ping": "Ping"
},
"portainer": {
"running": "Running",
"stopped": "Stopped",
"total": "Total"
},
"traefik": {
"routers": "Routers",
"services": "Services",
"middleware": "Middleware"
},
"npm": {
"enabled": "Enabled",
"disabled": "Disabled",
"total": "Total"
},
"coinmarketcap": {
"configure": "Configure one or more crypto currencies to track",
"1hour": "1 Hour",
"1day": "1 Day",
"7days": "7 Days",
"30days": "30 Days"
},
"gotify": {
"apps": "Applications",
"clients": "Clients",
"messages": "Messages"
},
"prowlarr": {
"enableIndexers": "Indexers",
"numberOfGrabs": "Grabs",
"numberOfQueries": "Queries",
"numberOfFailGrabs": "Fail Grabs",
"numberOfFailQueries": "Fail Queries"
},
"jackett": {
"configured": "Configured",
"errored": "Errored"
},
"strelaysrv": {
"numActiveSessions": "Sessions",
"numConnections": "Connections",
"dataRelayed": "Relayed",
"transferRate": "Rate"
},
"mastodon": {
"user_count": "Users",
"status_count": "Posts",
"domain_count": "Domains"
},
"authentik": {
"users": "Users",
"loginsLast24H": "Logins (24h)",
"failedLoginsLast24H": "Failed Logins (24h)"
},
"proxmox": {
"mem": "MEM",
"cpu": "CPU",
"lxc": "LXC",
"vms": "VMs"
},
"glances": {
"cpu": "CPU",
"mem": "MEM",
"wait": "Please wait"
},
"quicklaunch": {
"bookmark": "Bookmark",
"service": "Service"
},
"homebridge": {
"available_update": "System",
"updates": "Updates",
"update_available": "Update Available",
"up_to_date": "Up to Date",
"child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}"
},
"watchtower": {
"containers_scanned": "Scanned",
"containers_updated": "Updated",
"containers_failed": "Failed"
},
"autobrr": {
"approvedPushes": "Approved",
"rejectedPushes": "Rejected",
"filters": "Filters",
"indexers": "Indexers"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Videos",
"channels": "Channels",
"playlists": "Playlists"
},
"truenas": {
"load": "System Load",
"uptime": "Uptime",
"alerts": "Alerts",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"pyload": {
"speed": "Speed",
"active": "Active",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"error": "Error",
"ping": "Ping"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"diskstation": {
"leech": "Leech",
"seed": "Seed",
"download": "Download",
"upload": "Upload"
},
"flood": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
}
}

View File

@ -12,7 +12,11 @@
"widget": { "widget": {
"missing_type": "Липсваща приставка: {{type}}", "missing_type": "Липсваща приставка: {{type}}",
"api_error": "API Грешка", "api_error": "API Грешка",
"status": "Статус" "status": "Статус",
"information": "Information",
"url": "URL",
"raw_error": "Raw Error",
"response_data": "Response Data"
}, },
"weather": { "weather": {
"current": "Текущо местоположение", "current": "Текущо местоположение",
@ -51,7 +55,9 @@
"rx": "RX", "rx": "RX",
"tx": "TX", "tx": "TX",
"mem": "MEM", "mem": "MEM",
"cpu": "CPU" "cpu": "CPU",
"error": "Error",
"unknown": "Unknown"
}, },
"emby": { "emby": {
"playing": "Възпроизвежда", "playing": "Възпроизвежда",
@ -125,7 +131,8 @@
"overseerr": { "overseerr": {
"pending": "Pending", "pending": "Pending",
"approved": "Approved", "approved": "Approved",
"available": "Available" "available": "Available",
"processing": "Processing"
}, },
"pihole": { "pihole": {
"queries": "Queries", "queries": "Queries",
@ -281,5 +288,78 @@
"up_to_date": "Up to Date", "up_to_date": "Up to Date",
"child_bridges": "Child Bridges", "child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"autobrr": {
"rejectedPushes": "Rejected",
"filters": "Filters",
"indexers": "Indexers",
"approvedPushes": "Approved"
},
"watchtower": {
"containers_scanned": "Scanned",
"containers_updated": "Updated",
"containers_failed": "Failed"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Videos",
"channels": "Channels",
"playlists": "Playlists"
},
"truenas": {
"load": "System Load",
"uptime": "Uptime",
"alerts": "Alerts",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"pyload": {
"speed": "Speed",
"active": "Active",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"ping": "Ping",
"error": "Error"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"diskstation": {
"seed": "Seed",
"download": "Download",
"upload": "Upload",
"leech": "Leech"
},
"flood": {
"leech": "Leech",
"seed": "Seed",
"download": "Download",
"upload": "Upload"
} }
} }

View File

@ -2,7 +2,11 @@
"widget": { "widget": {
"missing_type": "Falta el tipus de widget: {{type}}", "missing_type": "Falta el tipus de widget: {{type}}",
"api_error": "Error d'API", "api_error": "Error d'API",
"status": "Estat" "status": "Estat",
"information": "Information",
"url": "URL",
"raw_error": "Raw Error",
"response_data": "Response Data"
}, },
"weather": { "weather": {
"allow": "Feu clic per permetre", "allow": "Feu clic per permetre",
@ -41,7 +45,9 @@
"tx": "Transmès", "tx": "Transmès",
"mem": "Memòria", "mem": "Memòria",
"cpu": "Processador", "cpu": "Processador",
"offline": "Fora de línia" "offline": "Fora de línia",
"error": "Error",
"unknown": "Unknown"
}, },
"emby": { "emby": {
"playing": "Reproduint", "playing": "Reproduint",
@ -94,7 +100,8 @@
"overseerr": { "overseerr": {
"pending": "Pendent", "pending": "Pendent",
"approved": "Aprovat", "approved": "Aprovat",
"available": "Disponible" "available": "Disponible",
"processing": "Processing"
}, },
"pihole": { "pihole": {
"queries": "Consultes", "queries": "Consultes",
@ -281,5 +288,78 @@
"up_to_date": "Up to Date", "up_to_date": "Up to Date",
"child_bridges": "Child Bridges", "child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"autobrr": {
"approvedPushes": "Approved",
"rejectedPushes": "Rejected",
"filters": "Filters",
"indexers": "Indexers"
},
"watchtower": {
"containers_scanned": "Scanned",
"containers_updated": "Updated",
"containers_failed": "Failed"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Videos",
"channels": "Channels",
"playlists": "Playlists"
},
"truenas": {
"load": "System Load",
"uptime": "Uptime",
"alerts": "Alerts",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"pyload": {
"speed": "Speed",
"active": "Active",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"error": "Error",
"ping": "Ping"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"seed": "Seed",
"download": "Download",
"upload": "Upload",
"leech": "Leech"
},
"diskstation": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"flood": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
} }
} }

View File

@ -0,0 +1,365 @@
{
"tubearchivist": {
"videos": "Videa",
"channels": "Kanály",
"playlists": "Playlisty",
"downloads": "Fronta"
},
"truenas": {
"load": "Vytížení systému",
"uptime": "Doba spuštění",
"alerts": "Upozornění",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"widget": {
"missing_type": "Chybí typ widgetu: {{type}}",
"api_error": "Chyba API",
"status": "Status",
"information": "Information",
"url": "URL",
"raw_error": "Raw Error",
"response_data": "Response Data"
},
"weather": {
"current": "Aktuální poloha",
"allow": "Klikni pro povolení",
"updating": "Probíhá aktualizace",
"wait": "Počkejte prosím"
},
"search": {
"placeholder": "Hledat…"
},
"resources": {
"cpu": "CPU",
"total": "Celkem",
"free": "Volné",
"used": "Využité",
"load": "Vytížení"
},
"unifi": {
"users": "Uživatelé",
"uptime": "Čas od startu systému",
"days": "Dnů",
"wan": "WAN",
"lan": "LAN",
"wlan": "WLAN",
"devices": "Zařízení",
"lan_devices": "LAN Zařízení",
"wlan_devices": "WLAN Zařízení",
"lan_users": "LAN Uživatelé",
"wlan_users": "WLAN Uživatelé",
"up": "BĚŽÍ",
"down": "NEBĚŽÍ",
"wait": "Počkejte prosím"
},
"docker": {
"rx": "RX",
"tx": "TX",
"mem": "RAM",
"cpu": "CPU",
"offline": "Offline",
"error": "Error",
"unknown": "Unknown"
},
"emby": {
"playing": "Přehrává",
"transcoding": "Transkódování",
"bitrate": "Bitrate",
"no_active": "Žádný aktivní stream"
},
"changedetectionio": {
"totalObserved": "Celkem zjištěno",
"diffsDetected": "Rozdíly detekovány"
},
"tautulli": {
"playing": "Přehrává",
"transcoding": "Transkódování",
"bitrate": "Bitrate",
"no_active": "Žádný aktivní stream"
},
"nzbget": {
"rate": "Rychlost",
"remaining": "Zbývá",
"downloaded": "Staženo"
},
"plex": {
"streams": "Aktivní streamy",
"movies": "Filmy",
"tv": "Seriály"
},
"sabnzbd": {
"rate": "Rychlost",
"queue": "Fronta",
"timeleft": "Zbývající čas"
},
"rutorrent": {
"active": "Aktivní",
"upload": "Nahrávání",
"download": "Stahování"
},
"transmission": {
"download": "Stahování",
"upload": "Nahrávání",
"leech": "Leecher",
"seed": "Seeder"
},
"qbittorrent": {
"download": "Stahování",
"upload": "Nahrávání",
"leech": "Leecher",
"seed": "Seeder"
},
"sonarr": {
"wanted": "Hledaný",
"queued": "Ve frontě",
"series": "Seriály"
},
"radarr": {
"wanted": "Hledaný",
"missing": "Chybějící",
"queued": "Ve frontě",
"movies": "Filmy"
},
"lidarr": {
"wanted": "Hledaný",
"queued": "Ve frontě",
"albums": "Alba"
},
"readarr": {
"wanted": "Hledaný",
"queued": "Ve frontě",
"books": "Knihy"
},
"bazarr": {
"missingEpisodes": "Chybějící epizody",
"missingMovies": "Chybějící filmy"
},
"ombi": {
"pending": "Čeká",
"approved": "Schváleno",
"available": "Dostupný"
},
"jellyseerr": {
"pending": "Čeká",
"approved": "Schváleno",
"available": "Dostupný"
},
"overseerr": {
"pending": "Čeká",
"approved": "Schváleno",
"available": "Dostupný",
"processing": "Processing"
},
"pihole": {
"queries": "Dotazy",
"blocked": "Blokováno",
"gravity": "Gravitace"
},
"adguard": {
"queries": "Dotazy",
"blocked": "Blokováno",
"filtered": "Filtrováno",
"latency": "Odezva"
},
"speedtest": {
"upload": "Nahrávání",
"download": "Stahování",
"ping": "Ping"
},
"portainer": {
"running": "Běží",
"stopped": "Zastaveno",
"total": "Celkově"
},
"traefik": {
"routers": "Routery",
"services": "Služby",
"middleware": "Prostředník"
},
"npm": {
"enabled": "Povoleno",
"disabled": "Zakázáno",
"total": "Celkově"
},
"coinmarketcap": {
"configure": "Nakonfigurujte alespoň jednu crypto měnu ke sledování",
"1hour": "1 Hodina",
"1day": "1 Den",
"7days": "7 Dní",
"30days": "30 Dní"
},
"wmo": {
"1-night": "Převážně jasno",
"2-day": "Polojasno",
"0-day": "Slunečno",
"0-night": "Jasno",
"1-day": "Převážně slunečno",
"2-night": "Polojasno",
"3-day": "Oblačno",
"3-night": "Oblačno",
"45-day": "Mlha",
"45-night": "Mlha",
"48-day": "Mlha",
"48-night": "Mlha",
"51-day": "Lehké mrholení",
"53-day": "Mrholení",
"53-night": "Mrholení",
"55-day": "Silné mrholení",
"55-night": "Silné mrholení",
"56-day": "Mírné mrznoucí mrholení",
"56-night": "Mírné mrznoucí mrholení",
"57-day": "Mrznoucí mrholení",
"57-night": "Mrznoucí mrholení",
"61-day": "Slabý déšť",
"61-night": "Slabý déšť",
"51-night": "Lehké mrholení",
"63-day": "Déšť",
"63-night": "Déšť",
"65-day": "Silný déšť",
"65-night": "Silný déšť",
"66-day": "Mrznoucí déšť",
"66-night": "Mrznoucí déšť",
"67-day": "Mrznoucí déšť",
"67-night": "Mrznoucí déšť",
"71-day": "Slabé sněžení",
"73-night": "Sněžení",
"75-day": "Silné sněžení",
"75-night": "Silné sněžení",
"77-day": "Sněhová zrna",
"71-night": "Slabé sněžení",
"73-day": "Sněžení",
"77-night": "Sněhová zrna",
"80-day": "Lehké přeháňky",
"80-night": "Lehké přeháňky",
"81-day": "Přeháňky",
"81-night": "Přeháňky",
"82-day": "Silné přeháňky",
"82-night": "Silné přeháňky",
"85-day": "Déšť se sněhem",
"85-night": "Déšť se sněhem",
"86-day": "Déšť se sněhem",
"86-night": "Déšť se sněhem",
"95-day": "Bouřka",
"95-night": "Bouřka",
"96-day": "Bouřka s krupobitím",
"96-night": "Bouřka s krupobitím",
"99-day": "Bouřka s krupobitím",
"99-night": "Bouřka s krupobitím"
},
"gotify": {
"apps": "Aplikace",
"clients": "Klienti",
"messages": "Zprávy"
},
"prowlarr": {
"enableIndexers": "Indexery",
"numberOfGrabs": "Uchopení",
"numberOfQueries": "Dotazy",
"numberOfFailGrabs": "Neúspěšné uchopení",
"numberOfFailQueries": "Neúspěšné dotazy"
},
"jackett": {
"configured": "Konfigurováno",
"errored": "Chybné"
},
"strelaysrv": {
"numActiveSessions": "Sezení",
"numConnections": "Připojení",
"dataRelayed": "Přenášení",
"transferRate": "Tempo"
},
"mastodon": {
"user_count": "Uživatelé",
"status_count": "Příspěvky",
"domain_count": "Domény"
},
"authentik": {
"users": "Uživatelé",
"loginsLast24H": "Příhlášení (24h)",
"failedLoginsLast24H": "Neúspěšná přihlášení (24h)"
},
"proxmox": {
"mem": "RAM",
"cpu": "CPU",
"lxc": "LXC",
"vms": "Virtuální Stroje"
},
"glances": {
"cpu": "CPU",
"mem": "RAM",
"wait": "Prosím počkejte"
},
"quicklaunch": {
"bookmark": "Záložka",
"service": "Služba"
},
"homebridge": {
"update_available": "Dostupná aktualizace",
"up_to_date": "Aktuální",
"available_update": "Systém",
"updates": "Aktualizace",
"child_bridges": "Podřadné můstky",
"child_bridges_status": "{{ok}}/{{total}}"
},
"watchtower": {
"containers_scanned": "Naskenováno",
"containers_updated": "Aktualizováno",
"containers_failed": "Chyba"
},
"autobrr": {
"approvedPushes": "Schváleno",
"rejectedPushes": "Zamítnuto",
"filters": "Filtry",
"indexers": "Indexery"
},
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"pyload": {
"speed": "Speed",
"active": "Active",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"error": "Error",
"ping": "Ping"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"upload": "Upload",
"leech": "Leech",
"seed": "Seed",
"download": "Download"
},
"diskstation": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"flood": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
}
}

View File

@ -0,0 +1,365 @@
{
"plex": {
"movies": "Film",
"tv": "TV-Shows",
"streams": "Aktive Streams"
},
"radarr": {
"queued": "I Kø",
"movies": "Film",
"wanted": "Ønskede",
"missing": "Mangler"
},
"lidarr": {
"wanted": "Ønsket",
"queued": "I Kø",
"albums": "Albums"
},
"jellyseerr": {
"available": "Tilgængelig",
"pending": "Afventer",
"approved": "Godkendt"
},
"overseerr": {
"pending": "Afventer",
"approved": "Godkendt",
"available": "Tilgængelig",
"processing": "Processing"
},
"adguard": {
"queries": "Forespørgsler",
"blocked": "Blokerede",
"filtered": "Filtreret",
"latency": "Latency"
},
"speedtest": {
"upload": "Upload",
"download": "Download",
"ping": "Ping"
},
"npm": {
"total": "Total",
"enabled": "Aktiveret",
"disabled": "Deaktiveret"
},
"coinmarketcap": {
"30days": "30 Dage",
"1day": "1 Dag",
"configure": "Konfigurer en eller flere crypto valutaer til tracking",
"7days": "7 Dage",
"1hour": "1 time"
},
"strelaysrv": {
"numActiveSessions": "Sessioner",
"dataRelayed": "Videresendt",
"numConnections": "Forbindelser",
"transferRate": "Rate"
},
"mastodon": {
"domain_count": "Domæner",
"status_count": "Indlæg",
"user_count": "Brugere"
},
"authentik": {
"users": "Brugere",
"loginsLast24H": "Login (24 timer)",
"failedLoginsLast24H": "Mislykkede logins (24 timer)"
},
"glances": {
"cpu": "CPU",
"mem": "RAM",
"wait": "Vent venligst"
},
"wmo": {
"1-day": "Hovedsageligt solrigt",
"48-day": "Tåget",
"48-night": "Tåget",
"51-day": "Let støvregn",
"51-night": "Let støvregn",
"66-night": "Frysende regn",
"67-day": "Frysende regn",
"67-night": "Frysende regn",
"71-day": "Let Sne",
"75-night": "Kraftig Sne",
"86-day": "Snebyger",
"86-night": "Snebyger",
"95-day": "Tordenvejr",
"99-day": "Tordenvejr med hagl",
"99-night": "Tordenvejr med hagl",
"0-day": "Solrig",
"0-night": "Klart",
"1-night": "Hovedsageligt klart",
"2-day": "Delvist skyet",
"2-night": "Delvist skyet",
"3-day": "Skyet",
"3-night": "Skyet",
"45-day": "Tåget",
"65-day": "Kraftig regn",
"65-night": "Kraftig regn",
"45-night": "Tåget",
"53-day": "Støvregn",
"53-night": "Støvregn",
"55-day": "Kraftig støvregn",
"55-night": "Kraftig støvregn",
"56-day": "Let frysende støvregn",
"56-night": "Let frysende støvregn",
"57-day": "Frysende støvregn",
"57-night": "Frysende støvregn",
"61-day": "Let Regn",
"61-night": "Let Regn",
"63-day": "Regn",
"63-night": "Regn",
"66-day": "Frysende regn",
"71-night": "Let Sne",
"73-day": "Sne",
"73-night": "Sne",
"75-day": "Kraftig Sne",
"77-day": "Snekorn",
"80-day": "Lette byger",
"80-night": "Lette byger",
"81-day": "Byger",
"77-night": "Snekorn",
"81-night": "Byger",
"82-day": "Kraftige Byger",
"82-night": "Kraftige Byger",
"85-day": "Snebyger",
"85-night": "Snebyger",
"95-night": "Tordenvejr",
"96-day": "Tordenvejr med hagl",
"96-night": "Tordenvejr med hagl"
},
"homebridge": {
"available_update": "System",
"updates": "Opdateringer",
"update_available": "Opdateringer tilgængelige",
"up_to_date": "Opdateret",
"child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}"
},
"widget": {
"missing_type": "Manglende Widget Type: {{type}}",
"api_error": "API fejl",
"status": "Status",
"information": "Information",
"url": "URL",
"raw_error": "Raw Error",
"response_data": "Response Data"
},
"weather": {
"current": "Nuværende lokation",
"allow": "Klik for at tillade",
"updating": "Opdaterer",
"wait": "Vent venligst"
},
"search": {
"placeholder": "Søg…"
},
"resources": {
"cpu": "CPU",
"total": "Total",
"free": "Fri",
"used": "Brugt",
"load": "Belastning"
},
"unifi": {
"users": "Brugere",
"uptime": "System Oppetid",
"days": "Dage",
"wan": "WAN",
"lan": "LAN",
"wlan": "Wifi",
"devices": "Enheder",
"lan_devices": "LAN Enheder",
"wlan_devices": "WLAN Enheder",
"lan_users": "LAN Brugere",
"wlan_users": "WLAN Brugere",
"up": "Oppe",
"down": "NED",
"wait": "Vent venligst"
},
"docker": {
"cpu": "CPU",
"rx": "RX",
"tx": "TX",
"mem": "RAM",
"offline": "Offline",
"error": "Error",
"unknown": "Unknown"
},
"emby": {
"playing": "Afspiller",
"transcoding": "Transcoder",
"bitrate": "Bitrate",
"no_active": "Ingen Aktive Streams"
},
"changedetectionio": {
"totalObserved": "Total Observeret",
"diffsDetected": "Forskelle Detekteret"
},
"tautulli": {
"playing": "Afspiller",
"transcoding": "Transcoder",
"bitrate": "Bitrate",
"no_active": "Ingen Aktive Streams"
},
"nzbget": {
"rate": "Rate",
"remaining": "Manglende",
"downloaded": "Hentet"
},
"sabnzbd": {
"rate": "Rate",
"queue": "Kø",
"timeleft": "Resterende tid"
},
"rutorrent": {
"active": "Aktive",
"upload": "Upload",
"download": "Download"
},
"transmission": {
"upload": "Upload",
"download": "Download",
"leech": "Leech",
"seed": "Seed"
},
"qbittorrent": {
"upload": "Upload",
"download": "Download",
"leech": "Leech",
"seed": "Seed"
},
"sonarr": {
"wanted": "Ønsket",
"queued": "I Kø",
"series": "Serier"
},
"readarr": {
"wanted": "Ønskede",
"queued": "I Kø",
"books": "Bøger"
},
"bazarr": {
"missingEpisodes": "Manglende Afsnit",
"missingMovies": "Manglende Film"
},
"ombi": {
"pending": "Afventer",
"approved": "Godkendt",
"available": "Tilgængelig"
},
"pihole": {
"blocked": "Blokerede",
"gravity": "Gravity",
"queries": "Forespørgsler"
},
"portainer": {
"running": "Kørende",
"stopped": "Stoppede",
"total": "Total"
},
"traefik": {
"routers": "Routere",
"services": "Services",
"middleware": "Middleware"
},
"gotify": {
"apps": "Applikationer",
"clients": "Klienter",
"messages": "Beskeder"
},
"prowlarr": {
"enableIndexers": "Indeksører",
"numberOfGrabs": "Grabs",
"numberOfQueries": "Forespørgsler",
"numberOfFailGrabs": "Fail Grabs",
"numberOfFailQueries": "Fejl forespørgsler"
},
"jackett": {
"configured": "Konfigureret",
"errored": "Fejlede"
},
"proxmox": {
"mem": "RAM",
"cpu": "CPU",
"lxc": "LXC",
"vms": "VMs"
},
"quicklaunch": {
"bookmark": "Bogmærker",
"service": "Service"
},
"watchtower": {
"containers_scanned": "Scannet",
"containers_updated": "Opdateret",
"containers_failed": "Fejlet"
},
"autobrr": {
"indexers": "Indeksører",
"approvedPushes": "Godkendte",
"rejectedPushes": "Afviste",
"filters": "Filtre"
},
"tubearchivist": {
"downloads": "Kø",
"videos": "Videoer",
"channels": "Kanaler",
"playlists": "Afspilningslister"
},
"truenas": {
"load": "Systembelastning",
"uptime": "Oppetid",
"alerts": "Advarsler",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "Ingen Aktive Streams",
"please_wait": "Vent venligst"
},
"pyload": {
"speed": "Hastighed",
"active": "Aktive",
"queue": "Kø",
"total": "Total"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"error": "Error",
"ping": "Ping"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"diskstation": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"flood": {
"leech": "Leech",
"download": "Download",
"upload": "Upload",
"seed": "Seed"
}
}

View File

@ -2,7 +2,11 @@
"widget": { "widget": {
"missing_type": "Fehlender Widget-Typ: {{type}}", "missing_type": "Fehlender Widget-Typ: {{type}}",
"api_error": "API-Fehler", "api_error": "API-Fehler",
"status": "Status" "status": "Status",
"url": "URL",
"information": "Information",
"raw_error": "Raw Error",
"response_data": "Response Data"
}, },
"search": { "search": {
"placeholder": "Suche…" "placeholder": "Suche…"
@ -19,7 +23,9 @@
"tx": "Tx", "tx": "Tx",
"mem": "Mem", "mem": "Mem",
"cpu": "Prozessor", "cpu": "Prozessor",
"offline": "Offline" "offline": "Offline",
"error": "Error",
"unknown": "Unknown"
}, },
"emby": { "emby": {
"playing": "Spielen", "playing": "Spielen",
@ -47,7 +53,7 @@
"wanted": "Gesucht", "wanted": "Gesucht",
"queued": "In Warteschlange", "queued": "In Warteschlange",
"movies": "Filme", "movies": "Filme",
"missing": "Missing" "missing": "Fehlt"
}, },
"readarr": { "readarr": {
"wanted": "Gesucht", "wanted": "Gesucht",
@ -98,7 +104,8 @@
"overseerr": { "overseerr": {
"pending": "Ausstehend", "pending": "Ausstehend",
"approved": "Genehmigt", "approved": "Genehmigt",
"available": "Verfügbar" "available": "Verfügbar",
"processing": "Processing"
}, },
"sabnzbd": { "sabnzbd": {
"rate": "Geschwindigkeit", "rate": "Geschwindigkeit",
@ -194,9 +201,9 @@
"wait": "Bitte warten", "wait": "Bitte warten",
"lan": "LAN", "lan": "LAN",
"wlan": "WLAN", "wlan": "WLAN",
"devices": "Devices", "devices": "Geräte",
"lan_devices": "LAN Devices", "lan_devices": "LAN-Geräte",
"wlan_devices": "WLAN Devices" "wlan_devices": "WLAN Geräte"
}, },
"plex": { "plex": {
"streams": "Aktive Streams", "streams": "Aktive Streams",
@ -204,82 +211,155 @@
"tv": "TV Sendungen" "tv": "TV Sendungen"
}, },
"glances": { "glances": {
"cpu": "CPU", "cpu": "Prozessor",
"mem": "RAM", "mem": "RAM",
"wait": "Bitte warten" "wait": "Bitte warten"
}, },
"changedetectionio": { "changedetectionio": {
"totalObserved": "Total Observed", "totalObserved": "Gesamt beobachtet",
"diffsDetected": "Diffs Detected" "diffsDetected": "Erkannte Differenzen"
}, },
"wmo": { "wmo": {
"0-day": "Sunny", "0-day": "Sonnig",
"0-night": "Clear", "0-night": "Klar",
"1-day": "Mainly Sunny", "1-day": "Überwiegend sonnig",
"1-night": "Mainly Clear", "1-night": "Überwiegend klar",
"2-day": "Partly Cloudy", "2-day": "Teilweise bewölkt",
"2-night": "Partly Cloudy", "2-night": "Teilweise bewölkt",
"3-day": "Cloudy", "3-day": "bewölkt",
"57-day": "Freezing Drizzle", "57-day": "Gefrierender Nieselregen",
"61-day": "Light Rain", "61-day": "Leichter Regen",
"65-night": "Heavy Rain", "65-night": "Starker Regen",
"66-day": "Freezing Rain", "66-day": "Gefrierender Regen",
"66-night": "Freezing Rain", "66-night": "Gefrierender Regen",
"3-night": "Cloudy", "3-night": "Bewölkt",
"45-day": "Foggy", "45-day": "Neblig",
"45-night": "Foggy", "45-night": "Neblig",
"48-day": "Foggy", "48-day": "Neblig",
"48-night": "Foggy", "48-night": "Neblig",
"51-day": "Light Drizzle", "51-day": "Leichter Nieselregen",
"51-night": "Light Drizzle", "51-night": "Leichter Nieselregen",
"55-day": "Heavy Drizzle", "55-day": "Starker Nieselregen",
"53-day": "Drizzle", "53-day": "Nieselregen",
"53-night": "Drizzle", "53-night": "Nieselregen",
"55-night": "Heavy Drizzle", "55-night": "Starker Nieselregen",
"56-day": "Light Freezing Drizzle", "56-day": "Leichter gefrierender Nieselregen",
"56-night": "Light Freezing Drizzle", "56-night": "Leichter eisiger Nieselregen",
"57-night": "Freezing Drizzle", "57-night": "Gefrierender Nieselregen",
"61-night": "Light Rain", "61-night": "Leichter Regen",
"63-day": "Rain", "63-day": "Regen",
"63-night": "Rain", "63-night": "Regen",
"65-day": "Heavy Rain", "65-day": "Starker Regen",
"67-day": "Freezing Rain", "67-day": "Gefrierender Regen",
"67-night": "Freezing Rain", "67-night": "Gefrierender Regen",
"71-day": "Light Snow", "71-day": "Leichter Schneefall",
"71-night": "Light Snow", "71-night": "Leichter Schnee",
"73-day": "Snow", "73-day": "Schnee",
"73-night": "Snow", "73-night": "Schnee",
"75-day": "Heavy Snow", "75-day": "Schwerer Schnee",
"75-night": "Heavy Snow", "75-night": "Schwerer Schnee",
"77-day": "Snow Grains", "77-day": "Schneegriesel",
"77-night": "Snow Grains", "77-night": "Schneegriesel",
"80-day": "Light Showers", "80-day": "Leichter Schauer",
"80-night": "Light Showers", "80-night": "Leichter Schauer",
"81-day": "Showers", "81-day": "Schauer",
"81-night": "Showers", "81-night": "Schauer",
"82-day": "Heavy Showers", "82-day": "Starke Regenschauer",
"82-night": "Heavy Showers", "82-night": "Starke Regenschauer",
"85-day": "Snow Showers", "85-day": "Schneeschauer",
"85-night": "Snow Showers", "85-night": "Schneeregen",
"86-day": "Snow Showers", "86-day": "Schneeregen",
"86-night": "Snow Showers", "86-night": "Schneeregen",
"95-day": "Thunderstorm", "95-day": "Gewitter",
"95-night": "Thunderstorm", "95-night": "Gewitter",
"96-day": "Thunderstorm With Hail", "96-day": "Gewitter mit Hagel",
"96-night": "Thunderstorm With Hail", "96-night": "Gewitter mit Hagel",
"99-day": "Thunderstorm With Hail", "99-day": "Gewitter mit Hagel",
"99-night": "Thunderstorm With Hail" "99-night": "Gewitter mit Hagel"
}, },
"quicklaunch": { "quicklaunch": {
"bookmark": "Bookmark", "bookmark": "Lesezeichen",
"service": "Service" "service": "Dienst"
}, },
"homebridge": { "homebridge": {
"available_update": "System", "available_update": "System",
"updates": "Updates", "updates": "Aktualisierungen",
"update_available": "Update Available", "update_available": "Aktualisierung verfügbar",
"up_to_date": "Up to Date", "up_to_date": "Aktuell",
"child_bridges": "Child Bridges", "child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"autobrr": {
"approvedPushes": "Genehmigt",
"rejectedPushes": "Abgelehnt",
"filters": "Filter",
"indexers": "Indexer"
},
"watchtower": {
"containers_scanned": "Überprüft",
"containers_updated": "Aktualisiert",
"containers_failed": "Fehlgeschlagen"
},
"tubearchivist": {
"downloads": "Warteschlange",
"videos": "Videos",
"channels": "Kanäle",
"playlists": "Wiedergabelisten"
},
"truenas": {
"load": "Systembelastung",
"uptime": "Betriebszeit",
"alerts": "Warnungen",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"pyload": {
"speed": "Speed",
"active": "Active",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"ping": "Ping",
"error": "Error"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"diskstation": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"flood": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
} }
} }

View File

@ -13,7 +13,11 @@
"widget": { "widget": {
"missing_type": "Missing Widget Type: {{type}}", "missing_type": "Missing Widget Type: {{type}}",
"api_error": "API Error", "api_error": "API Error",
"status": "Status" "information": "Information",
"status": "Status",
"url": "URL",
"raw_error": "Raw Error",
"response_data": "Response Data"
}, },
"weather": { "weather": {
"current": "Current Location", "current": "Current Location",
@ -52,7 +56,13 @@
"tx": "TX", "tx": "TX",
"mem": "MEM", "mem": "MEM",
"cpu": "CPU", "cpu": "CPU",
"offline": "Offline" "offline": "Offline",
"error": "Error",
"unknown": "Unknown"
},
"ping": {
"error": "Error",
"ping": "Ping"
}, },
"emby": { "emby": {
"playing": "Playing", "playing": "Playing",
@ -60,6 +70,12 @@
"bitrate": "Bitrate", "bitrate": "Bitrate",
"no_active": "No Active Streams" "no_active": "No Active Streams"
}, },
"flood": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"changedetectionio": { "changedetectionio": {
"totalObserved": "Total Observed", "totalObserved": "Total Observed",
"diffsDetected": "Diffs Detected" "diffsDetected": "Diffs Detected"
@ -102,6 +118,18 @@
"leech": "Leech", "leech": "Leech",
"seed": "Seed" "seed": "Seed"
}, },
"deluge": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"diskstation": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"sonarr": { "sonarr": {
"wanted": "Wanted", "wanted": "Wanted",
"queued": "Queued", "queued": "Queued",
@ -139,6 +167,7 @@
}, },
"overseerr": { "overseerr": {
"pending": "Pending", "pending": "Pending",
"processing": "Processing",
"approved": "Approved", "approved": "Approved",
"available": "Available" "available": "Available"
}, },
@ -168,6 +197,10 @@
"services": "Services", "services": "Services",
"middleware": "Middleware" "middleware": "Middleware"
}, },
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"npm": { "npm": {
"enabled": "Enabled", "enabled": "Enabled",
"disabled": "Disabled", "disabled": "Disabled",
@ -292,5 +325,52 @@
"up_to_date": "Up to Date", "up_to_date": "Up to Date",
"child_bridges": "Child Bridges", "child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"watchtower": {
"containers_scanned": "Scanned",
"containers_updated": "Updated",
"containers_failed": "Failed"
},
"autobrr": {
"approvedPushes": "Approved",
"rejectedPushes": "Rejected",
"filters": "Filters",
"indexers": "Indexers"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Videos",
"channels": "Channels",
"playlists": "Playlists"
},
"truenas": {
"load": "System Load",
"uptime": "Uptime",
"alerts": "Alerts",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"pyload": {
"speed": "Speed",
"active": "Active",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
} }
} }

View File

@ -0,0 +1,365 @@
{
"widget": {
"missing_type": "Missing Widget Type: {{type}}",
"api_error": "API Error",
"information": "Informo",
"status": "Stato",
"url": "URL",
"raw_error": "Raw Error",
"response_data": "Response Data"
},
"weather": {
"current": "Aktuala loko",
"allow": "Click to allow",
"updating": "Updating",
"wait": "Please wait"
},
"search": {
"placeholder": "Serĉi…"
},
"resources": {
"cpu": "Ĉefprocesoro",
"total": "Totalo",
"free": "Libera",
"used": "Uzata",
"load": "Ŝarĝo"
},
"unifi": {
"users": "Uzantoj",
"uptime": "System Uptime",
"days": "Tagoj",
"wan": "WAN",
"lan": "LAN",
"wlan": "WLAN",
"devices": "Aparatoj",
"lan_devices": "LAN Devices",
"wlan_devices": "WLAN Devices",
"lan_users": "LAN Users",
"wlan_users": "WLAN Users",
"up": "UP",
"down": "DOWN",
"wait": "Please wait"
},
"docker": {
"rx": "RX",
"tx": "TX",
"mem": "Memoro",
"cpu": "Ĉefprocesoro",
"offline": "Offline",
"error": "Eraro",
"unknown": "Nekonata"
},
"ping": {
"error": "Eraro",
"ping": "Ping"
},
"emby": {
"playing": "Ludante",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams"
},
"changedetectionio": {
"totalObserved": "Total Observed",
"diffsDetected": "Diffs Detected"
},
"tautulli": {
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams"
},
"nzbget": {
"rate": "Rate",
"remaining": "Remaining",
"downloaded": "Downloaded"
},
"plex": {
"streams": "Active Streams",
"movies": "Filmoj",
"tv": "Televidprogramoj"
},
"sabnzbd": {
"rate": "Rate",
"queue": "Queue",
"timeleft": "Time Left"
},
"rutorrent": {
"active": "Active",
"upload": "Alŝuto",
"download": "Elŝuto"
},
"transmission": {
"download": "Elŝuto",
"upload": "Alŝuto",
"leech": "Leech",
"seed": "Seed"
},
"qbittorrent": {
"download": "Elŝuto",
"upload": "Alŝuto",
"leech": "Leech",
"seed": "Seed"
},
"deluge": {
"download": "Elŝuto",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"sonarr": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Serio"
},
"radarr": {
"wanted": "Wanted",
"missing": "Missing",
"queued": "Queued",
"movies": "Filmoj"
},
"lidarr": {
"wanted": "Wanted",
"queued": "Queued",
"albums": "Albumoj"
},
"readarr": {
"wanted": "Wanted",
"queued": "Queued",
"books": "Libroj"
},
"bazarr": {
"missingEpisodes": "Missing Episodes",
"missingMovies": "Missing Movies"
},
"ombi": {
"pending": "Pending",
"approved": "Aprobita",
"available": "Havebla"
},
"jellyseerr": {
"pending": "Pending",
"approved": "Aprobita",
"available": "Havebla"
},
"overseerr": {
"pending": "Pending",
"processing": "Processing",
"approved": "Aprobita",
"available": "Havebla"
},
"pihole": {
"queries": "Queries",
"blocked": "Blocked",
"gravity": "Gravity"
},
"adguard": {
"queries": "Queries",
"blocked": "Blokitaj",
"filtered": "Filtritaj",
"latency": "Latency"
},
"speedtest": {
"upload": "Upload",
"download": "Download",
"ping": "Ping"
},
"portainer": {
"running": "Running",
"stopped": "Stopped",
"total": "Totalo"
},
"traefik": {
"routers": "Routers",
"services": "Servoj",
"middleware": "Middleware"
},
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"npm": {
"enabled": "Enabled",
"disabled": "Disabled",
"total": "Total"
},
"coinmarketcap": {
"configure": "Configure one or more crypto currencies to track",
"1hour": "1 horo",
"1day": "1 tago",
"7days": "7 tagoj",
"30days": "30 tagoj"
},
"gotify": {
"apps": "Applications",
"clients": "Klientoj",
"messages": "Mesaĝoj"
},
"prowlarr": {
"enableIndexers": "Indexers",
"numberOfGrabs": "Grabs",
"numberOfQueries": "Queries",
"numberOfFailGrabs": "Fail Grabs",
"numberOfFailQueries": "Fail Queries"
},
"jackett": {
"configured": "Configured",
"errored": "Errored"
},
"strelaysrv": {
"numActiveSessions": "Seancoj",
"numConnections": "Konektoj",
"dataRelayed": "Relayed",
"transferRate": "Rate"
},
"mastodon": {
"user_count": "Uzantoj",
"status_count": "Afiŝoj",
"domain_count": "Domains"
},
"authentik": {
"users": "Users",
"loginsLast24H": "Logins (24h)",
"failedLoginsLast24H": "Failed Logins (24h)"
},
"proxmox": {
"mem": "Memoro",
"cpu": "Ĉefprocesoro",
"lxc": "LXC",
"vms": "VMs"
},
"glances": {
"cpu": "Ĉefprocesoro",
"mem": "Memoro",
"wait": "Bonvolu atendi"
},
"quicklaunch": {
"bookmark": "Bookmark",
"service": "Servo"
},
"wmo": {
"0-day": "Suna",
"0-night": "Sennuba",
"1-day": "Mainly Sunny",
"1-night": "Mainly Clear",
"2-day": "Nubeta",
"2-night": "Nubeta",
"3-day": "Nuba",
"3-night": "Nuba",
"45-day": "Nebula",
"45-night": "Nebula",
"48-day": "Nebula",
"48-night": "Nebula",
"51-day": "Light Drizzle",
"51-night": "Light Drizzle",
"53-day": "Drizzle",
"53-night": "Drizzle",
"55-day": "Heavy Drizzle",
"55-night": "Heavy Drizzle",
"56-day": "Light Freezing Drizzle",
"56-night": "Light Freezing Drizzle",
"57-day": "Freezing Drizzle",
"57-night": "Freezing Drizzle",
"61-day": "Light Rain",
"61-night": "Light Rain",
"63-day": "Pluvo",
"63-night": "Pluvo",
"65-day": "Pluvego",
"65-night": "Pluvego",
"66-day": "Frosta pluvo",
"66-night": "Frosta pluvo",
"67-day": "Frosta pluvo",
"67-night": "Frosta pluvo",
"71-day": "Light Snow",
"71-night": "Light Snow",
"73-day": "Neĝo",
"73-night": "Neĝo",
"75-day": "Neĝego",
"75-night": "Neĝego",
"77-day": "Snow Grains",
"77-night": "Snow Grains",
"80-day": "Light Showers",
"80-night": "Light Showers",
"81-day": "Showers",
"81-night": "Showers",
"82-day": "Heavy Showers",
"82-night": "Heavy Showers",
"85-day": "Snow Showers",
"85-night": "Snow Showers",
"86-day": "Snow Showers",
"86-night": "Snow Showers",
"95-day": "Fulmotondro",
"95-night": "Fulmotondro",
"96-day": "Fulmotondro kun hajlo",
"96-night": "Fulmotondro kun hajlo",
"99-day": "Fulmotondro kun hajlo",
"99-night": "Fulmotondro kun hajlo"
},
"homebridge": {
"available_update": "Sistemo",
"updates": "Updates",
"update_available": "Update Available",
"up_to_date": "Up to Date",
"child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}"
},
"watchtower": {
"containers_scanned": "Scanned",
"containers_updated": "Updated",
"containers_failed": "Failed"
},
"autobrr": {
"approvedPushes": "Approved",
"rejectedPushes": "Rejected",
"filters": "Filtriloj",
"indexers": "Indexers"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Videos",
"channels": "Kanaloj",
"playlists": "Playlists"
},
"truenas": {
"load": "System Load",
"uptime": "Uptime",
"alerts": "Alerts",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"pyload": {
"speed": "Speed",
"active": "Aktiva",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Regiono",
"country": "Lando"
},
"hdhomerun": {
"channels": "Kanaloj",
"hd": "HD"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Totalo"
},
"diskstation": {
"download": "Download",
"leech": "Leech",
"upload": "Upload",
"seed": "Seed"
},
"flood": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
}
}

View File

@ -2,7 +2,11 @@
"widget": { "widget": {
"missing_type": "Falta el tipo de widget: {{type}}", "missing_type": "Falta el tipo de widget: {{type}}",
"api_error": "Error de API", "api_error": "Error de API",
"status": "Estado" "status": "Estado",
"information": "Información",
"url": "URL",
"raw_error": "Error sin procesar",
"response_data": "Datos de respuesta"
}, },
"search": { "search": {
"placeholder": "Buscar…" "placeholder": "Buscar…"
@ -19,7 +23,9 @@
"tx": "Transmitido", "tx": "Transmitido",
"mem": "Memoria", "mem": "Memoria",
"cpu": "Procesador", "cpu": "Procesador",
"offline": "Desconectado" "offline": "Desconectado",
"error": "Fallo",
"unknown": "Desconocido"
}, },
"emby": { "emby": {
"playing": "Reproduciendo", "playing": "Reproduciendo",
@ -47,7 +53,7 @@
"wanted": "Buscando", "wanted": "Buscando",
"queued": "En cola", "queued": "En cola",
"movies": "Películas", "movies": "Películas",
"missing": "No Encontrado" "missing": "Faltan"
}, },
"readarr": { "readarr": {
"wanted": "Buscando", "wanted": "Buscando",
@ -82,7 +88,7 @@
"traefik": { "traefik": {
"routers": "Enrutadores", "routers": "Enrutadores",
"services": "Servicios", "services": "Servicios",
"middleware": "Middleware" "middleware": "Software intermedio"
}, },
"npm": { "npm": {
"enabled": "Activado", "enabled": "Activado",
@ -98,7 +104,8 @@
"overseerr": { "overseerr": {
"pending": "Pendiente", "pending": "Pendiente",
"approved": "Aprobado", "approved": "Aprobado",
"available": "Disponible" "available": "Disponible",
"processing": "Procesando"
}, },
"sabnzbd": { "sabnzbd": {
"rate": "Tasa", "rate": "Tasa",
@ -132,7 +139,7 @@
"transmission": { "transmission": {
"download": "Bajada", "download": "Bajada",
"upload": "Subida", "upload": "Subida",
"leech": "Compañeros", "leech": "Leech",
"seed": "Semillas" "seed": "Semillas"
}, },
"jackett": { "jackett": {
@ -157,7 +164,7 @@
"qbittorrent": { "qbittorrent": {
"download": "Bajada", "download": "Bajada",
"upload": "Subida", "upload": "Subida",
"leech": "Compañeros", "leech": "Leech",
"seed": "Semillas" "seed": "Semillas"
}, },
"mastodon": { "mastodon": {
@ -275,11 +282,84 @@
"service": "Servicio" "service": "Servicio"
}, },
"homebridge": { "homebridge": {
"available_update": "System", "available_update": "Sistema",
"updates": "Updates", "updates": "Actualizaciones",
"update_available": "Update Available", "update_available": "Actualización disponible",
"up_to_date": "Up to Date", "up_to_date": "Actualizado",
"child_bridges": "Child Bridges", "child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"autobrr": {
"approvedPushes": "Aprobado",
"rejectedPushes": "Rechazado",
"filters": "Filtros",
"indexers": "Indexadores"
},
"watchtower": {
"containers_scanned": "Escaneado",
"containers_updated": "Actualizado",
"containers_failed": "Fallido"
},
"tubearchivist": {
"downloads": "Cola",
"videos": "Vídeos",
"channels": "Canales",
"playlists": "Listas de reproducción"
},
"truenas": {
"load": "Carga del sistema",
"uptime": "Tiempo de la actividad",
"alerts": "Alertas",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "Sin transmisiones activas",
"please_wait": "Espere por favor"
},
"pyload": {
"speed": "Velocidad",
"active": "Activo",
"queue": "Cola",
"total": "Total"
},
"gluetun": {
"public_ip": "IP pública",
"region": "Región",
"country": "País"
},
"hdhomerun": {
"channels": "Canales",
"hd": "Alta definición"
},
"ping": {
"error": "Error",
"ping": "Ping"
},
"scrutiny": {
"passed": "Aprobado",
"failed": "Fallido",
"unknown": "Desconocido"
},
"paperlessngx": {
"inbox": "Bandeja de entrada",
"total": "Total"
},
"deluge": {
"download": "Descarga",
"upload": "Subida",
"leech": "Leech",
"seed": "Semilla"
},
"diskstation": {
"download": "Descargar",
"upload": "Cargar",
"leech": "Leech",
"seed": "Semilla"
},
"flood": {
"download": "Descargar",
"upload": "Subir",
"leech": "Leech",
"seed": "Seed"
} }
} }

View File

@ -2,7 +2,11 @@
"widget": { "widget": {
"missing_type": "Puuttuva härpäkkeen tyyppi: {{type}}", "missing_type": "Puuttuva härpäkkeen tyyppi: {{type}}",
"api_error": "API-virhe", "api_error": "API-virhe",
"status": "Tila" "status": "Tila",
"information": "Information",
"url": "URL",
"raw_error": "Raw Error",
"response_data": "Response Data"
}, },
"weather": { "weather": {
"current": "Nykyinen sijainti", "current": "Nykyinen sijainti",
@ -25,7 +29,9 @@
"tx": "TX", "tx": "TX",
"mem": "RAM", "mem": "RAM",
"cpu": "CPU", "cpu": "CPU",
"offline": "Offline" "offline": "Offline",
"error": "Error",
"unknown": "Unknown"
}, },
"emby": { "emby": {
"playing": "Toistaa", "playing": "Toistaa",
@ -104,7 +110,8 @@
"overseerr": { "overseerr": {
"pending": "Vireillä", "pending": "Vireillä",
"approved": "Hyväksytty", "approved": "Hyväksytty",
"available": "Saatavilla" "available": "Saatavilla",
"processing": "Processing"
}, },
"pihole": { "pihole": {
"queries": "Kyselyjä", "queries": "Kyselyjä",
@ -281,5 +288,78 @@
"up_to_date": "Up to Date", "up_to_date": "Up to Date",
"child_bridges": "Child Bridges", "child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"autobrr": {
"approvedPushes": "Approved",
"rejectedPushes": "Rejected",
"filters": "Filters",
"indexers": "Indexers"
},
"watchtower": {
"containers_scanned": "Scanned",
"containers_updated": "Updated",
"containers_failed": "Failed"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Videos",
"channels": "Channels",
"playlists": "Playlists"
},
"truenas": {
"load": "System Load",
"uptime": "Uptime",
"alerts": "Alerts",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"pyload": {
"speed": "Speed",
"active": "Active",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"error": "Error",
"ping": "Ping"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"upload": "Upload",
"leech": "Leech",
"seed": "Seed",
"download": "Download"
},
"diskstation": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"flood": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
} }
} }

View File

@ -2,7 +2,11 @@
"widget": { "widget": {
"missing_type": "Type de widget manquant: {{type}}", "missing_type": "Type de widget manquant: {{type}}",
"api_error": "Erreur de l'API", "api_error": "Erreur de l'API",
"status": "Statut" "status": "Statut",
"information": "Information",
"url": "URL",
"raw_error": "Raw Error",
"response_data": "Response Data"
}, },
"search": { "search": {
"placeholder": "Recherche…" "placeholder": "Recherche…"
@ -19,7 +23,9 @@
"tx": "Tx", "tx": "Tx",
"mem": "Mém", "mem": "Mém",
"cpu": "Cpu", "cpu": "Cpu",
"offline": "Hors ligne" "offline": "Hors ligne",
"error": "Erreur",
"unknown": "Inconnu"
}, },
"emby": { "emby": {
"playing": "En lecture", "playing": "En lecture",
@ -98,7 +104,8 @@
"overseerr": { "overseerr": {
"pending": "En attente", "pending": "En attente",
"approved": "Demande", "approved": "Demande",
"available": "Disponible" "available": "Disponible",
"processing": "En traitement"
}, },
"sabnzbd": { "sabnzbd": {
"rate": "Débit", "rate": "Débit",
@ -275,11 +282,84 @@
"service": "Service" "service": "Service"
}, },
"homebridge": { "homebridge": {
"available_update": "System", "available_update": "Système",
"updates": "Updates", "updates": "Mises à jour",
"update_available": "Update Available", "update_available": "Mise à jour disponible",
"up_to_date": "Up to Date", "up_to_date": "À jour",
"child_bridges": "Child Bridges", "child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"autobrr": {
"approvedPushes": "Approuvé",
"rejectedPushes": "Rejeté",
"filters": "Filtres",
"indexers": "Indexeur"
},
"watchtower": {
"containers_scanned": "Scanné",
"containers_updated": "Mis à jour",
"containers_failed": "Échoué"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Vidéos",
"channels": "Chaînes",
"playlists": "Playlists"
},
"truenas": {
"load": "Charge Système",
"uptime": "Démarré depuis",
"alerts": "Alertes",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "Aucun flux actif",
"please_wait": "Merci de patienter"
},
"pyload": {
"speed": "Débit",
"active": "Actif",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "IP Publique",
"region": "Région",
"country": "Pays"
},
"hdhomerun": {
"channels": "Canaux",
"hd": "HD"
},
"ping": {
"error": "Erreur",
"ping": "Ping"
},
"scrutiny": {
"passed": "Réussi",
"failed": "Échoué",
"unknown": "Inconnu"
},
"paperlessngx": {
"inbox": "Boîte de réception",
"total": "Total"
},
"deluge": {
"download": "Récep.",
"upload": "Envoi",
"leech": "Leech",
"seed": "Seed"
},
"diskstation": {
"download": "Réception",
"upload": "Envoi",
"leech": "Leech",
"seed": "Seed"
},
"flood": {
"download": "Récep.",
"upload": "Envoi",
"leech": "Leech",
"seed": "Seed"
} }
} }

View File

@ -2,7 +2,11 @@
"widget": { "widget": {
"missing_type": "סוג ווידג'ט חסר: {{type}}", "missing_type": "סוג ווידג'ט חסר: {{type}}",
"api_error": "שגיאת API", "api_error": "שגיאת API",
"status": "סטטוס" "status": "סטטוס",
"information": "Information",
"url": "URL",
"raw_error": "Raw Error",
"response_data": "Response Data"
}, },
"weather": { "weather": {
"current": "מיקום נוכחי", "current": "מיקום נוכחי",
@ -25,7 +29,9 @@
"tx": "TX", "tx": "TX",
"mem": "זיכרון", "mem": "זיכרון",
"cpu": "מעבד", "cpu": "מעבד",
"offline": "כבוי" "offline": "כבוי",
"error": "Error",
"unknown": "Unknown"
}, },
"emby": { "emby": {
"playing": "מנגן", "playing": "מנגן",
@ -104,7 +110,8 @@
"overseerr": { "overseerr": {
"pending": "ממתין", "pending": "ממתין",
"approved": "מאושר", "approved": "מאושר",
"available": "זמין" "available": "זמין",
"processing": "Processing"
}, },
"pihole": { "pihole": {
"queries": "שאילתות", "queries": "שאילתות",
@ -281,5 +288,78 @@
"up_to_date": "Up to Date", "up_to_date": "Up to Date",
"child_bridges": "Child Bridges", "child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"autobrr": {
"approvedPushes": "Approved",
"rejectedPushes": "Rejected",
"filters": "Filters",
"indexers": "Indexers"
},
"watchtower": {
"containers_scanned": "Scanned",
"containers_updated": "Updated",
"containers_failed": "Failed"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Videos",
"channels": "Channels",
"playlists": "Playlists"
},
"truenas": {
"load": "System Load",
"uptime": "Uptime",
"alerts": "Alerts",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"pyload": {
"speed": "Speed",
"active": "Active",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"error": "Error",
"ping": "Ping"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"diskstation": {
"upload": "Upload",
"leech": "Leech",
"download": "Download",
"seed": "Seed"
},
"flood": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
} }
} }

View File

@ -0,0 +1,365 @@
{
"widget": {
"missing_type": "Missing Widget Type: {{type}}",
"api_error": "API Error",
"status": "Status",
"information": "Information",
"url": "URL",
"raw_error": "Raw Error",
"response_data": "Response Data"
},
"weather": {
"current": "Current Location",
"allow": "Click to allow",
"updating": "Updating",
"wait": "Please wait"
},
"readarr": {
"queued": "Queued",
"books": "Books",
"wanted": "Wanted"
},
"bazarr": {
"missingEpisodes": "Missing Episodes",
"missingMovies": "Missing Movies"
},
"ombi": {
"pending": "Pending",
"approved": "Approved",
"available": "Available"
},
"jellyseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available"
},
"traefik": {
"services": "Services",
"middleware": "Middleware",
"routers": "Routers"
},
"mastodon": {
"domain_count": "Domains",
"user_count": "Users",
"status_count": "Posts"
},
"authentik": {
"users": "Users",
"loginsLast24H": "Logins (24h)",
"failedLoginsLast24H": "Failed Logins (24h)"
},
"search": {
"placeholder": "Search…"
},
"resources": {
"cpu": "CPU",
"total": "Total",
"free": "Free",
"used": "Used",
"load": "Load"
},
"unifi": {
"users": "Users",
"uptime": "System Uptime",
"days": "Days",
"wan": "WAN",
"lan": "LAN",
"wlan": "WLAN",
"devices": "Devices",
"lan_devices": "LAN Devices",
"wlan_devices": "WLAN Devices",
"lan_users": "LAN Users",
"wlan_users": "WLAN Users",
"up": "UP",
"down": "DOWN",
"wait": "Please wait"
},
"docker": {
"rx": "RX",
"tx": "TX",
"mem": "MEM",
"cpu": "CPU",
"offline": "Offline",
"error": "Error",
"unknown": "Unknown"
},
"emby": {
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams"
},
"changedetectionio": {
"totalObserved": "Total Observed",
"diffsDetected": "Diffs Detected"
},
"tautulli": {
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams"
},
"nzbget": {
"rate": "Rate",
"remaining": "Remaining",
"downloaded": "Downloaded"
},
"plex": {
"streams": "Active Streams",
"movies": "Movies",
"tv": "TV Shows"
},
"sabnzbd": {
"rate": "Rate",
"queue": "Queue",
"timeleft": "Time Left"
},
"rutorrent": {
"active": "Active",
"upload": "Upload",
"download": "Download"
},
"transmission": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"qbittorrent": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"sonarr": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
},
"radarr": {
"wanted": "Wanted",
"missing": "Missing",
"queued": "Queued",
"movies": "Movies"
},
"lidarr": {
"wanted": "Wanted",
"queued": "Queued",
"albums": "Albums"
},
"overseerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"processing": "Processing"
},
"pihole": {
"queries": "Queries",
"blocked": "Blocked",
"gravity": "Gravity"
},
"adguard": {
"queries": "Queries",
"blocked": "Blocked",
"filtered": "Filtered",
"latency": "Latency"
},
"speedtest": {
"upload": "Upload",
"download": "Download",
"ping": "Ping"
},
"portainer": {
"running": "Running",
"stopped": "Stopped",
"total": "Total"
},
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"npm": {
"enabled": "Enabled",
"disabled": "Disabled",
"total": "Total"
},
"coinmarketcap": {
"configure": "Configure one or more crypto currencies to track",
"1hour": "1 Hour",
"1day": "1 Day",
"7days": "7 Days",
"30days": "30 Days"
},
"gotify": {
"apps": "Applications",
"clients": "Clients",
"messages": "Messages"
},
"prowlarr": {
"enableIndexers": "Indexers",
"numberOfGrabs": "Grabs",
"numberOfQueries": "Queries",
"numberOfFailGrabs": "Fail Grabs",
"numberOfFailQueries": "Fail Queries"
},
"jackett": {
"configured": "Configured",
"errored": "Errored"
},
"strelaysrv": {
"numActiveSessions": "Sessions",
"numConnections": "Connections",
"dataRelayed": "Relayed",
"transferRate": "Rate"
},
"proxmox": {
"mem": "MEM",
"cpu": "CPU",
"lxc": "LXC",
"vms": "VMs"
},
"glances": {
"cpu": "CPU",
"mem": "MEM",
"wait": "Please wait"
},
"quicklaunch": {
"bookmark": "Bookmark",
"service": "Service"
},
"wmo": {
"0-day": "Sunny",
"0-night": "Clear",
"1-day": "Mainly Sunny",
"1-night": "Mainly Clear",
"2-day": "Partly Cloudy",
"2-night": "Partly Cloudy",
"3-day": "Cloudy",
"3-night": "Cloudy",
"45-day": "Foggy",
"45-night": "Foggy",
"48-day": "Foggy",
"48-night": "Foggy",
"51-day": "Light Drizzle",
"51-night": "Light Drizzle",
"53-day": "Drizzle",
"53-night": "Drizzle",
"55-day": "Heavy Drizzle",
"55-night": "Heavy Drizzle",
"56-day": "Light Freezing Drizzle",
"56-night": "Light Freezing Drizzle",
"57-day": "Freezing Drizzle",
"57-night": "Freezing Drizzle",
"61-day": "Light Rain",
"61-night": "Light Rain",
"63-day": "Rain",
"63-night": "Rain",
"65-day": "Heavy Rain",
"65-night": "Heavy Rain",
"66-day": "Freezing Rain",
"66-night": "Freezing Rain",
"67-day": "Freezing Rain",
"67-night": "Freezing Rain",
"71-day": "Light Snow",
"71-night": "Light Snow",
"73-day": "Snow",
"73-night": "Snow",
"75-day": "Heavy Snow",
"75-night": "Heavy Snow",
"77-day": "Snow Grains",
"77-night": "Snow Grains",
"80-day": "Light Showers",
"80-night": "Light Showers",
"81-day": "Showers",
"81-night": "Showers",
"82-day": "Heavy Showers",
"82-night": "Heavy Showers",
"85-day": "Snow Showers",
"85-night": "Snow Showers",
"86-day": "Snow Showers",
"86-night": "Snow Showers",
"95-day": "Thunderstorm",
"95-night": "Thunderstorm",
"96-day": "Thunderstorm With Hail",
"96-night": "Thunderstorm With Hail",
"99-day": "Thunderstorm With Hail",
"99-night": "Thunderstorm With Hail"
},
"homebridge": {
"available_update": "System",
"updates": "Updates",
"update_available": "Update Available",
"up_to_date": "Up to Date",
"child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}"
},
"watchtower": {
"containers_scanned": "Scanned",
"containers_updated": "Updated",
"containers_failed": "Failed"
},
"autobrr": {
"approvedPushes": "Approved",
"rejectedPushes": "Rejected",
"filters": "Filters",
"indexers": "Indexers"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Videos",
"channels": "Channels",
"playlists": "Playlists"
},
"truenas": {
"load": "System Load",
"uptime": "Uptime",
"time": "{{value, number(style: unit; unitDisplay: long;)}}",
"alerts": "Alerts"
},
"pyload": {
"speed": "Speed",
"active": "Active",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"error": "Error",
"ping": "Ping"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"diskstation": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"flood": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
}
}

View File

@ -1,12 +1,12 @@
{ {
"weather": { "weather": {
"current": "Trenutna lokacija", "current": "Trenutna lokacija",
"allow": "Pritisni za dozvoljavanje", "allow": "Pritisni za dozvoljavanje",
"updating": "Aktualiziranje", "updating": "Aktualiziranje",
"wait": "Molimo pričekajte" "wait": "Pričekaj"
}, },
"search": { "search": {
"placeholder": "Traži…" "placeholder": "Traži …"
}, },
"resources": { "resources": {
"total": "Ukupno", "total": "Ukupno",
@ -17,18 +17,19 @@
}, },
"sabnzbd": { "sabnzbd": {
"rate": "Stopa", "rate": "Stopa",
"queue": "Red", "queue": "Red čekanja",
"timeleft": "Preostalo vrijeme" "timeleft": "Preostalo vrijeme"
}, },
"overseerr": { "overseerr": {
"available": "Dostupno", "available": "Dostupno",
"pending": "Predstoji", "pending": "Predstoji",
"approved": "Odobreno" "approved": "Odobreno",
"processing": "Obrada"
}, },
"pihole": { "pihole": {
"queries": "Upiti", "queries": "Upiti",
"blocked": "Blokirano", "blocked": "Blokirano",
"gravity": "Ozbiljnost" "gravity": "Čuvanje podataka"
}, },
"adguard": { "adguard": {
"latency": "Kašnjenje", "latency": "Kašnjenje",
@ -58,14 +59,20 @@
"widget": { "widget": {
"missing_type": "Nedostajuća vrsta widgeta: {{type}}", "missing_type": "Nedostajuća vrsta widgeta: {{type}}",
"api_error": "API greška", "api_error": "API greška",
"status": "Stanje" "status": "Stanje",
"information": "Informacije",
"url": "URL",
"raw_error": "Raw greška",
"response_data": "Podaci odgovora"
}, },
"docker": { "docker": {
"rx": "RX", "rx": "RX",
"tx": "TX", "tx": "TX",
"mem": "MEM", "mem": "MEM",
"cpu": "CPU", "cpu": "CPU",
"offline": "Izvan mreže" "offline": "Nepovezan",
"error": "Greška",
"unknown": "Nepoznato"
}, },
"emby": { "emby": {
"playing": "Reprodukcija", "playing": "Reprodukcija",
@ -92,27 +99,27 @@
"transmission": { "transmission": {
"download": "Preuzimanje", "download": "Preuzimanje",
"upload": "Prijenos", "upload": "Prijenos",
"leech": "Krvopija", "leech": "Leecher",
"seed": "Prijenos preuzetog sadržaja" "seed": "Seeder"
}, },
"sonarr": { "sonarr": {
"wanted": "Željeno", "wanted": "Zatraženo",
"queued": "U redu čekanja", "queued": "U redu čekanja",
"series": "Serije" "series": "Serije"
}, },
"radarr": { "radarr": {
"wanted": "Željeno", "wanted": "Zatraženo",
"queued": "U redu čekanja", "queued": "U redu čekanja",
"movies": "Filmovi", "movies": "Filmovi",
"missing": "Missing" "missing": "Nedostaje"
}, },
"lidarr": { "lidarr": {
"wanted": "Željeno", "wanted": "Zatraženo",
"queued": "U redu čekanja", "queued": "U redu čekanja",
"albums": "Albumi" "albums": "Albumi"
}, },
"readarr": { "readarr": {
"wanted": "Željeno", "wanted": "Zatraženo",
"queued": "U redu čekanja", "queued": "U redu čekanja",
"books": "Knjige" "books": "Knjige"
}, },
@ -143,7 +150,7 @@
"traefik": { "traefik": {
"routers": "Ruteri", "routers": "Ruteri",
"services": "Usluge", "services": "Usluge",
"middleware": "Middleware" "middleware": "Posrednički softver"
}, },
"gotify": { "gotify": {
"clients": "Klijenti", "clients": "Klijenti",
@ -157,8 +164,8 @@
"qbittorrent": { "qbittorrent": {
"download": "Preuzimanje", "download": "Preuzimanje",
"upload": "Prijenos", "upload": "Prijenos",
"leech": "Krvopija", "leech": "Leecher",
"seed": "Prijenos preuzetog sadržaja" "seed": "Seeder"
}, },
"mastodon": { "mastodon": {
"user_count": "Korisnici", "user_count": "Korisnici",
@ -172,114 +179,187 @@
"transferRate": "Stopa" "transferRate": "Stopa"
}, },
"authentik": { "authentik": {
"users": "Users", "users": "Korisnici",
"loginsLast24H": "Logins (24h)", "loginsLast24H": "Prijave (24 h)",
"failedLoginsLast24H": "Failed Logins (24h)" "failedLoginsLast24H": "Neuspjele prijave (24 h)"
}, },
"proxmox": { "proxmox": {
"mem": "MEM", "mem": "MEM",
"cpu": "CPU", "cpu": "CPU",
"lxc": "LXC", "lxc": "Linux kontejner",
"vms": "VMs" "vms": "Virtualni uređaji"
}, },
"unifi": { "unifi": {
"users": "Korisnici", "users": "Korisnici",
"uptime": "Vrijeme rada sustava", "uptime": "Radno vrijeme sustava",
"days": "Dani", "days": "Dani",
"wan": "WAN", "wan": "WAN",
"lan_users": "LAN Korisnici", "lan_users": "LAN korisnici",
"wlan_users": "WLAN Korisnici", "wlan_users": "WLAN korisnici",
"up": "Upaljen", "up": "SLANJE",
"down": "Ugašen", "down": "PRIMANJE",
"wait": "Molimo pričekajte", "wait": "Pričekaj",
"lan": "LAN", "lan": "LAN",
"wlan": "WLAN", "wlan": "WLAN",
"devices": "Devices", "devices": "Uređaji",
"lan_devices": "LAN Devices", "lan_devices": "LAN uređaji",
"wlan_devices": "WLAN Devices" "wlan_devices": "WLAN uređaji"
}, },
"plex": { "plex": {
"streams": "Active Streams", "streams": "Aktivni prijenosi",
"movies": "Movies", "movies": "Filmovi",
"tv": "TV Shows" "tv": "TV emisije"
}, },
"glances": { "glances": {
"cpu": "CPU", "cpu": "CPU",
"mem": "MEM", "mem": "MEM",
"wait": "Please wait" "wait": "Pričekaj"
}, },
"changedetectionio": { "changedetectionio": {
"totalObserved": "Total Observed", "totalObserved": "Ukupno promatrano",
"diffsDetected": "Diffs Detected" "diffsDetected": "Otkrivene razlike"
}, },
"wmo": { "wmo": {
"0-day": "Sunny", "0-day": "Sunčano",
"0-night": "Clear", "0-night": "Vedro",
"1-day": "Mainly Sunny", "1-day": "Pretežno sunčano",
"1-night": "Mainly Clear", "1-night": "Pretežno verdo",
"2-day": "Partly Cloudy", "2-day": "Djelimično oblačno",
"45-day": "Foggy", "45-day": "Maglovito",
"45-night": "Foggy", "45-night": "Maglovito",
"48-day": "Foggy", "48-day": "Maglovito",
"2-night": "Partly Cloudy", "2-night": "Djelimično oblačno",
"3-day": "Cloudy", "3-day": "Oblačno",
"3-night": "Cloudy", "3-night": "Oblačno",
"48-night": "Foggy", "48-night": "Maglovito",
"51-day": "Light Drizzle", "51-day": "Laka rosulja",
"51-night": "Light Drizzle", "51-night": "Laka rosulja",
"53-day": "Drizzle", "53-day": "Rosulja",
"53-night": "Drizzle", "53-night": "Rosulja",
"55-day": "Heavy Drizzle", "55-day": "Jaka rosulja",
"55-night": "Heavy Drizzle", "55-night": "Jaka rosulja",
"56-day": "Light Freezing Drizzle", "56-day": "Laka ledena rosulja",
"56-night": "Light Freezing Drizzle", "56-night": "Laka ledena rosulja",
"57-day": "Freezing Drizzle", "57-day": "Ledena rosulja",
"57-night": "Freezing Drizzle", "57-night": "Ledena rosulja",
"61-day": "Light Rain", "61-day": "Laka kiša",
"61-night": "Light Rain", "61-night": "Laka kiša",
"63-day": "Rain", "63-day": "Kiša",
"63-night": "Rain", "63-night": "Kiša",
"65-day": "Heavy Rain", "65-day": "Jaka kiša",
"65-night": "Heavy Rain", "65-night": "Jaka kiša",
"66-day": "Freezing Rain", "66-day": "Ledena kiša",
"66-night": "Freezing Rain", "66-night": "Ledena kiša",
"67-day": "Freezing Rain", "67-day": "Ledena kiša",
"67-night": "Freezing Rain", "67-night": "Ledena kiša",
"75-night": "Heavy Snow", "75-night": "Jaki snijeg",
"77-day": "Snow Grains", "77-day": "Zrnati snijeg",
"71-day": "Light Snow", "71-day": "Laki snijeg",
"71-night": "Light Snow", "71-night": "Laki snijeg",
"73-day": "Snow", "73-day": "Snijeg",
"73-night": "Snow", "73-night": "Snijeg",
"75-day": "Heavy Snow", "75-day": "Jaki snijeg",
"77-night": "Snow Grains", "77-night": "Zrnati snijeg",
"80-day": "Light Showers", "80-day": "Laki pljuskovi",
"80-night": "Light Showers", "80-night": "Laki pljuskovi",
"81-day": "Showers", "81-day": "Pljuskovi",
"81-night": "Showers", "81-night": "Pljuskovi",
"82-day": "Heavy Showers", "82-day": "Jaki pljuskovi",
"82-night": "Heavy Showers", "82-night": "Jaki pljuskovi",
"85-day": "Snow Showers", "85-day": "Snježni pljuskovi",
"85-night": "Snow Showers", "85-night": "Snježni pljuskovi",
"86-day": "Snow Showers", "86-day": "Snježni pljuskovi",
"86-night": "Snow Showers", "86-night": "Snježni pljuskovi",
"95-day": "Thunderstorm", "95-day": "Oluja",
"95-night": "Thunderstorm", "95-night": "Oluja",
"96-day": "Thunderstorm With Hail", "96-day": "Oluja s tučom",
"96-night": "Thunderstorm With Hail", "96-night": "Oluja s tučom",
"99-day": "Thunderstorm With Hail", "99-day": "Oluja s tučom",
"99-night": "Thunderstorm With Hail" "99-night": "Oluja s tučom"
}, },
"quicklaunch": { "quicklaunch": {
"bookmark": "Bookmark", "bookmark": "Straničnik",
"service": "Service" "service": "Usluga"
}, },
"homebridge": { "homebridge": {
"available_update": "System", "available_update": "Sustav",
"updates": "Updates", "updates": "Aktualiziranja",
"update_available": "Update Available", "update_available": "Dostupna je nova verzija",
"up_to_date": "Up to Date", "up_to_date": "Aktualno",
"child_bridges": "Child Bridges", "child_bridges": "Podređeni mosotvi",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"autobrr": {
"rejectedPushes": "Odbijeno",
"approvedPushes": "Odobreno",
"filters": "Filtri",
"indexers": "Indeksatori"
},
"watchtower": {
"containers_scanned": "Skenirano",
"containers_updated": "Aktualizirano",
"containers_failed": "Neuspjelo"
},
"tubearchivist": {
"downloads": "Red čekanja",
"videos": "Videa",
"channels": "Kanali",
"playlists": "Playliste"
},
"truenas": {
"load": "Opterećenje sustava",
"uptime": "Radno vrijeme",
"alerts": "Upozorenja",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "Nema aktivnih prijenosa",
"please_wait": "Pričekaj"
},
"pyload": {
"speed": "Brzina",
"active": "Aktivno",
"queue": "Red čekanja",
"total": "Ukupno"
},
"gluetun": {
"public_ip": "Javni IP",
"region": "Regija",
"country": "Zemlja"
},
"hdhomerun": {
"channels": "Kanali",
"hd": "HD"
},
"ping": {
"error": "Greška",
"ping": "Ping"
},
"scrutiny": {
"passed": "Prošlo",
"failed": "Neuspjelo",
"unknown": "Nepoznato"
},
"paperlessngx": {
"inbox": "Ulazni sandučić",
"total": "Ukupno"
},
"deluge": {
"download": "Preuzimanje",
"upload": "Prijenos",
"leech": "Leech",
"seed": "Seed"
},
"diskstation": {
"download": "Preuzimanje",
"upload": "Prijenos",
"leech": "Leech",
"seed": "Seed"
},
"flood": {
"download": "Preuzimanje",
"upload": "Prijenos",
"leech": "Leech",
"seed": "Seed"
} }
} }

View File

@ -11,7 +11,9 @@
"tx": "TX", "tx": "TX",
"mem": "MEM", "mem": "MEM",
"cpu": "CPU", "cpu": "CPU",
"offline": "Offline" "offline": "Offline",
"error": "Error",
"unknown": "Unknown"
}, },
"lidarr": { "lidarr": {
"albums": "Albumok", "albums": "Albumok",
@ -30,7 +32,11 @@
"widget": { "widget": {
"missing_type": "Hiányzó Widget Típus: {{type}}", "missing_type": "Hiányzó Widget Típus: {{type}}",
"api_error": "API Hiba", "api_error": "API Hiba",
"status": "Státusz" "status": "Státusz",
"information": "Information",
"url": "URL",
"raw_error": "Raw Error",
"response_data": "Response Data"
}, },
"weather": { "weather": {
"current": "Aktuális hely", "current": "Aktuális hely",
@ -104,7 +110,8 @@
"overseerr": { "overseerr": {
"pending": "Függőben", "pending": "Függőben",
"approved": "Engedélyezett", "approved": "Engedélyezett",
"available": "Elérhető" "available": "Elérhető",
"processing": "Processing"
}, },
"pihole": { "pihole": {
"queries": "Lekérdezések", "queries": "Lekérdezések",
@ -281,5 +288,78 @@
"up_to_date": "Up to Date", "up_to_date": "Up to Date",
"child_bridges": "Child Bridges", "child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"autobrr": {
"approvedPushes": "Approved",
"rejectedPushes": "Rejected",
"filters": "Filters",
"indexers": "Indexers"
},
"watchtower": {
"containers_scanned": "Scanned",
"containers_updated": "Updated",
"containers_failed": "Failed"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Videos",
"channels": "Channels",
"playlists": "Playlists"
},
"truenas": {
"load": "System Load",
"uptime": "Uptime",
"alerts": "Alerts",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"pyload": {
"speed": "Speed",
"active": "Active",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"error": "Error",
"ping": "Ping"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"download": "Download",
"seed": "Seed",
"upload": "Upload",
"leech": "Leech"
},
"diskstation": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"flood": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
} }
} }

View File

@ -4,7 +4,9 @@
"mem": "MEM", "mem": "MEM",
"cpu": "CPU", "cpu": "CPU",
"offline": "Offline", "offline": "Offline",
"rx": "RX" "rx": "RX",
"error": "Error",
"unknown": "Unknown"
}, },
"emby": { "emby": {
"playing": "In riproduzione", "playing": "In riproduzione",
@ -36,7 +38,11 @@
"widget": { "widget": {
"missing_type": "Tipo del Widget Mancante: {{type}}", "missing_type": "Tipo del Widget Mancante: {{type}}",
"api_error": "Errore API", "api_error": "Errore API",
"status": "Stato" "status": "Stato",
"url": "URL",
"information": "Information",
"raw_error": "Raw Error",
"response_data": "Response Data"
}, },
"search": { "search": {
"placeholder": "Cerca…" "placeholder": "Cerca…"
@ -98,7 +104,8 @@
"overseerr": { "overseerr": {
"pending": "In attesa", "pending": "In attesa",
"approved": "Approvati", "approved": "Approvati",
"available": "Disponibili" "available": "Disponibili",
"processing": "Processing"
}, },
"sabnzbd": { "sabnzbd": {
"rate": "Rapporto", "rate": "Rapporto",
@ -123,11 +130,11 @@
"messages": "Messaggi" "messages": "Messaggi"
}, },
"prowlarr": { "prowlarr": {
"enableIndexers": "Indexers", "enableIndexers": "Indicizzatori",
"numberOfGrabs": "Grabs", "numberOfGrabs": "Grabs",
"numberOfQueries": "Queries", "numberOfQueries": "Queries",
"numberOfFailGrabs": "Fail Grabs", "numberOfFailGrabs": "Grabs Falliti",
"numberOfFailQueries": "Fail Queries" "numberOfFailQueries": "Queries Fallite"
}, },
"transmission": { "transmission": {
"download": "Download", "download": "Download",
@ -184,7 +191,7 @@
}, },
"unifi": { "unifi": {
"users": "Utenti", "users": "Utenti",
"uptime": "System Uptime", "uptime": "Uptime di Sistema",
"days": "Giorni", "days": "Giorni",
"wan": "WAN", "wan": "WAN",
"lan_users": "Utenti LAN", "lan_users": "Utenti LAN",
@ -209,16 +216,16 @@
"wait": "Attendere prego" "wait": "Attendere prego"
}, },
"changedetectionio": { "changedetectionio": {
"totalObserved": "Total Observed", "totalObserved": "Totale Osservato",
"diffsDetected": "Diffs Detected" "diffsDetected": "Differenze Rilevate"
}, },
"wmo": { "wmo": {
"65-day": "Heavy Rain", "65-day": "Pioggia Intensa",
"2-night": "Parzialmente Nuvoloso", "2-night": "Parzialmente Nuvoloso",
"0-day": "Solleggiato", "0-day": "Solleggiato",
"0-night": "Clear", "0-night": "Pulisci",
"1-day": "Mainly Sunny", "1-day": "Principalmente Soleggiato",
"1-night": "Mainly Clear", "1-night": "Principalmente Sereno",
"2-day": "Parzialmente Nuvoloso", "2-day": "Parzialmente Nuvoloso",
"3-day": "Nuvoloso", "3-day": "Nuvoloso",
"3-night": "Nuvoloso", "3-night": "Nuvoloso",
@ -232,37 +239,37 @@
"53-night": "Pioggerella", "53-night": "Pioggerella",
"55-day": "Pioggerella Pesante", "55-day": "Pioggerella Pesante",
"55-night": "Pioggerella Pesante", "55-night": "Pioggerella Pesante",
"56-day": "Light Freezing Drizzle", "56-day": "Leggera Pioggia Gelata",
"56-night": "Light Freezing Drizzle", "56-night": "Leggera Pioggia Gelata",
"57-day": "Freezing Drizzle", "57-day": "Pioggerella Gelata",
"57-night": "Freezing Drizzle", "57-night": "Pioggerella Gelata",
"61-day": "Pioggia Leggera", "61-day": "Pioggia Leggera",
"61-night": "Pioggia Leggera", "61-night": "Pioggia Leggera",
"63-day": "Pioggia", "63-day": "Pioggia",
"63-night": "Pioggia", "63-night": "Pioggia",
"65-night": "Heavy Rain", "65-night": "Pioggia Intensa",
"66-day": "Grandine", "66-day": "Grandine",
"66-night": "Grandine", "66-night": "Grandine",
"67-day": "Grandine", "67-day": "Grandine",
"67-night": "Grandine", "67-night": "Grandine",
"71-day": "Light Snow", "71-day": "Leggera Nevicata",
"71-night": "Light Snow", "71-night": "Leggera Nevicata",
"73-day": "Neve", "73-day": "Neve",
"73-night": "Neve", "73-night": "Neve",
"75-day": "Heavy Snow", "75-day": "Nevicata Intensa",
"75-night": "Heavy Snow", "75-night": "Nevicata Intensa",
"77-day": "Snow Grains", "77-day": "Fiocchi di Neve",
"77-night": "Snow Grains", "77-night": "Fiocchi di Neve",
"80-day": "Light Showers", "80-day": "Leggeri Rovesci",
"80-night": "Light Showers", "80-night": "Leggeri Rovesci",
"81-day": "Showers", "81-day": "Rovesci",
"81-night": "Showers", "81-night": "Rovesci",
"82-day": "Heavy Showers", "82-day": "Intensi Rovesci",
"82-night": "Heavy Showers", "82-night": "Intensi Rovesci",
"85-day": "Snow Showers", "85-day": "Rovesci di Neve",
"85-night": "Snow Showers", "85-night": "Rovesci di Neve",
"86-day": "Snow Showers", "86-day": "Rovesci di Neve",
"86-night": "Snow Showers", "86-night": "Rovesci di Neve",
"95-day": "Temporale", "95-day": "Temporale",
"95-night": "Temporale", "95-night": "Temporale",
"96-day": "Temporale con grandine", "96-day": "Temporale con grandine",
@ -271,15 +278,88 @@
"99-night": "Temporale con grandine" "99-night": "Temporale con grandine"
}, },
"quicklaunch": { "quicklaunch": {
"bookmark": "Bookmark", "bookmark": "Segnalibro",
"service": "Servizio" "service": "Servizio"
}, },
"homebridge": { "homebridge": {
"available_update": "System", "available_update": "Sistema",
"updates": "Updates", "updates": "Aggiornamenti",
"update_available": "Update Available", "update_available": "Aggiornamento Disponibile",
"up_to_date": "Up to Date", "up_to_date": "Aggiornato",
"child_bridges": "Child Bridges", "child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"autobrr": {
"approvedPushes": "Approvato",
"rejectedPushes": "Rifiutato",
"filters": "Filtri",
"indexers": "Indicizzatori"
},
"watchtower": {
"containers_scanned": "Scansionato",
"containers_updated": "Aggiornato",
"containers_failed": "Fallito"
},
"tubearchivist": {
"downloads": "Coda",
"videos": "Video",
"channels": "Canali",
"playlists": "Playlists"
},
"truenas": {
"load": "Carico di Sistema",
"uptime": "Uptime",
"alerts": "Alerts",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "Nessun Sistema Attivo",
"please_wait": "Attendere, Prego"
},
"pyload": {
"speed": "Velocità",
"active": "Attivo",
"queue": "Coda",
"total": "Totale"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"error": "Error",
"ping": "Ping"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"diskstation": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"flood": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
} }
} }

View File

@ -0,0 +1,365 @@
{
"resources": {
"cpu": "CPU",
"total": "Jumlah",
"free": "Bebas",
"used": "Telah diguna",
"load": "Beban"
},
"unifi": {
"uptime": "Masa Operasi Sistem",
"users": "Pengguna",
"days": "Hari",
"wan": "WAN",
"lan": "LAN",
"wlan": "WLAN",
"devices": "Peranti",
"lan_devices": "Peranti LAN",
"wlan_devices": "Peranti WLAN",
"lan_users": "Pengguna LAN",
"wlan_users": "Pengguna WLAN",
"up": "HIDUP",
"down": "MATI",
"wait": "Sila tunggu"
},
"lidarr": {
"queued": "Dibaris Gilir",
"albums": "Album",
"wanted": "Mahu"
},
"readarr": {
"wanted": "Mahu",
"queued": "Dibaris Gilir",
"books": "Buku"
},
"jellyseerr": {
"pending": "Tertangguh",
"approved": "Lulus",
"available": "Sudah Ada"
},
"coinmarketcap": {
"30days": "30 Hari",
"configure": "Konfigurasikan satu atau lebih matawang crypto untuk dipantau",
"1hour": "1 Jam",
"1day": "1 Hari",
"7days": "7 Hari"
},
"gotify": {
"apps": "Aplikasi",
"clients": "Klien",
"messages": "Mesej"
},
"proxmox": {
"mem": "MEM",
"cpu": "CPU",
"lxc": "LXC",
"vms": "Mesin Maya"
},
"glances": {
"cpu": "CPU",
"mem": "MEM",
"wait": "Sila tunggu"
},
"quicklaunch": {
"bookmark": "Tandabuku",
"service": "Servis"
},
"wmo": {
"0-day": "Terik",
"0-night": "Cerah",
"1-day": "Sebahagian Besar Terik",
"1-night": "Sebahagian Besar Cerah",
"63-day": "Hujan",
"63-night": "Hujan",
"2-day": "Sebahagian Mendung",
"2-night": "Sebahagian Mendung",
"3-day": "Mendung",
"3-night": "Mendung",
"45-day": "Berkabus",
"45-night": "Berkabus",
"48-day": "Berkabus",
"48-night": "Berkabus",
"51-day": "Gerimis",
"51-night": "Gerimis",
"53-day": "Renyai",
"53-night": "Renyai",
"55-day": "Renyai Kuat",
"55-night": "Renyai Kuat",
"56-day": "Gerimis Sejuk Ringan",
"56-night": "Gerimis Sejuk Ringan",
"57-day": "Gerimis Sejuk",
"57-night": "Gerimis Sejuk",
"61-day": "Hujan Renyai",
"61-night": "Hujan Renyai",
"65-day": "Hujan Lebat",
"65-night": "Hujan Lebat",
"66-day": "Hujan Sejuk",
"66-night": "Hujan Sejuk",
"67-day": "Hujan Sejuk",
"67-night": "Hujan Sejuk",
"71-day": "Salji Ringan",
"71-night": "Salji Ringan",
"73-day": "Salji",
"73-night": "Salji",
"75-day": "Salji Lebat",
"75-night": "Salji Lebat",
"81-day": "Rintik",
"77-day": "Butiran Salji",
"77-night": "Butiran Salji",
"80-day": "Rintik Ringan",
"80-night": "Rintik Ringan",
"81-night": "Rintik",
"82-day": "Rintik Lebat",
"82-night": "Rintik Lebat",
"85-day": "Rintik Salji",
"85-night": "Rintik Salji",
"86-day": "Rintik Salji",
"86-night": "Rintik Salji",
"95-day": "Ribut",
"95-night": "Ribut",
"96-day": "Ribut Hujan Batu",
"96-night": "Ribut Hujan Batu",
"99-day": "Ribut Hujan Batu",
"99-night": "Ribut Hujan Batu"
},
"widget": {
"missing_type": "Jenis Widget Hilang: {{type}}",
"api_error": "Masalah API",
"status": "Status",
"information": "Informasi",
"url": "URL",
"raw_error": "Ralat Mentah",
"response_data": "Data Respon"
},
"weather": {
"current": "Lokasi Sekarang",
"allow": "Klik untuk benarkan",
"updating": "Mengemas kini",
"wait": "Sila tunggu"
},
"search": {
"placeholder": "Carian…"
},
"nzbget": {
"remaining": "Baki",
"downloaded": "Telah Muat Turun",
"rate": "Kadar"
},
"docker": {
"rx": "RX",
"tx": "TX",
"mem": "MEM",
"cpu": "CPU",
"offline": "Luar talian",
"error": "Ralat",
"unknown": "Tidak Diketahui"
},
"changedetectionio": {
"totalObserved": "Jumlah Diperhatikan",
"diffsDetected": "Perbezaan Dikesan"
},
"emby": {
"playing": "Sedang dimainkan",
"transcoding": "Transkoding",
"bitrate": "Kadar bit",
"no_active": "Tiada Strim Aktif"
},
"tautulli": {
"playing": "Sedang Dimainkan",
"transcoding": "Transkoding",
"bitrate": "Kadar bit",
"no_active": "Tiada Strim Aktif"
},
"plex": {
"streams": "Strim Aktif",
"movies": "Filem",
"tv": "Rancangan TV"
},
"sabnzbd": {
"rate": "Kadar",
"queue": "Barisan",
"timeleft": "Masa Tinggal"
},
"rutorrent": {
"active": "Aktif",
"upload": "Muat Naik",
"download": "Muat Turun"
},
"transmission": {
"leech": "Leech",
"download": "Muat Turun",
"upload": "Muat Naik",
"seed": "Seed"
},
"qbittorrent": {
"download": "Muat Turun",
"upload": "Muat Naik",
"leech": "Leech",
"seed": "Seed"
},
"sonarr": {
"wanted": "Mahu",
"queued": "Dibaris Gilir",
"series": "Bersiri"
},
"radarr": {
"wanted": "Mahu",
"missing": "Hilang",
"queued": "Dibaris Gilir",
"movies": "Filem"
},
"bazarr": {
"missingEpisodes": "Episod Yang Hilang",
"missingMovies": "Filem Yang Hilang"
},
"ombi": {
"pending": "Tertunda",
"approved": "Lulus",
"available": "Sudah Ada"
},
"overseerr": {
"pending": "Tertangguh",
"approved": "Lulus",
"available": "Sudah Ada",
"processing": "Processing"
},
"pihole": {
"queries": "Permintaan",
"blocked": "Disekat",
"gravity": "Gravity"
},
"adguard": {
"queries": "Permintaan",
"blocked": "Disekat",
"filtered": "Ditapis",
"latency": "Kependaman"
},
"speedtest": {
"upload": "Muat Naik",
"download": "Muat Turun",
"ping": "Ping"
},
"portainer": {
"running": "Sedang Berjalan",
"stopped": "Terhenti",
"total": "Jumlah"
},
"traefik": {
"routers": "Router",
"services": "Servis",
"middleware": "Perisian Tengah"
},
"npm": {
"enabled": "Didayakan",
"disabled": "Dinyahdayakan",
"total": "Jumlah"
},
"prowlarr": {
"enableIndexers": "Pengindeks",
"numberOfGrabs": "Capai",
"numberOfQueries": "Permintaan",
"numberOfFailGrabs": "Capai Yang Ggagal",
"numberOfFailQueries": "Permintaan Yang Gagal"
},
"jackett": {
"configured": "Telah Dikonfigurasi",
"errored": "Telah Tersalah"
},
"strelaysrv": {
"numActiveSessions": "Sesi",
"numConnections": "Penyambungan",
"dataRelayed": "Disalurkan",
"transferRate": "Kadar"
},
"mastodon": {
"user_count": "Pengguna",
"status_count": "Pos",
"domain_count": "Domain"
},
"authentik": {
"users": "Pengguna",
"loginsLast24H": "Logmasuk (24j)",
"failedLoginsLast24H": "Logmasuk Gagal (24j)"
},
"homebridge": {
"child_bridges_status": "{{ok}}/{{total}}",
"available_update": "Sistem",
"updates": "Kemaskini",
"update_available": "Kemaskini Tersedia",
"up_to_date": "Terkemaskini",
"child_bridges": "Jambatan Anak"
},
"watchtower": {
"containers_scanned": "Terimbas",
"containers_updated": "Dikemaskini",
"containers_failed": "Gagal"
},
"autobrr": {
"approvedPushes": "Lulus",
"rejectedPushes": "Ditolak",
"filters": "Tapisan",
"indexers": "Pengindeks"
},
"tubearchivist": {
"downloads": "Baris Gilir",
"videos": "Video",
"channels": "Saluran",
"playlists": "Senarai Siar"
},
"truenas": {
"load": "Beban Sistem",
"uptime": "Masa Hidup",
"alerts": "Amaran",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "Tiada Strim Aktif",
"please_wait": "Sila tunggu"
},
"pyload": {
"speed": "Kelajuan",
"active": "Aktif",
"queue": "Baris Gilir",
"total": "Jumlah"
},
"gluetun": {
"public_ip": "IP Awam",
"region": "Rantau",
"country": "Negara"
},
"hdhomerun": {
"channels": "Saluran",
"hd": "HD"
},
"ping": {
"error": "Ralat",
"ping": "Ping"
},
"scrutiny": {
"passed": "Lulus",
"failed": "Gagal",
"unknown": "Tidak Diketahui"
},
"paperlessngx": {
"inbox": "Peti Masuk",
"total": "Jumlah"
},
"deluge": {
"download": "Muat Turun",
"upload": "Muat Naik",
"leech": "Leech",
"seed": "Seed"
},
"diskstation": {
"upload": "Upload",
"download": "Download",
"leech": "Leech",
"seed": "Seed"
},
"flood": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
}
}

View File

@ -2,7 +2,11 @@
"widget": { "widget": {
"missing_type": "Manglende miniprogramstype: {{type}}", "missing_type": "Manglende miniprogramstype: {{type}}",
"api_error": "API-feil", "api_error": "API-feil",
"status": "Status" "status": "Status",
"information": "Information",
"url": "URL",
"raw_error": "Raw Error",
"response_data": "Response Data"
}, },
"search": { "search": {
"placeholder": "Søk …" "placeholder": "Søk …"
@ -19,7 +23,9 @@
"tx": "Sendt", "tx": "Sendt",
"mem": "Minne", "mem": "Minne",
"cpu": "Prosessor", "cpu": "Prosessor",
"offline": "Frakoblet" "offline": "Frakoblet",
"error": "Error",
"unknown": "Unknown"
}, },
"emby": { "emby": {
"playing": "Spiller", "playing": "Spiller",
@ -98,7 +104,8 @@
"overseerr": { "overseerr": {
"pending": "Venter", "pending": "Venter",
"approved": "Godkjent", "approved": "Godkjent",
"available": "Tilgjengelig" "available": "Tilgjengelig",
"processing": "Processing"
}, },
"sabnzbd": { "sabnzbd": {
"rate": "Takt", "rate": "Takt",
@ -281,5 +288,78 @@
"up_to_date": "Up to Date", "up_to_date": "Up to Date",
"child_bridges": "Child Bridges", "child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"autobrr": {
"approvedPushes": "Approved",
"rejectedPushes": "Rejected",
"filters": "Filters",
"indexers": "Indexers"
},
"watchtower": {
"containers_scanned": "Scanned",
"containers_updated": "Updated",
"containers_failed": "Failed"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Videos",
"channels": "Channels",
"playlists": "Playlists"
},
"truenas": {
"load": "System Load",
"uptime": "Uptime",
"alerts": "Alerts",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"pyload": {
"speed": "Speed",
"active": "Active",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"error": "Error",
"ping": "Ping"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"leech": "Leech",
"download": "Download",
"upload": "Upload",
"seed": "Seed"
},
"diskstation": {
"leech": "Leech",
"download": "Download",
"upload": "Upload",
"seed": "Seed"
},
"flood": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
} }
} }

View File

@ -2,7 +2,11 @@
"widget": { "widget": {
"missing_type": "Missing Widget Type: {{type}}", "missing_type": "Missing Widget Type: {{type}}",
"api_error": "API Error", "api_error": "API Error",
"status": "Status" "status": "Status",
"information": "Information",
"url": "URL",
"raw_error": "Raw Error",
"response_data": "Response Data"
}, },
"resources": { "resources": {
"total": "Totaal", "total": "Totaal",
@ -16,7 +20,9 @@
"tx": "TX", "tx": "TX",
"mem": "MEM", "mem": "MEM",
"cpu": "CPU", "cpu": "CPU",
"offline": "Offline" "offline": "Offline",
"error": "Error",
"unknown": "Unknown"
}, },
"speedtest": { "speedtest": {
"upload": "Upload", "upload": "Upload",
@ -98,7 +104,8 @@
"overseerr": { "overseerr": {
"pending": "Pending", "pending": "Pending",
"approved": "Approved", "approved": "Approved",
"available": "Available" "available": "Available",
"processing": "Processing"
}, },
"sabnzbd": { "sabnzbd": {
"rate": "Rate", "rate": "Rate",
@ -281,5 +288,78 @@
"up_to_date": "Up to Date", "up_to_date": "Up to Date",
"child_bridges": "Child Bridges", "child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"autobrr": {
"approvedPushes": "Approved",
"rejectedPushes": "Rejected",
"filters": "Filters",
"indexers": "Indexers"
},
"watchtower": {
"containers_scanned": "Scanned",
"containers_updated": "Updated",
"containers_failed": "Failed"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Videos",
"channels": "Channels",
"playlists": "Playlists"
},
"truenas": {
"load": "System Load",
"uptime": "Uptime",
"alerts": "Alerts",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"pyload": {
"speed": "Speed",
"active": "Active",
"total": "Total",
"queue": "Queue"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"error": "Error",
"ping": "Ping"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"diskstation": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"flood": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
} }
} }

View File

@ -52,14 +52,20 @@
"widget": { "widget": {
"missing_type": "Brakujący typ widżetu: {{type}}", "missing_type": "Brakujący typ widżetu: {{type}}",
"api_error": "Błąd API", "api_error": "Błąd API",
"status": "Stan" "status": "Stan",
"url": "Adres URL",
"information": "Informacje",
"raw_error": "Niesformatowany błąd",
"response_data": "Dane odpowiedzi"
}, },
"docker": { "docker": {
"rx": "RX", "rx": "Rx",
"tx": "TX", "tx": "Tx",
"mem": "MEM", "mem": "Pamięć",
"cpu": "CPU", "cpu": "Procesor",
"offline": "Offline" "offline": "Offline",
"error": "Błąd",
"unknown": "Nieznany"
}, },
"nzbget": { "nzbget": {
"rate": "Szybkość", "rate": "Szybkość",
@ -91,7 +97,7 @@
"wanted": "Poszukiwane", "wanted": "Poszukiwane",
"queued": "W kolejce", "queued": "W kolejce",
"movies": "Filmy", "movies": "Filmy",
"missing": "Missing" "missing": "Brakujące"
}, },
"lidarr": { "lidarr": {
"wanted": "Poszukiwane", "wanted": "Poszukiwane",
@ -120,7 +126,8 @@
"overseerr": { "overseerr": {
"pending": "Oczekiwane", "pending": "Oczekiwane",
"approved": "Zaakceptowane", "approved": "Zaakceptowane",
"available": "Dostępne" "available": "Dostępne",
"processing": "Przetwarzane"
}, },
"pihole": { "pihole": {
"queries": "Zapytania", "queries": "Zapytania",
@ -149,27 +156,27 @@
"errored": "Błędne" "errored": "Błędne"
}, },
"adguard": { "adguard": {
"queries": "Queries", "queries": "Zapytania",
"blocked": "Blocked", "blocked": "Zablokowane",
"filtered": "Filtered", "filtered": "Przefiltrowane",
"latency": "Latency" "latency": "Opóźnienia"
}, },
"qbittorrent": { "qbittorrent": {
"download": "Download", "download": "Pobieranie",
"upload": "Upload", "upload": "Wysyłanie",
"leech": "Leech", "leech": "Leech",
"seed": "Seed" "seed": "Seed"
}, },
"mastodon": { "mastodon": {
"user_count": "Użytkownicy", "user_count": "Użytkownicy",
"status_count": "Posts", "status_count": "Posty",
"domain_count": "Domeny" "domain_count": "Domeny"
}, },
"strelaysrv": { "strelaysrv": {
"numActiveSessions": "Sesje", "numActiveSessions": "Sesje",
"numConnections": "Połączenia", "numConnections": "Połączenia",
"dataRelayed": "Relayed", "dataRelayed": "Przekazane",
"transferRate": "Rate" "transferRate": "Przesył"
}, },
"authentik": { "authentik": {
"users": "Użytkownicy", "users": "Użytkownicy",
@ -177,109 +184,182 @@
"failedLoginsLast24H": "Nieudane logowania (24h)" "failedLoginsLast24H": "Nieudane logowania (24h)"
}, },
"proxmox": { "proxmox": {
"mem": "MEM", "mem": "Pamięć",
"cpu": "CPU", "cpu": "Procesor",
"lxc": "LXC", "lxc": "Kontenery LXC",
"vms": "VMs" "vms": "Maszyn wirtualnych"
}, },
"unifi": { "unifi": {
"users": "Użytkownicy", "users": "Użytkownicy",
"uptime": "Czas pracy systemu", "uptime": "Czas pracy systemu",
"days": "Dni", "days": "Dni",
"wan": "WAN", "wan": "WAN",
"lan_users": "LAN Users", "lan_users": "Użytkownicy LAN",
"wlan_users": "WLAN Users", "wlan_users": "Użytkownicy WLAN",
"up": "UP", "up": "Wysyłanie",
"down": "DOWN", "down": "Pobieranie",
"wait": "Please wait", "wait": "Proszę czekać",
"lan": "LAN", "lan": "LAN",
"wlan": "WLAN", "wlan": "WLAN",
"devices": "Devices", "devices": "Urządzenia",
"lan_devices": "LAN Devices", "lan_devices": "Urządzenia LAN",
"wlan_devices": "WLAN Devices" "wlan_devices": "Urządzenia WLAN"
}, },
"plex": { "plex": {
"streams": "Active Streams", "streams": "Aktywne strumienie",
"movies": "Movies", "movies": "Filmy",
"tv": "TV Shows" "tv": "Seriale"
}, },
"glances": { "glances": {
"cpu": "CPU", "cpu": "Procesor",
"mem": "MEM", "mem": "Pamięć",
"wait": "Please wait" "wait": "Proszę czekać"
}, },
"changedetectionio": { "changedetectionio": {
"diffsDetected": "Diffs Detected", "diffsDetected": "Wykryto różnic",
"totalObserved": "Total Observed" "totalObserved": "Obserwowanych ogółem"
}, },
"wmo": { "wmo": {
"77-day": "Snow Grains", "77-day": "Ziarnisty śnieg",
"0-day": "Słoneczny", "0-day": "Słoneczny",
"0-night": "Clear", "0-night": "Bezchmurny",
"1-day": "Mainly Sunny", "1-day": "Głównie słoneczny",
"1-night": "Mainly Clear", "1-night": "Głównie bezchmurny",
"2-day": "Partly Cloudy", "2-day": "Częściowo pochmurnie",
"2-night": "Partly Cloudy", "2-night": "Częściowo pochmurnie",
"3-day": "Cloudy", "3-day": "Pochmurnie",
"3-night": "Cloudy", "3-night": "Pochmurnie",
"45-day": "Foggy", "45-day": "Mgliście",
"45-night": "Foggy", "45-night": "Mgliście",
"48-day": "Foggy", "48-day": "Mgliście",
"48-night": "Foggy", "48-night": "Mgliście",
"51-day": "Light Drizzle", "51-day": "Lekka mżawka",
"51-night": "Light Drizzle", "51-night": "Lekka mżawka",
"53-day": "Drizzle", "53-day": "Mżawka",
"53-night": "Drizzle", "53-night": "Mżawka",
"55-day": "Heavy Drizzle", "55-day": "Ciężka mżawka",
"55-night": "Heavy Drizzle", "55-night": "Ciężka mżawka",
"56-day": "Light Freezing Drizzle", "56-day": "Lekko chłodna mżawka",
"56-night": "Light Freezing Drizzle", "56-night": "Lekko chłodna mżawka",
"57-day": "Freezing Drizzle", "57-day": "Chłodna mżawka",
"57-night": "Freezing Drizzle", "57-night": "Chłodna mżawka",
"61-day": "Light Rain", "61-day": "Lekki deszcz",
"61-night": "Light Rain", "61-night": "Lekki deszcz",
"63-day": "Rain", "63-day": "Deszcz",
"63-night": "Rain", "63-night": "Deszcz",
"65-day": "Heavy Rain", "65-day": "Ciężki deszcz",
"65-night": "Heavy Rain", "65-night": "Ciężki deszcz",
"66-day": "Freezing Rain", "66-day": "Mroźny deszcz",
"66-night": "Freezing Rain", "66-night": "Mroźny deszcz",
"67-day": "Freezing Rain", "67-day": "Mroźny deszcz",
"67-night": "Freezing Rain", "67-night": "Mroźny deszcz",
"71-day": "Light Snow", "71-day": "Lekki śnieg",
"71-night": "Light Snow", "71-night": "Lekki śnieg",
"73-day": "Snow", "73-day": "Śnieg",
"73-night": "Snow", "73-night": "Śnieg",
"75-day": "Heavy Snow", "75-day": "Ciężki śnieg",
"75-night": "Heavy Snow", "75-night": "Ciężki śnieg",
"77-night": "Snow Grains", "77-night": "Ziarnisty śnieg",
"80-day": "Light Showers", "80-day": "Lekkie opady",
"80-night": "Light Showers", "80-night": "Lekkie opady",
"81-day": "Showers", "81-day": "Opady",
"81-night": "Showers", "81-night": "Opady",
"82-day": "Heavy Showers", "82-day": "Ciężkie opady",
"82-night": "Heavy Showers", "82-night": "Ciężkie opady",
"85-day": "Snow Showers", "85-day": "Opady śniegu",
"85-night": "Snow Showers", "85-night": "Opady śniegu",
"86-day": "Snow Showers", "86-day": "Opady śniegu",
"86-night": "Snow Showers", "86-night": "Opady śniegu",
"95-day": "Thunderstorm", "95-day": "Burze z piorunami",
"95-night": "Thunderstorm", "95-night": "Burze z piorunami",
"96-day": "Thunderstorm With Hail", "96-day": "Burza z gradobiciem",
"96-night": "Thunderstorm With Hail", "96-night": "Burza z gradobiciem",
"99-day": "Thunderstorm With Hail", "99-day": "Burza z gradobiciem",
"99-night": "Thunderstorm With Hail" "99-night": "Burza z gradobiciem"
}, },
"quicklaunch": { "quicklaunch": {
"bookmark": "Bookmark", "bookmark": "Zakładka",
"service": "Service" "service": "Usługi"
}, },
"homebridge": { "homebridge": {
"available_update": "System", "available_update": "System",
"updates": "Updates", "updates": "Aktualizacje",
"update_available": "Update Available", "update_available": "Dostępna aktualizacja",
"up_to_date": "Up to Date", "up_to_date": "Aktualny",
"child_bridges": "Child Bridges", "child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"autobrr": {
"approvedPushes": "Zaakceptowane",
"rejectedPushes": "Odrzucone",
"filters": "Filtry",
"indexers": "Indeksery"
},
"watchtower": {
"containers_scanned": "Zeskanowane",
"containers_updated": "Zaktualizowane",
"containers_failed": "Niepowodzenie"
},
"tubearchivist": {
"downloads": "Kolejka",
"videos": "Pliki wideo",
"channels": "Kanały",
"playlists": "Playlisty"
},
"truenas": {
"load": "Obciążenie systemu",
"uptime": "Czas działania",
"alerts": "Ostrzeżenia",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"please_wait": "Proszę czekać",
"nothing_streaming": "Brak aktywnych strumieni"
},
"pyload": {
"speed": "Prędkość",
"active": "Aktywne",
"queue": "Kolejka",
"total": "Razem"
},
"gluetun": {
"public_ip": "Adres publiczny",
"region": "Region",
"country": "Państwo"
},
"hdhomerun": {
"channels": "Kanały",
"hd": "HD"
},
"ping": {
"error": "Błąd",
"ping": "Ping"
},
"scrutiny": {
"passed": "Powodzenie",
"failed": "Niepowodzenie",
"unknown": "Nieznane"
},
"paperlessngx": {
"inbox": "Skrzynka odbiorcza",
"total": "W sumie"
},
"deluge": {
"download": "Pobieranie",
"upload": "Wysyłanie",
"leech": "Leech",
"seed": "Seed"
},
"diskstation": {
"download": "Pobieranie",
"upload": "Wysyłanie",
"leech": "Leech",
"seed": "Seed"
},
"flood": {
"download": "Pobieranie",
"upload": "Wysyłanie",
"leech": "Leech",
"seed": "Seed"
} }
} }

View File

@ -30,7 +30,11 @@
"widget": { "widget": {
"missing_type": "Tipo de Widget ausente: {{type}}", "missing_type": "Tipo de Widget ausente: {{type}}",
"api_error": "Erro da API", "api_error": "Erro da API",
"status": "Status" "status": "Status",
"information": "Information",
"url": "URL",
"raw_error": "Raw Error",
"response_data": "Response Data"
}, },
"weather": { "weather": {
"current": "Localização atual", "current": "Localização atual",
@ -53,7 +57,9 @@
"tx": "Tx", "tx": "Tx",
"mem": "Mem", "mem": "Mem",
"cpu": "CPU", "cpu": "CPU",
"offline": "Desligado" "offline": "Desligado",
"error": "Error",
"unknown": "Unknown"
}, },
"emby": { "emby": {
"playing": "Reproduzindo", "playing": "Reproduzindo",
@ -122,7 +128,8 @@
"overseerr": { "overseerr": {
"pending": "Pendente", "pending": "Pendente",
"approved": "Aprovado", "approved": "Aprovado",
"available": "Disponível" "available": "Disponível",
"processing": "Processing"
}, },
"pihole": { "pihole": {
"queries": "Consultas", "queries": "Consultas",
@ -209,8 +216,8 @@
"wait": "Please wait" "wait": "Please wait"
}, },
"changedetectionio": { "changedetectionio": {
"totalObserved": "Total Observed", "totalObserved": "Observados",
"diffsDetected": "Diffs Detected" "diffsDetected": "Mudanças"
}, },
"wmo": { "wmo": {
"1-night": "Mainly Clear", "1-night": "Mainly Clear",
@ -281,5 +288,78 @@
"up_to_date": "Up to Date", "up_to_date": "Up to Date",
"child_bridges": "Child Bridges", "child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"autobrr": {
"approvedPushes": "Approved",
"rejectedPushes": "Rejected",
"filters": "Filters",
"indexers": "Indexers"
},
"watchtower": {
"containers_scanned": "Scanned",
"containers_updated": "Updated",
"containers_failed": "Failed"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Videos",
"channels": "Channels",
"playlists": "Playlists"
},
"truenas": {
"load": "System Load",
"uptime": "Uptime",
"alerts": "Alerts",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"pyload": {
"speed": "Speed",
"active": "Active",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"error": "Error",
"ping": "Ping"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"diskstation": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"flood": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
} }
} }

View File

@ -2,7 +2,11 @@
"widget": { "widget": {
"missing_type": "Widget ausente: {{type}}", "missing_type": "Widget ausente: {{type}}",
"api_error": "Erro da API", "api_error": "Erro da API",
"status": "Status" "status": "Status",
"information": "Informação",
"url": "Endereço URL",
"raw_error": "Raw Error",
"response_data": "Dados da Resposta"
}, },
"search": { "search": {
"placeholder": "Pesquisar…" "placeholder": "Pesquisar…"
@ -19,7 +23,9 @@
"tx": "Tx", "tx": "Tx",
"mem": "Mem", "mem": "Mem",
"cpu": "CPU", "cpu": "CPU",
"offline": "Desligado" "offline": "Desligado",
"error": "Erro",
"unknown": "Desconhecido"
}, },
"emby": { "emby": {
"playing": "A reproduzir", "playing": "A reproduzir",
@ -109,7 +115,8 @@
"overseerr": { "overseerr": {
"pending": "Pendente", "pending": "Pendente",
"approved": "Aprovado", "approved": "Aprovado",
"available": "Disponível" "available": "Disponível",
"processing": "Processing"
}, },
"sabnzbd": { "sabnzbd": {
"rate": "Taxa", "rate": "Taxa",
@ -143,7 +150,7 @@
"transmission": { "transmission": {
"download": "Baixando", "download": "Baixando",
"upload": "Enviando", "upload": "Enviando",
"leech": "Sanguessugas", "leech": "Leech",
"seed": "Semeadores" "seed": "Semeadores"
}, },
"jackett": { "jackett": {
@ -194,25 +201,25 @@
"vms": "VMs" "vms": "VMs"
}, },
"unifi": { "unifi": {
"users": "Users", "users": "Utilizadores",
"uptime": "System Uptime", "uptime": "Tempo de Atividade do Sistema",
"days": "Days", "days": "Dias",
"wan": "WAN", "wan": "WAN",
"lan_users": "LAN Users", "lan_users": "Utilizadores LAN",
"wlan_users": "WLAN Users", "wlan_users": "Utilizadores WLAN",
"up": "UP", "up": "UP",
"down": "DOWN", "down": "DOWN",
"wait": "Please wait", "wait": "Por favor aguarde",
"lan": "LAN", "lan": "LAN",
"wlan": "WLAN", "wlan": "WLAN",
"devices": "Devices", "devices": "Dispositivos",
"lan_devices": "LAN Devices", "lan_devices": "Dispositivos LAN",
"wlan_devices": "WLAN Devices" "wlan_devices": "Dispositivos WLAN"
}, },
"plex": { "plex": {
"streams": "Active Streams", "streams": "Streams Ativas",
"movies": "Movies", "movies": "Filmes",
"tv": "TV Shows" "tv": "Series de TV"
}, },
"glances": { "glances": {
"cpu": "CPU", "cpu": "CPU",
@ -220,8 +227,8 @@
"wait": "Please wait" "wait": "Please wait"
}, },
"changedetectionio": { "changedetectionio": {
"totalObserved": "Total Observed", "totalObserved": "Total Observado",
"diffsDetected": "Diffs Detected" "diffsDetected": "Diferenças Detetadas"
}, },
"wmo": { "wmo": {
"0-day": "Sunny", "0-day": "Sunny",
@ -292,5 +299,78 @@
"up_to_date": "Up to Date", "up_to_date": "Up to Date",
"child_bridges": "Child Bridges", "child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"autobrr": {
"approvedPushes": "Approved",
"rejectedPushes": "Rejected",
"filters": "Filters",
"indexers": "Indexers"
},
"watchtower": {
"containers_scanned": "Scanned",
"containers_updated": "Updated",
"containers_failed": "Failed"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Videos",
"channels": "Channels",
"playlists": "Playlists"
},
"truenas": {
"load": "System Load",
"uptime": "Uptime",
"alerts": "Alerts",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"pyload": {
"queue": "Queue",
"total": "Total",
"speed": "Speed",
"active": "Active"
},
"gluetun": {
"region": "Region",
"country": "Country",
"public_ip": "Public IP"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"error": "Erro",
"ping": "Ping"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"diskstation": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"flood": {
"download": "Descarregar",
"upload": "Carregar",
"leech": "Leech",
"seed": "Seed"
} }
} }

View File

@ -11,7 +11,9 @@
"tx": "TX", "tx": "TX",
"mem": "MEM", "mem": "MEM",
"cpu": "CPU", "cpu": "CPU",
"offline": "Offline" "offline": "Offline",
"error": "Error",
"unknown": "Unknown"
}, },
"jellyseerr": { "jellyseerr": {
"approved": "Aprobate", "approved": "Aprobate",
@ -21,7 +23,8 @@
"overseerr": { "overseerr": {
"pending": "În așteptare", "pending": "În așteptare",
"approved": "Aprobate", "approved": "Aprobate",
"available": "Disponibile" "available": "Disponibile",
"processing": "Processing"
}, },
"pihole": { "pihole": {
"queries": "Cereri", "queries": "Cereri",
@ -60,7 +63,11 @@
"widget": { "widget": {
"missing_type": "Lipsește Tipul de Widget: {{type}}", "missing_type": "Lipsește Tipul de Widget: {{type}}",
"api_error": "Eroare API", "api_error": "Eroare API",
"status": "Status" "status": "Status",
"information": "Information",
"url": "URL",
"raw_error": "Raw Error",
"response_data": "Response Data"
}, },
"search": { "search": {
"placeholder": "Caută…" "placeholder": "Caută…"
@ -281,5 +288,78 @@
"available_update": "System", "available_update": "System",
"updates": "Updates", "updates": "Updates",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"autobrr": {
"approvedPushes": "Approved",
"rejectedPushes": "Rejected",
"filters": "Filters",
"indexers": "Indexers"
},
"watchtower": {
"containers_scanned": "Scanned",
"containers_updated": "Updated",
"containers_failed": "Failed"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Videos",
"channels": "Channels",
"playlists": "Playlists"
},
"truenas": {
"load": "System Load",
"uptime": "Uptime",
"alerts": "Alerts",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"pyload": {
"speed": "Speed",
"active": "Active",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"error": "Error",
"ping": "Ping"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"diskstation": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"flood": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
} }
} }

View File

@ -2,7 +2,11 @@
"widget": { "widget": {
"missing_type": "Отсутствует тип виджета: {{type}}", "missing_type": "Отсутствует тип виджета: {{type}}",
"api_error": "Ошибка API", "api_error": "Ошибка API",
"status": "Статус" "status": "Статус",
"information": "Информация",
"url": "URL",
"raw_error": "Raw Error",
"response_data": "Данные ответа"
}, },
"search": { "search": {
"placeholder": "Поиск…" "placeholder": "Поиск…"
@ -11,21 +15,23 @@
"total": "Всего", "total": "Всего",
"free": "Свободно", "free": "Свободно",
"used": "Использовано", "used": "Использовано",
"load": "Load", "load": "Загрузка",
"cpu": "CPU" "cpu": "Процессор"
}, },
"docker": { "docker": {
"rx": "Rx", "rx": "Rx",
"tx": "Тx", "tx": "Тx",
"mem": "Память", "mem": "Память",
"cpu": "Процессор", "cpu": "Процессор",
"offline": "Не в сети" "offline": "Не в сети",
"error": "Ошибка",
"unknown": "Неизвестный"
}, },
"emby": { "emby": {
"playing": "Воспроизведение", "playing": "Воспроизведение",
"transcoding": "Транскодирование", "transcoding": "Транскодирование",
"bitrate": "Битрейт", "bitrate": "Битрейт",
"no_active": "No Active Streams" "no_active": "Нет активных потоков"
}, },
"tautulli": { "tautulli": {
"playing": "Воспроизведение", "playing": "Воспроизведение",
@ -98,7 +104,8 @@
"overseerr": { "overseerr": {
"pending": "Pending", "pending": "Pending",
"approved": "Approved", "approved": "Approved",
"available": "Available" "available": "Available",
"processing": "Processing"
}, },
"sabnzbd": { "sabnzbd": {
"rate": "Rate", "rate": "Rate",
@ -183,19 +190,19 @@
"vms": "VMs" "vms": "VMs"
}, },
"unifi": { "unifi": {
"users": "Users", "users": "Пользователи",
"uptime": "System Uptime", "uptime": "Время работы системы",
"days": "Days", "days": "Дней",
"wan": "WAN", "wan": "WAN",
"lan_users": "LAN Users", "lan_users": "Пользователи LAN",
"wlan_users": "WLAN Users", "wlan_users": "Пользователи WLAN",
"up": "UP", "up": "UP",
"down": "DOWN", "down": "DOWN",
"wait": "Please wait", "wait": "Подождите",
"lan": "LAN", "lan": "LAN",
"wlan": "WLAN", "wlan": "WLAN",
"devices": "Devices", "devices": "Устройства",
"lan_devices": "LAN Devices", "lan_devices": "Устройства подключённые по LAN",
"wlan_devices": "WLAN Devices" "wlan_devices": "WLAN Devices"
}, },
"plex": { "plex": {
@ -209,8 +216,8 @@
"wait": "Please wait" "wait": "Please wait"
}, },
"changedetectionio": { "changedetectionio": {
"totalObserved": "Total Observed", "totalObserved": "Всего наблюдаемых",
"diffsDetected": "Diffs Detected" "diffsDetected": "Обнаружены различия"
}, },
"wmo": { "wmo": {
"0-day": "Sunny", "0-day": "Sunny",
@ -281,5 +288,78 @@
"up_to_date": "Up to Date", "up_to_date": "Up to Date",
"child_bridges_status": "{{ok}}/{{total}}", "child_bridges_status": "{{ok}}/{{total}}",
"child_bridges": "Child Bridges" "child_bridges": "Child Bridges"
},
"autobrr": {
"approvedPushes": "Approved",
"rejectedPushes": "Rejected",
"filters": "Filters",
"indexers": "Indexers"
},
"watchtower": {
"containers_scanned": "Scanned",
"containers_updated": "Updated",
"containers_failed": "Failed"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Videos",
"channels": "Channels",
"playlists": "Playlists"
},
"truenas": {
"load": "System Load",
"uptime": "Uptime",
"alerts": "Alerts",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"pyload": {
"speed": "Speed",
"active": "Active",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"error": "Ошибка",
"ping": "Пинг"
},
"scrutiny": {
"failed": "Failed",
"unknown": "Unknown",
"passed": "Passed"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"diskstation": {
"download": "Download",
"upload": "Upload",
"seed": "Seed",
"leech": "Leech"
},
"flood": {
"upload": "Upload",
"download": "Download",
"leech": "Leech",
"seed": "Seed"
} }
} }

View File

@ -2,7 +2,11 @@
"widget": { "widget": {
"missing_type": "Missing Widget Type: {{type}}", "missing_type": "Missing Widget Type: {{type}}",
"api_error": "API Error", "api_error": "API Error",
"status": "Status" "status": "Status",
"information": "Information",
"url": "URL",
"raw_error": "Raw Error",
"response_data": "Response Data"
}, },
"weather": { "weather": {
"current": "Current Location", "current": "Current Location",
@ -41,7 +45,9 @@
"tx": "TX", "tx": "TX",
"mem": "MEM", "mem": "MEM",
"cpu": "CPU", "cpu": "CPU",
"offline": "Offline" "offline": "Offline",
"error": "Error",
"unknown": "Unknown"
}, },
"emby": { "emby": {
"playing": "Playing", "playing": "Playing",
@ -125,7 +131,8 @@
"overseerr": { "overseerr": {
"pending": "Pending", "pending": "Pending",
"approved": "Approved", "approved": "Approved",
"available": "Available" "available": "Available",
"processing": "Processing"
}, },
"pihole": { "pihole": {
"queries": "Queries", "queries": "Queries",
@ -281,5 +288,78 @@
"up_to_date": "Up to Date", "up_to_date": "Up to Date",
"child_bridges": "Child Bridges", "child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"autobrr": {
"approvedPushes": "Approved",
"rejectedPushes": "Rejected",
"filters": "Filters",
"indexers": "Indexers"
},
"watchtower": {
"containers_scanned": "Scanned",
"containers_updated": "Updated",
"containers_failed": "Failed"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Videos",
"channels": "Channels",
"playlists": "Playlists"
},
"truenas": {
"load": "System Load",
"uptime": "Uptime",
"alerts": "Alerts",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"pyload": {
"speed": "Speed",
"active": "Active",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"error": "Error",
"ping": "Ping"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"diskstation": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"flood": {
"download": "Download",
"seed": "Seed",
"upload": "Upload",
"leech": "Leech"
} }
} }

View File

@ -2,7 +2,11 @@
"widget": { "widget": {
"missing_type": "Saknar Widget-typ: {{type}}", "missing_type": "Saknar Widget-typ: {{type}}",
"api_error": "API-fel", "api_error": "API-fel",
"status": "Status" "status": "Status",
"information": "Information",
"url": "URL",
"raw_error": "Raw Error",
"response_data": "Response Data"
}, },
"weather": { "weather": {
"current": "Nuvarande plats", "current": "Nuvarande plats",
@ -22,7 +26,9 @@
"tx": "TX", "tx": "TX",
"mem": "MEM", "mem": "MEM",
"cpu": "CPU", "cpu": "CPU",
"offline": "Offline" "offline": "Offline",
"error": "Error",
"unknown": "Unknown"
}, },
"search": { "search": {
"placeholder": "Sök…" "placeholder": "Sök…"
@ -98,7 +104,8 @@
"overseerr": { "overseerr": {
"pending": "Avvaktar", "pending": "Avvaktar",
"approved": "Godkända", "approved": "Godkända",
"available": "Tillgänglig" "available": "Tillgänglig",
"processing": "Processing"
}, },
"pihole": { "pihole": {
"blocked": "Blockerad", "blocked": "Blockerad",
@ -281,5 +288,78 @@
"up_to_date": "Up to Date", "up_to_date": "Up to Date",
"child_bridges": "Child Bridges", "child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"autobrr": {
"approvedPushes": "Approved",
"rejectedPushes": "Rejected",
"filters": "Filters",
"indexers": "Indexers"
},
"watchtower": {
"containers_scanned": "Scanned",
"containers_updated": "Updated",
"containers_failed": "Failed"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Videos",
"channels": "Channels",
"playlists": "Playlists"
},
"truenas": {
"load": "System Load",
"uptime": "Uptime",
"alerts": "Alerts",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"pyload": {
"speed": "Speed",
"active": "Active",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"error": "Error",
"ping": "Ping"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"download": "Download",
"leech": "Leech",
"upload": "Upload",
"seed": "Seed"
},
"diskstation": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"flood": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
} }
} }

View File

@ -19,7 +19,11 @@
"widget": { "widget": {
"missing_type": "విడ్జెట్ లేదు: {{type}}", "missing_type": "విడ్జెట్ లేదు: {{type}}",
"api_error": "API లోపం", "api_error": "API లోపం",
"status": "హోదా" "status": "హోదా",
"information": "Information",
"url": "URL",
"raw_error": "Raw Error",
"response_data": "Response Data"
}, },
"weather": { "weather": {
"current": "ప్రస్తుత స్తలం", "current": "ప్రస్తుత స్తలం",
@ -42,7 +46,9 @@
"tx": "TX", "tx": "TX",
"mem": "MEM", "mem": "MEM",
"cpu": "సీపియూ", "cpu": "సీపియూ",
"offline": "ఆఫ్‌లైన్" "offline": "ఆఫ్‌లైన్",
"error": "Error",
"unknown": "Unknown"
}, },
"emby": { "emby": {
"playing": "ఆడుతున్నారు", "playing": "ఆడుతున్నారు",
@ -116,7 +122,8 @@
"overseerr": { "overseerr": {
"pending": "పెండింగ్", "pending": "పెండింగ్",
"approved": "ఆమోదించబడింది", "approved": "ఆమోదించబడింది",
"available": "అందుబాటులో" "available": "అందుబాటులో",
"processing": "Processing"
}, },
"pihole": { "pihole": {
"queries": "ప్రశ్నలు", "queries": "ప్రశ్నలు",
@ -209,77 +216,150 @@
"wait": "దయచేసి వేచి ఉండండి" "wait": "దయచేసి వేచి ఉండండి"
}, },
"changedetectionio": { "changedetectionio": {
"totalObserved": "Total Observed", "totalObserved": "మొత్తం గమనించబడింది",
"diffsDetected": "Diffs Detected" "diffsDetected": "తేడాలు గుర్తించబడ్డాయి"
}, },
"wmo": { "wmo": {
"0-day": "Sunny", "0-day": "సన్నీ",
"0-night": "Clear", "0-night": "స్పష్టమైన",
"57-night": "Freezing Drizzle", "57-night": "గడ్డకట్టే చినుకులు",
"73-day": "Snow", "73-day": "మంచు",
"73-night": "Snow", "73-night": "మంచు",
"75-day": "Heavy Snow", "75-day": "భారీ మంచు",
"75-night": "Heavy Snow", "75-night": "భారీ మంచు",
"77-day": "Snow Grains", "77-day": "మంచు గింజలు",
"77-night": "Snow Grains", "77-night": "మంచు గింజలు",
"80-day": "Light Showers", "80-day": "తేలికపాటి జల్లులు",
"80-night": "Light Showers", "80-night": "తేలికపాటి జల్లులు",
"81-day": "Showers", "81-day": "జల్లులు",
"81-night": "Showers", "81-night": "జల్లులు",
"82-day": "Heavy Showers", "82-day": "భారీ వర్షాలు",
"82-night": "Heavy Showers", "82-night": "భారీ వర్షాలు",
"85-day": "Snow Showers", "85-day": "మంచు జల్లులు",
"85-night": "Snow Showers", "85-night": "మంచు జల్లులు",
"1-day": "Mainly Sunny", "1-day": "ప్రధానంగా ఎండ",
"1-night": "Mainly Clear", "1-night": "ప్రధానంగా స్పష్టంగా",
"2-day": "Partly Cloudy", "2-day": "పాక్షికంగా మేఘావృతమై ఉంటుంది",
"2-night": "Partly Cloudy", "2-night": "పాక్షికంగా మేఘావృతమై ఉంటుంది",
"3-day": "Cloudy", "3-day": "మేఘావృతం",
"3-night": "Cloudy", "3-night": "మేఘావృతం",
"45-day": "Foggy", "45-day": "పొగమంచు",
"45-night": "Foggy", "45-night": "పొగమంచు",
"48-day": "Foggy", "48-day": "పొగమంచు",
"48-night": "Foggy", "48-night": "పొగమంచు",
"51-day": "Light Drizzle", "51-day": "తేలికపాటి చినుకులు",
"51-night": "Light Drizzle", "51-night": "తేలికపాటి చినుకులు",
"53-day": "Drizzle", "53-day": "చినుకులు",
"53-night": "Drizzle", "53-night": "చినుకులు",
"55-day": "Heavy Drizzle", "55-day": "భారీ చినుకులు",
"55-night": "Heavy Drizzle", "55-night": "భారీ చినుకులు",
"56-day": "Light Freezing Drizzle", "56-day": "తేలికపాటి గడ్డకట్టే చినుకులు",
"56-night": "Light Freezing Drizzle", "56-night": "తేలికపాటి గడ్డకట్టే చినుకులు",
"57-day": "Freezing Drizzle", "57-day": "గడ్డకట్టే చినుకులు",
"61-day": "Light Rain", "61-day": "తేలికపాటి వర్షం",
"61-night": "Light Rain", "61-night": "తేలికపాటి వర్షం",
"63-day": "Rain", "63-day": "వర్షం",
"63-night": "Rain", "63-night": "వర్షం",
"65-day": "Heavy Rain", "65-day": "భారీవర్షం",
"65-night": "Heavy Rain", "65-night": "భారీవర్షం",
"66-day": "Freezing Rain", "66-day": "గడ్డకట్టే వర్షం",
"66-night": "Freezing Rain", "66-night": "గడ్డకట్టే వర్షం",
"67-day": "Freezing Rain", "67-day": "గడ్డకట్టే వర్షం",
"67-night": "Freezing Rain", "67-night": "గడ్డకట్టే వర్షం",
"71-day": "Light Snow", "71-day": "తేలికపాటి మంచు",
"71-night": "Light Snow", "71-night": "తేలికపాటి మంచు",
"86-day": "Snow Showers", "86-day": "మంచు జల్లులు",
"86-night": "Snow Showers", "86-night": "మంచు జల్లులు",
"95-day": "Thunderstorm", "95-day": "ఉరుము",
"95-night": "Thunderstorm", "95-night": "ఉరుము",
"96-day": "Thunderstorm With Hail", "96-day": "వడగళ్లతో కూడిన ఉరుములతో కూడిన వర్షం",
"96-night": "Thunderstorm With Hail", "96-night": "వడగళ్లతో కూడిన ఉరుములతో కూడిన వర్షం",
"99-day": "Thunderstorm With Hail", "99-day": "వడగళ్లతో కూడిన ఉరుములతో కూడిన వర్షం",
"99-night": "Thunderstorm With Hail" "99-night": "వడగళ్లతో కూడిన ఉరుములతో కూడిన వర్షం"
}, },
"quicklaunch": { "quicklaunch": {
"bookmark": "Bookmark", "bookmark": "బుక్మార్క్",
"service": "Service" "service": "సేవ"
}, },
"homebridge": { "homebridge": {
"available_update": "System", "available_update": "వ్యవస్థ",
"updates": "Updates", "updates": "నవీకరణలు",
"update_available": "Update Available", "update_available": "అందుబాటులో నవీకరణ",
"up_to_date": "Up to Date", "up_to_date": "తాజాగా",
"child_bridges": "Child Bridges", "child_bridges": "పిల్ల వంతెనలు",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"autobrr": {
"rejectedPushes": "తిరస్కరించారు",
"approvedPushes": "ఆమోదించబడింది",
"filters": "ఫిల్టర్లు",
"indexers": "సూచికలు"
},
"watchtower": {
"containers_scanned": "స్కాన్ చేశారు",
"containers_updated": "నవీకరించబడింది",
"containers_failed": "విఫలమయ్యారు"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Videos",
"channels": "Channels",
"playlists": "Playlists"
},
"truenas": {
"load": "System Load",
"uptime": "Uptime",
"alerts": "Alerts",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"pyload": {
"speed": "Speed",
"active": "Active",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"error": "Error",
"ping": "Ping"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"seed": "Seed",
"download": "Download",
"upload": "Upload",
"leech": "Leech"
},
"diskstation": {
"leech": "Leech",
"download": "Download",
"upload": "Upload",
"seed": "Seed"
},
"flood": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
} }
} }

View File

@ -2,7 +2,11 @@
"widget": { "widget": {
"missing_type": "Kayıp Araç Türü: {{type}}", "missing_type": "Kayıp Araç Türü: {{type}}",
"api_error": "API Hatası", "api_error": "API Hatası",
"status": "Durum" "status": "Durum",
"information": "Information",
"url": "URL",
"raw_error": "Raw Error",
"response_data": "Response Data"
}, },
"weather": { "weather": {
"current": "Mevcut Konum", "current": "Mevcut Konum",
@ -41,7 +45,9 @@
"tx": "Giden Veri", "tx": "Giden Veri",
"mem": "Bellek", "mem": "Bellek",
"cpu": "İşlemci", "cpu": "İşlemci",
"offline": "Çevrimdışı" "offline": "Çevrimdışı",
"error": "Error",
"unknown": "Unknown"
}, },
"emby": { "emby": {
"playing": "Oynatılıyor", "playing": "Oynatılıyor",
@ -125,7 +131,8 @@
"overseerr": { "overseerr": {
"pending": "Bekliyor", "pending": "Bekliyor",
"approved": "Onaylı", "approved": "Onaylı",
"available": "Kullanılabilir" "available": "Kullanılabilir",
"processing": "Processing"
}, },
"pihole": { "pihole": {
"queries": "Sorgular", "queries": "Sorgular",
@ -213,73 +220,146 @@
"diffsDetected": "Farklar Algılandı" "diffsDetected": "Farklar Algılandı"
}, },
"wmo": { "wmo": {
"99-day": "Thunderstorm With Hail", "99-day": "Dolu İle Gök Gürültülü Fırtına",
"0-day": "Sunny", "0-day": "Güneşli",
"0-night": "Clear", "0-night": "ık",
"1-day": "Mainly Sunny", "1-day": "Çoğunlukla Güneşli",
"1-night": "Mainly Clear", "1-night": "Çoğunlukla Açık",
"2-day": "Partly Cloudy", "2-day": "Parçalı Bulutlu",
"2-night": "Partly Cloudy", "2-night": "Parçalı Bulutlu",
"3-day": "Cloudy", "3-day": "Bulutlu",
"3-night": "Cloudy", "3-night": "Bulutlu",
"45-day": "Foggy", "45-day": "Sisli",
"45-night": "Foggy", "45-night": "Sisli",
"48-day": "Foggy", "48-day": "Sisli",
"48-night": "Foggy", "48-night": "Sisli",
"51-day": "Light Drizzle", "51-day": "Az Çiseleyen Yağmur",
"51-night": "Light Drizzle", "51-night": "Az Çiseleyen Yağmur",
"53-day": "Drizzle", "53-day": "Çiseleyen Yağmur",
"53-night": "Drizzle", "53-night": "Çiseleyen Yağmur",
"55-day": "Heavy Drizzle", "55-day": "Çok Çiseleyen Yağmur",
"55-night": "Heavy Drizzle", "55-night": "Çok Çiseleyen Yağmur",
"56-day": "Light Freezing Drizzle", "56-day": "Soğuk Az Çiseleyen Yağmur",
"56-night": "Light Freezing Drizzle", "56-night": "Soğuk Az Çiseleyen Yağmur",
"57-day": "Freezing Drizzle", "57-day": "Soğuk Çiseleyen Yağmur",
"57-night": "Freezing Drizzle", "57-night": "Soğuk Çiseleyen Yağmur",
"61-day": "Light Rain", "61-day": "Hafif Yağmur",
"61-night": "Light Rain", "61-night": "Hafif Yağmur",
"63-day": "Rain", "63-day": "Yağmur",
"63-night": "Rain", "63-night": "Yağmur",
"65-day": "Heavy Rain", "65-day": "Çok Yağmur",
"65-night": "Heavy Rain", "65-night": "Çok Yağmur",
"66-day": "Freezing Rain", "66-day": "Dondurucu Yağmur",
"66-night": "Freezing Rain", "66-night": "Dondurucu Yağmur",
"67-day": "Freezing Rain", "67-day": "Dondurucu Yağmur",
"67-night": "Freezing Rain", "67-night": "Dondurucu Yağmur",
"71-day": "Light Snow", "71-day": "Hafif Kar",
"71-night": "Light Snow", "71-night": "Hafif Kar",
"73-day": "Snow", "73-day": "Kar",
"73-night": "Snow", "73-night": "Kar",
"75-day": "Heavy Snow", "75-day": "Çok Kar",
"75-night": "Heavy Snow", "75-night": "Çok Kar",
"77-day": "Snow Grains", "77-day": "Kar Taneleri",
"77-night": "Snow Grains", "77-night": "Kar Taneleri",
"80-day": "Light Showers", "80-day": "Hafif Sağanak",
"80-night": "Light Showers", "80-night": "Hafif Sağanak",
"81-day": "Showers", "81-day": "Sağanak",
"81-night": "Showers", "81-night": "Sağanak",
"82-day": "Heavy Showers", "82-day": "Yoğun Sağanak",
"95-night": "Thunderstorm", "95-night": "Gök Gürültülü Fırtına",
"82-night": "Heavy Showers", "82-night": "Yoğun Sağanak",
"85-day": "Snow Showers", "85-day": "Karlı Sağanak",
"85-night": "Snow Showers", "85-night": "Karlı Sağanak",
"86-day": "Snow Showers", "86-day": "Karlı Sağanak",
"86-night": "Snow Showers", "86-night": "Karlı Sağanak",
"95-day": "Thunderstorm", "95-day": "Gök Gürültülü Fırtına",
"96-day": "Thunderstorm With Hail", "96-day": "Dolu İle Gök Gürültülü Fırtına",
"96-night": "Thunderstorm With Hail", "96-night": "Dolu İle Gök Gürültülü Fırtına",
"99-night": "Thunderstorm With Hail" "99-night": "Dolu İle Gök Gürültülü Fırtına"
}, },
"quicklaunch": { "quicklaunch": {
"bookmark": "Bookmark", "bookmark": "Yer İmi",
"service": "Service" "service": "Hizmet"
}, },
"homebridge": { "homebridge": {
"available_update": "System", "available_update": "Sistem",
"updates": "Updates", "updates": "Güncellemeler",
"update_available": "Update Available", "update_available": "Güncelleme Kullanılabilir",
"up_to_date": "Up to Date", "up_to_date": "Güncel",
"child_bridges": "Child Bridges", "child_bridges": "Alt Köprüler",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"autobrr": {
"approvedPushes": "Onaylandı",
"rejectedPushes": "Reddedildi",
"filters": "Süzgeçler",
"indexers": "Dizin Oluşturucular"
},
"watchtower": {
"containers_scanned": "Tarandı",
"containers_updated": "Güncellendi",
"containers_failed": "Başarısız"
},
"tubearchivist": {
"downloads": "Kuyruk",
"videos": "Videolar",
"channels": "Kanallar",
"playlists": "Oynatma Listeleri"
},
"truenas": {
"load": "Sistem Yükü",
"uptime": "Çalışma Süresi",
"alerts": "Alarmlar",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "Geçerli Akış Yok",
"please_wait": "Lütfen Bekleyin"
},
"pyload": {
"speed": "Hız",
"active": "Geçerli",
"queue": "Kuyruk",
"total": "Toplam"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"error": "Error",
"ping": "Ping"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"diskstation": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"flood": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
} }
} }

View File

@ -2,7 +2,11 @@
"widget": { "widget": {
"missing_type": "Thiếu loại Widget: {{type}}", "missing_type": "Thiếu loại Widget: {{type}}",
"api_error": "Lỗi API", "api_error": "Lỗi API",
"status": "Trạng thái" "status": "Trạng thái",
"information": "Information",
"url": "URL",
"raw_error": "Raw Error",
"response_data": "Response Data"
}, },
"search": { "search": {
"placeholder": "Tìm kiếm…" "placeholder": "Tìm kiếm…"
@ -19,7 +23,9 @@
"tx": "TX", "tx": "TX",
"mem": "BỘ NHỚ", "mem": "BỘ NHỚ",
"cpu": "CPU", "cpu": "CPU",
"offline": "Ngoại tuyến" "offline": "Ngoại tuyến",
"error": "Error",
"unknown": "Unknown"
}, },
"emby": { "emby": {
"playing": "Đang chơi", "playing": "Đang chơi",
@ -98,7 +104,8 @@
"overseerr": { "overseerr": {
"pending": "Pending", "pending": "Pending",
"approved": "Đã duyệt", "approved": "Đã duyệt",
"available": "Available" "available": "Available",
"processing": "Processing"
}, },
"sabnzbd": { "sabnzbd": {
"rate": "Rate", "rate": "Rate",
@ -281,5 +288,78 @@
"up_to_date": "Up to Date", "up_to_date": "Up to Date",
"child_bridges": "Child Bridges", "child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"autobrr": {
"approvedPushes": "Approved",
"rejectedPushes": "Rejected",
"filters": "Filters",
"indexers": "Indexers"
},
"watchtower": {
"containers_scanned": "Scanned",
"containers_updated": "Updated",
"containers_failed": "Failed"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Videos",
"channels": "Channels",
"playlists": "Playlists"
},
"truenas": {
"load": "System Load",
"uptime": "Uptime",
"alerts": "Alerts",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"pyload": {
"speed": "Speed",
"active": "Active",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"error": "Error",
"ping": "Ping"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"diskstation": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"flood": {
"download": "Download",
"upload": "Upload",
"seed": "Seed",
"leech": "Leech"
} }
} }

View File

@ -20,7 +20,11 @@
"widget": { "widget": {
"missing_type": "缺少小部件類型:{{type}}", "missing_type": "缺少小部件類型:{{type}}",
"api_error": "API 錯誤", "api_error": "API 錯誤",
"status": "狀況" "status": "狀況",
"url": "URL",
"information": "Information",
"raw_error": "Raw Error",
"response_data": "Response Data"
}, },
"weather": { "weather": {
"current": "依家位置", "current": "依家位置",
@ -43,7 +47,9 @@
"tx": "發送", "tx": "發送",
"mem": "內存", "mem": "內存",
"cpu": "處理器", "cpu": "處理器",
"offline": "離線" "offline": "離線",
"error": "Error",
"unknown": "Unknown"
}, },
"nzbget": { "nzbget": {
"rate": "速度", "rate": "速度",
@ -104,7 +110,8 @@
"overseerr": { "overseerr": {
"pending": "待定", "pending": "待定",
"approved": "批准", "approved": "批准",
"available": "可用" "available": "可用",
"processing": "Processing"
}, },
"pihole": { "pihole": {
"queries": "查詢", "queries": "查詢",
@ -281,5 +288,78 @@
"up_to_date": "Up to Date", "up_to_date": "Up to Date",
"child_bridges": "Child Bridges", "child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"autobrr": {
"approvedPushes": "Approved",
"rejectedPushes": "Rejected",
"filters": "Filters",
"indexers": "Indexers"
},
"watchtower": {
"containers_scanned": "Scanned",
"containers_updated": "Updated",
"containers_failed": "Failed"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Videos",
"channels": "Channels",
"playlists": "Playlists"
},
"truenas": {
"load": "System Load",
"uptime": "Uptime",
"alerts": "Alerts",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"pyload": {
"speed": "Speed",
"active": "Active",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"error": "Error",
"ping": "Ping"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"diskstation": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"flood": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
} }
} }

View File

@ -2,7 +2,11 @@
"widget": { "widget": {
"missing_type": "缺少小部件类型:{{type}}", "missing_type": "缺少小部件类型:{{type}}",
"api_error": "API错误", "api_error": "API错误",
"status": "状态" "status": "状态",
"information": "Information",
"url": "URL",
"raw_error": "Raw Error",
"response_data": "Response Data"
}, },
"search": { "search": {
"placeholder": "搜索…" "placeholder": "搜索…"
@ -19,7 +23,9 @@
"tx": "发送", "tx": "发送",
"mem": "内存", "mem": "内存",
"cpu": "处理器", "cpu": "处理器",
"offline": "离线" "offline": "离线",
"error": "Error",
"unknown": "Unknown"
}, },
"emby": { "emby": {
"playing": "播放中", "playing": "播放中",
@ -47,7 +53,7 @@
"wanted": "想看", "wanted": "想看",
"queued": "队列", "queued": "队列",
"movies": "电影", "movies": "电影",
"missing": "Missing" "missing": "丢失"
}, },
"readarr": { "readarr": {
"wanted": "订阅", "wanted": "订阅",
@ -98,7 +104,8 @@
"overseerr": { "overseerr": {
"pending": "待办", "pending": "待办",
"approved": "已批准", "approved": "已批准",
"available": "可用" "available": "可用",
"processing": "Processing"
}, },
"sabnzbd": { "sabnzbd": {
"rate": "速率", "rate": "速率",
@ -192,11 +199,11 @@
"up": "向上", "up": "向上",
"down": "向下", "down": "向下",
"wait": "请稍候", "wait": "请稍候",
"lan": "LAN", "lan": "局域网",
"wlan": "WLAN", "wlan": "无线局域网",
"devices": "Devices", "devices": "设备",
"lan_devices": "LAN Devices", "lan_devices": "局域网设备",
"wlan_devices": "WLAN Devices" "wlan_devices": "无线局域网设备"
}, },
"plex": { "plex": {
"streams": "活动流", "streams": "活动流",
@ -209,26 +216,26 @@
"wait": "请稍等" "wait": "请稍等"
}, },
"changedetectionio": { "changedetectionio": {
"totalObserved": "Total Observed", "totalObserved": "观察到的总数",
"diffsDetected": "Diffs Detected" "diffsDetected": "检测到差异"
}, },
"wmo": { "wmo": {
"0-day": "Sunny", "0-day": "晴天",
"0-night": "Clear", "0-night": "晴朗",
"1-day": "Mainly Sunny", "1-day": "主要是晴天",
"3-day": "Cloudy", "3-day": "阴天",
"3-night": "Cloudy", "3-night": "阴天",
"45-day": "Foggy", "45-day": "有雾",
"48-day": "Foggy", "48-day": "有雾",
"51-day": "Light Drizzle", "51-day": "小雨",
"73-night": "Snow", "73-night": "Snow",
"75-day": "Heavy Snow", "75-day": "Heavy Snow",
"1-night": "Mainly Clear", "1-night": "大部晴朗",
"2-day": "Partly Cloudy", "2-day": "多云",
"2-night": "Partly Cloudy", "2-night": "多云",
"45-night": "Foggy", "45-night": "有雾",
"48-night": "Foggy", "48-night": "有雾",
"51-night": "Light Drizzle", "51-night": "小雨",
"53-day": "Drizzle", "53-day": "Drizzle",
"53-night": "Drizzle", "53-night": "Drizzle",
"55-day": "Heavy Drizzle", "55-day": "Heavy Drizzle",
@ -271,8 +278,8 @@
"99-night": "Thunderstorm With Hail" "99-night": "Thunderstorm With Hail"
}, },
"quicklaunch": { "quicklaunch": {
"bookmark": "Bookmark", "bookmark": "书签",
"service": "Service" "service": "服务"
}, },
"homebridge": { "homebridge": {
"available_update": "System", "available_update": "System",
@ -281,5 +288,78 @@
"up_to_date": "Up to Date", "up_to_date": "Up to Date",
"child_bridges": "Child Bridges", "child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"autobrr": {
"approvedPushes": "Approved",
"rejectedPushes": "Rejected",
"filters": "Filters",
"indexers": "Indexers"
},
"watchtower": {
"containers_scanned": "以扫描",
"containers_updated": "以升级",
"containers_failed": "失败"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Videos",
"channels": "Channels",
"playlists": "Playlists"
},
"truenas": {
"load": "System Load",
"uptime": "Uptime",
"alerts": "警报",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "暂无播放",
"please_wait": "请等待"
},
"pyload": {
"speed": "Speed",
"active": "Active",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"error": "Error",
"ping": "Ping"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"diskstation": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"flood": {
"leech": "Leech",
"download": "Download",
"upload": "Upload",
"seed": "Seed"
} }
} }

View File

@ -2,7 +2,11 @@
"widget": { "widget": {
"missing_type": "Missing Widget Type: {{type}}", "missing_type": "Missing Widget Type: {{type}}",
"api_error": "API Error", "api_error": "API Error",
"status": "Status" "status": "Status",
"information": "Information",
"url": "URL",
"raw_error": "Raw Error",
"response_data": "Response Data"
}, },
"weather": { "weather": {
"current": "Current Location", "current": "Current Location",
@ -15,7 +19,9 @@
"offline": "Offline", "offline": "Offline",
"tx": "TX", "tx": "TX",
"mem": "MEM", "mem": "MEM",
"cpu": "CPU" "cpu": "CPU",
"error": "Error",
"unknown": "Unknown"
}, },
"emby": { "emby": {
"playing": "Playing", "playing": "Playing",
@ -83,7 +89,8 @@
"overseerr": { "overseerr": {
"pending": "Pending", "pending": "Pending",
"approved": "Approved", "approved": "Approved",
"available": "Available" "available": "Available",
"processing": "Processing"
}, },
"pihole": { "pihole": {
"queries": "Queries", "queries": "Queries",
@ -281,5 +288,78 @@
"up_to_date": "Up to Date", "up_to_date": "Up to Date",
"child_bridges": "Child Bridges", "child_bridges": "Child Bridges",
"child_bridges_status": "{{ok}}/{{total}}" "child_bridges_status": "{{ok}}/{{total}}"
},
"autobrr": {
"approvedPushes": "Approved",
"rejectedPushes": "Rejected",
"filters": "Filters",
"indexers": "Indexers"
},
"watchtower": {
"containers_scanned": "Scanned",
"containers_updated": "Updated",
"containers_failed": "Failed"
},
"tubearchivist": {
"downloads": "Queue",
"videos": "Videos",
"channels": "Channels",
"playlists": "Playlists"
},
"truenas": {
"load": "System Load",
"uptime": "Uptime",
"alerts": "Alerts",
"time": "{{value, number(style: unit; unitDisplay: long;)}}"
},
"navidrome": {
"nothing_streaming": "No Active Streams",
"please_wait": "Please Wait"
},
"pyload": {
"speed": "Speed",
"active": "Active",
"queue": "Queue",
"total": "Total"
},
"gluetun": {
"public_ip": "Public IP",
"region": "Region",
"country": "Country"
},
"hdhomerun": {
"channels": "Channels",
"hd": "HD"
},
"ping": {
"error": "Error",
"ping": "Ping"
},
"scrutiny": {
"passed": "Passed",
"failed": "Failed",
"unknown": "Unknown"
},
"paperlessngx": {
"inbox": "Inbox",
"total": "Total"
},
"deluge": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"diskstation": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"flood": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
} }
} }

View File

@ -3,7 +3,7 @@ import List from "components/bookmarks/list";
export default function BookmarksGroup({ group }) { export default function BookmarksGroup({ group }) {
return ( return (
<div key={group.name} className="basis-full md:basis-1/2 lg:basis-1/3 xl:basis-1/4 flex-1"> <div key={group.name} className="flex-1">
<h2 className="text-theme-800 dark:text-theme-300 text-xl font-medium">{group.name}</h2> <h2 className="text-theme-800 dark:text-theme-300 text-xl font-medium">{group.name}</h2>
<ErrorBoundary> <ErrorBoundary>
<List bookmarks={group.bookmarks} /> <List bookmarks={group.bookmarks} />

View File

@ -1,6 +1,7 @@
import { useContext } from "react"; import { useContext } from "react";
import { SettingsContext } from "utils/contexts/settings"; import { SettingsContext } from "utils/contexts/settings";
import ResolvedIcon from "components/resolvedicon";
export default function Item({ bookmark }) { export default function Item({ bookmark }) {
const { hostname } = new URL(bookmark.href); const { hostname } = new URL(bookmark.href);
@ -16,7 +17,12 @@ export default function Item({ bookmark }) {
> >
<div className="flex"> <div className="flex">
<div className="flex-shrink-0 flex items-center justify-center w-11 bg-theme-500/10 dark:bg-theme-900/50 text-theme-700 hover:text-theme-700 dark:text-theme-200 text-sm font-medium rounded-l-md"> <div className="flex-shrink-0 flex items-center justify-center w-11 bg-theme-500/10 dark:bg-theme-900/50 text-theme-700 hover:text-theme-700 dark:text-theme-200 text-sm font-medium rounded-l-md">
{bookmark.abbr} {bookmark.icon &&
<div className="flex-shrink-0 w-5 h-5">
<ResolvedIcon icon={bookmark.icon} />
</div>
}
{!bookmark.icon && bookmark.abbr}
</div> </div>
<div className="flex-1 flex items-center justify-between rounded-r-md "> <div className="flex-1 flex items-center justify-between rounded-r-md ">
<div className="flex-1 grow pl-3 py-2 text-xs">{bookmark.name}</div> <div className="flex-1 grow pl-3 py-2 text-xs">{bookmark.name}</div>

View File

@ -2,7 +2,7 @@ import { useTranslation } from "react-i18next";
import { useEffect, useState, useRef, useCallback, useContext } from "react"; import { useEffect, useState, useRef, useCallback, useContext } from "react";
import classNames from "classnames"; import classNames from "classnames";
import { resolveIcon } from "./services/item"; import ResolvedIcon from "./resolvedicon";
import { SettingsContext } from "utils/contexts/settings"; import { SettingsContext } from "utils/contexts/settings";
@ -107,18 +107,19 @@ export default function QuickLaunch({servicesAndBookmarks, searchString, setSear
function highlightText(text) { function highlightText(text) {
const parts = text.split(new RegExp(`(${searchString})`, 'gi')); const parts = text.split(new RegExp(`(${searchString})`, 'gi'));
return <span>{parts.map(part => part.toLowerCase() === searchString.toLowerCase() ? <span className="bg-theme-300/10">{part}</span> : part)}</span>; // eslint-disable-next-line react/no-array-index-key
return <span>{parts.map((part, i) => part.toLowerCase() === searchString.toLowerCase() ? <span key={`${searchString}_${i}`} className="bg-theme-300/10">{part}</span> : part)}</span>;
} }
return ( return (
<div className={classNames( <div className={classNames(
"relative z-10 ease-in-out duration-300 transition-opacity", "relative z-20 ease-in-out duration-300 transition-opacity",
hidden && !isOpen && "hidden", hidden && !isOpen && "hidden",
!hidden && isOpen && "opacity-100", !hidden && isOpen && "opacity-100",
!isOpen && "opacity-0", !isOpen && "opacity-0",
)} role="dialog" aria-modal="true"> )} role="dialog" aria-modal="true">
<div className="fixed inset-0 bg-gray-500 bg-opacity-50" /> <div className="fixed inset-0 bg-gray-500 bg-opacity-50" />
<div className="fixed inset-0 z-10 overflow-y-auto"> <div className="fixed inset-0 z-20 overflow-y-auto">
<div className="flex min-h-full min-w-full items-start justify-center text-center"> <div className="flex min-h-full min-w-full items-start justify-center text-center">
<dialog className="mt-[10%] min-w-[80%] max-w-[90%] md:min-w-[40%] rounded-md p-0 block font-medium text-theme-700 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-50 dark:bg-theme-800"> <dialog className="mt-[10%] min-w-[80%] max-w-[90%] md:min-w-[40%] rounded-md p-0 block font-medium text-theme-700 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-50 dark:bg-theme-800">
<input placeholder="Search" className={classNames( <input placeholder="Search" className={classNames(
@ -135,7 +136,7 @@ export default function QuickLaunch({servicesAndBookmarks, searchString, setSear
)} onClick={handleItemClick}> )} onClick={handleItemClick}>
<div className="flex flex-row items-center mr-4 pointer-events-none"> <div className="flex flex-row items-center mr-4 pointer-events-none">
<div className="w-5 text-xs mr-4"> <div className="w-5 text-xs mr-4">
{r.icon && resolveIcon(r.icon)} {r.icon && <ResolvedIcon icon={r.icon} />}
{r.abbr && r.abbr} {r.abbr && r.abbr}
</div> </div>
<div className="flex flex-col md:flex-row text-left items-baseline mr-4 pointer-events-none"> <div className="flex flex-col md:flex-row text-left items-baseline mr-4 pointer-events-none">
@ -147,7 +148,7 @@ export default function QuickLaunch({servicesAndBookmarks, searchString, setSear
} }
</div> </div>
</div> </div>
<div className="text-xs text-theme-600 font-bold pointer-events-none">{r.abbr ? t("quicklaunch.bookmark") : t("quicklaunch.service")}</div> <div className="text-xs text-theme-600 font-bold pointer-events-none">{r.type === 'service' ? t("quicklaunch.service") : t("quicklaunch.bookmark")}</div>
</button> </button>
</li> </li>
))} ))}

View File

@ -0,0 +1,37 @@
import Image from "next/future/image";
export default function ResolvedIcon({ icon }) {
// direct or relative URLs
if (icon.startsWith("http") || icon.startsWith("/")) {
return <Image src={`${icon}`} width={32} height={32} alt="logo" />;
}
// mdi- prefixed, material design icons
if (icon.startsWith("mdi-")) {
const iconName = icon.replace("mdi-", "").replace(".svg", "");
return (
<div
style={{
width: 32,
height: 32,
maxWidth: '100%',
maxHeight: '100%',
background: "linear-gradient(180deg, rgb(var(--color-logo-start)), rgb(var(--color-logo-stop)))",
mask: `url(https://cdn.jsdelivr.net/npm/@mdi/svg@latest/svg/${iconName}.svg) no-repeat center / contain`,
WebkitMask: `url(https://cdn.jsdelivr.net/npm/@mdi/svg@latest/svg/${iconName}.svg) no-repeat center / contain`,
}}
/>
);
}
// fallback to dashboard-icons
const iconName = icon.replace(".png", "");
return (
<Image
src={`https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/${iconName}.png`}
width={32}
height={32}
alt="logo"
/>
);
}

View File

@ -1,6 +1,7 @@
import classNames from "classnames"; import classNames from "classnames";
import List from "components/services/list"; import List from "components/services/list";
import ResolvedIcon from "components/resolvedicon";
export default function ServicesGroup({ services, layout }) { export default function ServicesGroup({ services, layout }) {
return ( return (
@ -11,7 +12,14 @@ export default function ServicesGroup({ services, layout }) {
"flex-1 p-1" "flex-1 p-1"
)} )}
> >
<h2 className="text-theme-800 dark:text-theme-300 text-xl font-medium">{services.name}</h2> <div className="flex select-none items-center">
{layout?.icon &&
<div className="flex-shrink-0 mr-2 w-7 h-7">
<ResolvedIcon icon={layout.icon} />
</div>
}
<h2 className="text-theme-800 dark:text-theme-300 text-xl font-medium">{services.name}</h2>
</div>
<List services={services.services} layout={layout} /> <List services={services.services} layout={layout} />
</div> </div>
); );

View File

@ -1,46 +1,13 @@
import Image from "next/future/image";
import classNames from "classnames"; import classNames from "classnames";
import { useContext, useState } from "react"; import { useContext, useState } from "react";
import Status from "./status"; import Status from "./status";
import Widget from "./widget"; import Widget from "./widget";
import Ping from "./ping";
import Docker from "widgets/docker/component"; import Docker from "widgets/docker/component";
import { SettingsContext } from "utils/contexts/settings"; import { SettingsContext } from "utils/contexts/settings";
import ResolvedIcon from "components/resolvedicon";
export function resolveIcon(icon) {
// direct or relative URLs
if (icon.startsWith("http") || icon.startsWith("/")) {
return <Image src={`${icon}`} width={32} height={32} alt="logo" />;
}
// mdi- prefixed, material design icons
if (icon.startsWith("mdi-")) {
const iconName = icon.replace("mdi-", "").replace(".svg", "");
return (
<div
style={{
width: 32,
height: 32,
background: "linear-gradient(180deg, rgb(var(--color-logo-start)), rgb(var(--color-logo-stop)))",
mask: `url(https://cdn.jsdelivr.net/npm/@mdi/svg@latest/svg/${iconName}.svg) no-repeat center / contain`,
WebkitMask: `url(https://cdn.jsdelivr.net/npm/@mdi/svg@latest/svg/${iconName}.svg) no-repeat center / contain`,
}}
/>
);
}
// fallback to dashboard-icons
const iconName = icon.replace(".png", "");
return (
<Image
src={`https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/${iconName}.png`}
width={32}
height={32}
alt="logo"
/>
);
}
export default function Item({ service }) { export default function Item({ service }) {
const hasLink = service.href && service.href !== "#"; const hasLink = service.href && service.href !== "#";
@ -64,7 +31,7 @@ export default function Item({ service }) {
<div <div
className={`${ className={`${
hasLink ? "cursor-pointer " : " " hasLink ? "cursor-pointer " : " "
}transition-all h-15 mb-3 p-1 rounded-md font-medium text-theme-700 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 hover:bg-theme-300/20 dark:bg-white/5 dark:hover:bg-white/10`} }transition-all h-15 mb-3 p-1 rounded-md font-medium text-theme-700 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 hover:bg-theme-300/20 dark:bg-white/5 dark:hover:bg-white/10 relative`}
> >
<div className="flex select-none"> <div className="flex select-none">
{service.icon && {service.icon &&
@ -75,10 +42,12 @@ export default function Item({ service }) {
rel="noreferrer" rel="noreferrer"
className="flex-shrink-0 flex items-center justify-center w-12 " className="flex-shrink-0 flex items-center justify-center w-12 "
> >
{resolveIcon(service.icon)} <ResolvedIcon icon={service.icon} />
</a> </a>
) : ( ) : (
<div className="flex-shrink-0 flex items-center justify-center w-12 ">{resolveIcon(service.icon)}</div> <div className="flex-shrink-0 flex items-center justify-center w-12 ">
<ResolvedIcon icon={service.icon} />
</div>
))} ))}
{hasLink ? ( {hasLink ? (
@ -102,22 +71,31 @@ export default function Item({ service }) {
</div> </div>
)} )}
{service.container && ( <div className="absolute top-0 right-0 w-1/2 flex flex-row justify-end gap-2 mr-2">
<button {service.ping && (
type="button" <div className="flex-shrink-0 flex items-center justify-center cursor-pointer">
onClick={() => (statsOpen ? closeStats() : setStatsOpen(true))} <Ping service={service} />
className="flex-shrink-0 flex items-center justify-center w-12 cursor-pointer" <span className="sr-only">Ping status</span>
> </div>
<Status service={service} /> )}
<span className="sr-only">View container stats</span>
</button> {service.container && (
)} <button
type="button"
onClick={() => (statsOpen ? closeStats() : setStatsOpen(true))}
className="flex-shrink-0 flex items-center justify-center cursor-pointer"
>
<Status service={service} />
<span className="sr-only">View container stats</span>
</button>
)}
</div>
</div> </div>
{service.container && service.server && ( {service.container && service.server && (
<div <div
className={classNames( className={classNames(
statsOpen && !statsClosing ? "max-h-[55px] opacity-100" : " max-h-[0] opacity-0", statsOpen && !statsClosing ? "max-h-[110px] opacity-100" : " max-h-[0] opacity-0",
"w-full overflow-hidden transition-all duration-300 ease-in-out" "w-full overflow-hidden transition-all duration-300 ease-in-out"
)} )}
> >

View File

@ -0,0 +1,44 @@
import { useTranslation } from "react-i18next";
import useSWR from "swr";
export default function Ping({ service }) {
const { t } = useTranslation();
const { data, error } = useSWR(`/api/ping?${new URLSearchParams({ping: service.ping}).toString()}`, {
refreshInterval: 30000
});
if (error) {
return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden">
<div className="text-[8px] font-bold text-rose-500 uppercase">{t("ping.error")}</div>
</div>
);
}
if (!data) {
return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden">
<div className="text-[8px] font-bold text-black/20 dark:text-white/40 uppercase">{t("ping.ping")}</div>
</div>
);
}
const statusText = `${service.ping}: HTTP status ${data.status}`;
if (data && data.status !== 200) {
return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={statusText}>
<div className="text-[8px] font-bold text-rose-500/80">{data.status}</div>
</div>
);
}
if (data && data.status === 200) {
return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={statusText}>
<div className="text-[8px] font-bold text-emerald-500/80">{t("common.ms", { value: data.latency, style: "unit", unit: "millisecond", unitDisplay: "narrow", maximumFractionDigits: 0 })}</div>
</div>
);
}
}

View File

@ -1,19 +1,52 @@
import { useTranslation } from "react-i18next";
import useSWR from "swr"; import useSWR from "swr";
export default function Status({ service }) { export default function Status({ service }) {
const { t } = useTranslation();
const { data, error } = useSWR(`/api/docker/status/${service.container}/${service.server || ""}`); const { data, error } = useSWR(`/api/docker/status/${service.container}/${service.server || ""}`);
if (error) { if (error) {
return <div className="w-3 h-3 bg-rose-300 dark:bg-rose-500 rounded-full" />; <div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={data.status}>
<div className="text-[8px] font-bold text-rose-500/80 uppercase">{t("docker.error")}</div>
</div>
} }
if (data && data.status === "running") { if (data && data.status === "running") {
return <div className="w-3 h-3 bg-emerald-300 dark:bg-emerald-500 rounded-full" />; if (data.health === "starting") {
return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={data.health}>
<div className="text-[8px] font-bold text-blue-500/80 uppercase">{data.health}</div>
</div>
);
}
if (data.health === "unhealthy") {
return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={data.health}>
<div className="text-[8px] font-bold text-orange-400/50 dark:text-orange-400/80 uppercase">{data.health}</div>
</div>
);
}
return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={data.health ?? data.status}>
<div className="text-[8px] font-bold text-emerald-500/80 uppercase">{data.health ?? data.status}</div>
</div>
);
} }
if (data && data.status === "not found") { if (data && (data.status === "not found" || data.status === "exited")) {
return <div className="h-2.5 w-2.5 bg-orange-400/50 dark:bg-yellow-200/40 -rotate-45" />; return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={data.status}>
<div className="text-[8px] font-bold text-orange-400/50 dark:text-orange-400/80 uppercase">{data.status}</div>
</div>
);
} }
return <div className="w-3 h-3 bg-black/20 dark:bg-white/40 rounded-full" />; return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden">
<div className="text-[8px] font-bold text-black/20 dark:text-white/40 uppercase">{t("docker.unknown")}</div>
</div>
);
} }

View File

@ -7,7 +7,7 @@ export default function Block({ value, label }) {
return ( return (
<div <div
className={classNames( className={classNames(
"bg-theme-200/50 dark:bg-theme-900/20 rounded m-1 flex-1 flex flex-col items-center justify-center p-1", "bg-theme-200/50 dark:bg-theme-900/20 rounded m-1 flex-1 flex flex-col items-center justify-center text-center p-1",
value === undefined ? "animate-pulse" : "" value === undefined ? "animate-pulse" : ""
)} )}
> >

View File

@ -1,10 +1,8 @@
import Error from "./error";
export default function Container({ error = false, children, service }) { export default function Container({ error = false, children, service }) {
if (error) { if (error) {
return ( return <Error error={error} />
<div className="bg-theme-200/50 dark:bg-theme-900/20 rounded m-1 flex-1 flex flex-col items-center justify-center p-1">
<div className="font-thin text-sm">{error}</div>
</div>
);
} }
let visibleChildren = children; let visibleChildren = children;

View File

@ -0,0 +1,50 @@
import { useTranslation } from "react-i18next";
import { IoAlertCircle } from "react-icons/io5";
function displayError(error) {
return JSON.stringify(error[1] ? error[1] : error, null, 4);
}
function displayData(data) {
return (data.type === 'Buffer') ? Buffer.from(data).toString() : JSON.stringify(data, 4);
}
export default function Error({ error }) {
const { t } = useTranslation();
if (error?.data?.error) {
error = error.data.error; // eslint-disable-line no-param-reassign
}
return (
<details className="px-1 pb-1">
<summary className="block text-center mt-1 mb-0 mx-auto p-3 rounded bg-rose-900/80 hover:bg-rose-900/95 text-theme-900 cursor-pointer">
<div className="flex items-center justify-center text-xs font-bold">
<IoAlertCircle className="mr-1 w-5 h-5"/>{t("widget.api_error")} {error.message && t("widget.information")}
</div>
</summary>
<div className="bg-white dark:bg-theme-200/50 mt-2 rounded text-rose-900 text-xs font-mono whitespace-pre-wrap break-all">
<ul className="p-4">
{error.message && <li>
<span className="text-black">{t("widget.api_error")}:</span> {error.message}
</li>}
{error.url && <li className="mt-2">
<span className="text-black">{t("widget.url")}:</span> {error.url}
</li>}
{error.rawError && <li className="mt-2">
<span className="text-black">{t("widget.raw_error")}:</span>
<div className="ml-2">
{displayError(error.rawError)}
</div>
</li>}
{error.data && <li className="mt-2">
<span className="text-black">{t("widget.response_data")}:</span>
<div className="ml-2">
{displayData(error.data)}
</div>
</li>}
</ul>
</div>
</details>
);
}

View File

@ -8,9 +8,9 @@ import cachedFetch from "utils/proxy/cached-fetch";
export default function Version() { export default function Version() {
const { t, i18n } = useTranslation(); const { t, i18n } = useTranslation();
const buildTime = process.env.NEXT_PUBLIC_BUILDTIME ?? new Date().toISOString(); const buildTime = process.env.NEXT_PUBLIC_BUILDTIME?.length ? process.env.NEXT_PUBLIC_BUILDTIME : new Date().toISOString();
const revision = process.env.NEXT_PUBLIC_REVISION ?? "dev"; const revision = process.env.NEXT_PUBLIC_REVISION?.length ? process.env.NEXT_PUBLIC_REVISION : "dev";
const version = process.env.NEXT_PUBLIC_VERSION ?? "dev"; const version = process.env.NEXT_PUBLIC_VERSION?.length ? process.env.NEXT_PUBLIC_VERSION : "dev";
const cachedFetcher = (resource) => cachedFetch(resource, 5).then((res) => res.json()); const cachedFetcher = (resource) => cachedFetch(resource, 5).then((res) => res.json());
@ -36,17 +36,14 @@ export default function Version() {
{version} ({revision.substring(0, 7)}, {formatDate(buildTime)}) {version} ({revision.substring(0, 7)}, {formatDate(buildTime)})
</> </>
) : ( ) : (
releaseData && <a
compareVersions(latestRelease.tag_name, version) > 0 && ( href={`https://github.com/benphelps/homepage/releases/tag/${version}`}
<a target="_blank"
href={`https://github.com/benphelps/homepage/releases/tag/${version}`} rel="noopener noreferrer"
target="_blank" className="ml-2 text-xs text-theme-500 dark:text-theme-400 flex flex-row items-center"
rel="noopener noreferrer" >
className="ml-2 text-xs text-theme-500 dark:text-theme-400 flex flex-row items-center" {version} ({revision.substring(0, 7)}, {formatDate(buildTime)})
> </a>
{version} ({revision.substring(0, 7)}, {formatDate(buildTime)})
</a>
)
)} )}
</span> </span>
{version === "main" || version === "dev" || version === "nightly" {version === "main" || version === "dev" || version === "nightly"

View File

@ -15,22 +15,23 @@ const textSizes = {
export default function DateTime({ options }) { export default function DateTime({ options }) {
const { text_size: textSize, format } = options; const { text_size: textSize, format } = options;
const { i18n } = useTranslation(); const { i18n } = useTranslation();
const [date, setDate] = useState(new Date()); const [date, setDate] = useState("");
useEffect(() => { useEffect(() => {
const dateFormat = new Intl.DateTimeFormat(i18n.language, { ...format });
const interval = setInterval(() => { const interval = setInterval(() => {
setDate(new Date()); setDate(dateFormat.format(new Date()));
}, 1000); }, 1000);
return () => clearInterval(interval); return () => clearInterval(interval);
}, [setDate]); }, [date, setDate, i18n.language, format]);
const dateFormat = new Intl.DateTimeFormat(i18n.language, { ...format });
return ( return (
<div className="flex flex-row items-center grow justify-end"> <div className="flex flex-col justify-center first:ml-0 ml-4">
<span className={`text-theme-800 dark:text-theme-200 ${textSizes[textSize || "lg"]}`}> <div className="flex flex-row items-center grow justify-end">
{dateFormat.format(date)} <span className={`text-theme-800 dark:text-theme-200 ${textSizes[textSize || "lg"]}`}>
</span> {date}
</span>
</div>
</div> </div>
); );
} }

View File

@ -1,4 +1,4 @@
import mapIcon from "utils/weather/owm-condition-map"; import mapIcon from "utils/weather/openmeteo-condition-map";
export default function Icon({ condition, timeOfDay }) { export default function Icon({ condition, timeOfDay }) {
const IconComponent = mapIcon(condition, timeOfDay); const IconComponent = mapIcon(condition, timeOfDay);

View File

@ -54,7 +54,7 @@ function Widget({ options }) {
<div className="hidden sm:flex flex-col items-center"> <div className="hidden sm:flex flex-col items-center">
<Icon <Icon
condition={data.weather[0].id} condition={data.weather[0].id}
timeOfDay={data.dt > data.sys.sunrise && data.dt < data.sys.sundown ? "day" : "night"} timeOfDay={data.dt > data.sys.sunrise && data.dt < data.sys.sunset ? "day" : "night"}
/> />
</div> </div>
<div className="flex flex-col ml-3 text-left"> <div className="flex flex-col ml-3 text-left">

View File

@ -52,7 +52,7 @@ export default function Memory({ expanded }) {
<div className="flex flex-col ml-3 text-left min-w-[85px]"> <div className="flex flex-col ml-3 text-left min-w-[85px]">
<span className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between"> <span className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between">
<div className="pl-0.5"> <div className="pl-0.5">
{t("common.bytes", { value: data.memory.freeMemMb * 1024 * 1024, maximumFractionDigits: 0, binary: true })} {t("common.bytes", { value: data.memory.freeMemMb * 1024 * 1024, maximumFractionDigits: 1, binary: true })}
</div> </div>
<div className="pr-1">{t("resources.free")}</div> <div className="pr-1">{t("resources.free")}</div>
</span> </span>
@ -61,7 +61,7 @@ export default function Memory({ expanded }) {
<div className="pl-0.5"> <div className="pl-0.5">
{t("common.bytes", { {t("common.bytes", {
value: data.memory.totalMemMb * 1024 * 1024, value: data.memory.totalMemMb * 1024 * 1024,
maximumFractionDigits: 0, maximumFractionDigits: 1,
binary: true, binary: true,
})} })}
</div> </div>

View File

@ -12,7 +12,7 @@ export default function Widget({ options }) {
options.type = "unifi_console"; options.type = "unifi_console";
const { data: statsData, error: statsError } = useWidgetAPI(options, "stat/sites", { index: options.index }); const { data: statsData, error: statsError } = useWidgetAPI(options, "stat/sites", { index: options.index });
if (statsError || statsData?.error) { if (statsError) {
return ( return (
<div className="flex flex-col justify-center first:ml-0 ml-4"> <div className="flex flex-col justify-center first:ml-0 ml-4">
<div className="flex flex-row items-center justify-end"> <div className="flex flex-row items-center justify-end">

View File

@ -9,9 +9,6 @@ export default function Document() {
content="A highly customizable homepage (or startpage / application dashboard) with Docker and service API integrations." content="A highly customizable homepage (or startpage / application dashboard) with Docker and service API integrations."
/> />
<meta name="apple-mobile-web-app-capable" content="yes" /> <meta name="apple-mobile-web-app-capable" content="yes" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png?v=4" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png?v=4" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png?v=4" />
<link rel="manifest" href="/site.webmanifest?v=4" /> <link rel="manifest" href="/site.webmanifest?v=4" />
<link rel="mask-icon" href="/safari-pinned-tab.svg?v=4" color="#1e9cd7" /> <link rel="mask-icon" href="/safari-pinned-tab.svg?v=4" color="#1e9cd7" />
</Head> </Head>

View File

@ -69,7 +69,7 @@ export default async function handler(req, res) {
}); });
} catch { } catch {
res.status(500).send({ res.status(500).send({
error: "unknown error", error: {message: "Unknown error"},
}); });
} }
} }

View File

@ -35,6 +35,7 @@ export default async function handler(req, res) {
return res.status(200).json({ return res.status(200).json({
status: info.State.Status, status: info.State.Status,
health: info.State.Health?.Status
}); });
} }
@ -56,6 +57,7 @@ export default async function handler(req, res) {
return res.status(200).json({ return res.status(200).json({
status: info.State.Status, status: info.State.Status,
health: info.State.Health?.Status
}); });
} }

35
src/pages/api/ping.js Normal file
View File

@ -0,0 +1,35 @@
import { performance } from "perf_hooks";
import createLogger from "utils/logger";
import { httpProxy } from "utils/proxy/http";
const logger = createLogger("ping");
export default async function handler(req, res) {
const { ping: pingURL } = req.query;
if (!pingURL) {
logger.debug("No ping URL specified");
return res.status(400).send({
error: "No ping URL given",
});
}
let startTime = performance.now();
let [status] = await httpProxy(pingURL, {
method: "HEAD"
});
let endTime = performance.now();
if (status >= 400) {
// try one more time as a GET in case HEAD is rejected for whatever reason
startTime = performance.now();
[status] = await httpProxy(pingURL);
endTime = performance.now();
}
return res.status(200).json({
status,
latency: endTime - startTime
});
}

View File

@ -1,8 +1,9 @@
import cachedFetch from "utils/proxy/cached-fetch"; import cachedFetch from "utils/proxy/cached-fetch";
export default async function handler(req, res) { export default async function handler(req, res) {
const { latitude, longitude, units, cache } = req.query; const { latitude, longitude, units, cache, timezone } = req.query;
const degrees = units === "imperial" ? "fahrenheit" : "celsius"; const degrees = units === "imperial" ? "fahrenheit" : "celsius";
const apiUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&daily=sunrise,sunset&current_weather=true&temperature_unit=${degrees}&timezone=auto`; const timezeone = timezone ?? 'auto'
const apiUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&daily=sunrise,sunset&current_weather=true&temperature_unit=${degrees}&timezone=${timezeone}`;
return res.send(await cachedFetch(apiUrl, cache)); return res.send(await cachedFetch(apiUrl, cache));
} }

View File

@ -35,7 +35,7 @@ const Version = dynamic(() => import("components/version"), {
ssr: false, ssr: false,
}); });
const rightAlignedWidgets = ["weatherapi", "openweathermap", "weather", "search", "datetime"]; const rightAlignedWidgets = ["weatherapi", "openweathermap", "weather", "openmeteo", "search", "datetime"];
export async function getStaticProps() { export async function getStaticProps() {
let logger; let logger;
@ -219,9 +219,17 @@ function Home({ initialSettings }) {
<title>{initialSettings.title || "Homepage"}</title> <title>{initialSettings.title || "Homepage"}</title>
{initialSettings.base && <base href={initialSettings.base} />} {initialSettings.base && <base href={initialSettings.base} />}
{initialSettings.favicon ? ( {initialSettings.favicon ? (
<link rel="icon" href={initialSettings.favicon} /> <>
<link rel="apple-touch-icon" sizes="180x180" href={initialSettings.favicon} />
<link rel="icon" href={initialSettings.favicon} />
</>
) : ( ) : (
<link rel="shortcut icon" href="/homepage.ico" /> <>
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png?v=4" />
<link rel="shortcut icon" href="/homepage.ico" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png?v=4" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png?v=4" />
</>
)} )}
<meta <meta
name="msapplication-TileColor" name="msapplication-TileColor"
@ -272,7 +280,7 @@ function Home({ initialSettings }) {
)} )}
{bookmarks && ( {bookmarks && (
<div className="grow flex flex-wrap pt-0 p-4 sm:p-8"> <div className={`grow flex flex-wrap pt-0 p-4 sm:p-8 gap-2 grid-cols-1 lg:grid-cols-2 lg:grid-cols-${Math.min(6, bookmarks.length)}`}>
{bookmarks.map((group) => ( {bookmarks.map((group) => (
<BookmarksGroup key={group.name} group={group} /> <BookmarksGroup key={group.name} group={group} />
))} ))}

View File

@ -1,6 +1,6 @@
--- ---
# For configuration options and examples, please see: # For configuration options and examples, please see:
# https://github.com/benphelps/homepage/wiki/Bookmarks # https://gethomepage.dev/en/configs/bookmarks
- Developer: - Developer:
- Github: - Github:

View File

@ -1,6 +1,6 @@
--- ---
# For configuration options and examples, please see: # For configuration options and examples, please see:
# https://github.com/benphelps/homepage/wiki/Docker-Integration # https://gethomepage.dev/en/configs/docker/
# my-docker: # my-docker:
# host: 127.0.0.1 # host: 127.0.0.1

View File

@ -1,6 +1,6 @@
--- ---
# For configuration options and examples, please see: # For configuration options and examples, please see:
# https://github.com/benphelps/homepage/wiki/Services # https://gethomepage.dev/en/configs/services
- My First Group: - My First Group:
- My First Service: - My First Service:

View File

@ -1,6 +1,6 @@
--- ---
# For configuration options and examples, please see: # For configuration options and examples, please see:
# https://github.com/benphelps/homepage/wiki/Settings # https://gethomepage.dev/en/configs/settings
providers: providers:
openweathermap: openweathermapapikey openweathermap: openweathermapapikey

View File

@ -1,6 +1,6 @@
--- ---
# For configuration options and examples, please see: # For configuration options and examples, please see:
# https://github.com/benphelps/homepage/wiki/Information-Widgets # https://gethomepage.dev/en/configs/widgets
- resources: - resources:
cpu: true cpu: true

View File

@ -54,3 +54,7 @@ body {
background-color: var(--scrollbar-thumb); background-color: var(--scrollbar-thumb);
border-radius: 0.25em; border-radius: 0.25em;
} }
::-webkit-details-marker {
display: none;
}

View File

@ -4,7 +4,7 @@ import path from "path";
import yaml from "js-yaml"; import yaml from "js-yaml";
import checkAndCopyConfig from "utils/config/config"; import checkAndCopyConfig, { getSettings } from "utils/config/config";
import { servicesFromConfig, servicesFromDocker, cleanServiceGroups } from "utils/config/service-helpers"; import { servicesFromConfig, servicesFromDocker, cleanServiceGroups } from "utils/config/service-helpers";
import { cleanWidgetGroups, widgetsFromConfig } from "utils/config/widget-helpers"; import { cleanWidgetGroups, widgetsFromConfig } from "utils/config/widget-helpers";
@ -46,6 +46,7 @@ export async function widgetsResponse() {
export async function servicesResponse() { export async function servicesResponse() {
let discoveredServices; let discoveredServices;
let configuredServices; let configuredServices;
let initialSettings;
try { try {
discoveredServices = cleanServiceGroups(await servicesFromDocker()); discoveredServices = cleanServiceGroups(await servicesFromDocker());
@ -63,11 +64,21 @@ export async function servicesResponse() {
configuredServices = []; configuredServices = [];
} }
try {
initialSettings = await getSettings();
} catch (e) {
console.error("Failed to load settings.yaml, please check for errors");
if (e) console.error(e);
initialSettings = {};
}
const mergedGroupsNames = [ const mergedGroupsNames = [
...new Set([discoveredServices.map((group) => group.name), configuredServices.map((group) => group.name)].flat()), ...new Set([discoveredServices.map((group) => group.name), configuredServices.map((group) => group.name)].flat()),
]; ];
const mergedGroups = []; const sortedGroups = [];
const unsortedGroups = [];
const definedLayouts = initialSettings.layout ? Object.keys(initialSettings.layout) : null;
mergedGroupsNames.forEach((groupName) => { mergedGroupsNames.forEach((groupName) => {
const discoveredGroup = discoveredServices.find((group) => group.name === groupName) || { services: [] }; const discoveredGroup = discoveredServices.find((group) => group.name === groupName) || { services: [] };
@ -78,8 +89,14 @@ export async function servicesResponse() {
services: [...discoveredGroup.services, ...configuredGroup.services].filter((service) => service), services: [...discoveredGroup.services, ...configuredGroup.services].filter((service) => service),
}; };
mergedGroups.push(mergedGroup); if (definedLayouts) {
const layoutIndex = definedLayouts.findIndex(layout => layout === mergedGroup.name);
if (layoutIndex > -1) sortedGroups[layoutIndex] = mergedGroup;
else unsortedGroups.push(mergedGroup);
} else {
unsortedGroups.push(mergedGroup);
}
}); });
return mergedGroups; return [...sortedGroups.filter(g => g), ...unsortedGroups];
} }

View File

@ -32,5 +32,5 @@ export function getSettings() {
const settingsYaml = join(process.cwd(), "config", "settings.yaml"); const settingsYaml = join(process.cwd(), "config", "settings.yaml");
const fileContents = readFileSync(settingsYaml, "utf8"); const fileContents = readFileSync(settingsYaml, "utf8");
return yaml.load(fileContents); return yaml.load(fileContents) ?? {};
} }

View File

@ -118,6 +118,7 @@ export function cleanServiceGroups(groups) {
container, container,
currency, // coinmarketcap widget currency, // coinmarketcap widget
symbols, symbols,
defaultinterval
} = cleanedService.widget; } = cleanedService.widget;
cleanedService.widget = { cleanedService.widget = {
@ -129,6 +130,7 @@ export function cleanServiceGroups(groups) {
if (currency) cleanedService.widget.currency = currency; if (currency) cleanedService.widget.currency = currency;
if (symbols) cleanedService.widget.symbols = symbols; if (symbols) cleanedService.widget.symbols = symbols;
if (defaultinterval) cleanedService.widget.defaultinterval = defaultinterval;
if (type === "docker") { if (type === "docker") {
if (server) cleanedService.widget.server = server; if (server) cleanedService.widget.server = server;

View File

@ -4,10 +4,15 @@ import { format as utilFormat } from "node:util";
import winston from "winston"; import winston from "winston";
import checkAndCopyConfig, { getSettings } from "utils/config/config";
let winstonLogger; let winstonLogger;
function init() { function init() {
const configPath = join(process.cwd(), "config"); const configPath = join(process.cwd(), "config");
checkAndCopyConfig("settings.yaml");
const settings = getSettings();
const logpath = settings.logpath || configPath;
function combineMessageAndSplat() { function combineMessageAndSplat() {
return { return {
@ -57,7 +62,7 @@ function init() {
winston.format.timestamp(), winston.format.timestamp(),
winston.format.printf(messageFormatter) winston.format.printf(messageFormatter)
), ),
filename: `${configPath}/logs/homepage.log`, filename: `${logpath}/logs/homepage.log`,
handleExceptions: true, handleExceptions: true,
handleRejections: true, handleRejections: true,
}), }),

View File

@ -1,5 +1,6 @@
import getServiceWidget from "utils/config/service-helpers"; import getServiceWidget from "utils/config/service-helpers";
import { formatApiCall } from "utils/proxy/api-helpers"; import { formatApiCall } from "utils/proxy/api-helpers";
import validateWidgetData from "utils/proxy/validate-widget-data";
import { httpProxy } from "utils/proxy/http"; import { httpProxy } from "utils/proxy/http";
import createLogger from "utils/logger"; import createLogger from "utils/logger";
import widgets from "widgets/widgets"; import widgets from "widgets/widgets";
@ -31,6 +32,10 @@ export default async function credentialedProxyHandler(req, res) {
headers.Authorization = `Bearer ${widget.key}`; headers.Authorization = `Bearer ${widget.key}`;
} else if (widget.type === "proxmox") { } else if (widget.type === "proxmox") {
headers.Authorization = `PVEAPIToken=${widget.username}=${widget.password}`; headers.Authorization = `PVEAPIToken=${widget.username}=${widget.password}`;
} else if (widget.type === "autobrr") {
headers["X-API-Token"] = `${widget.key}`;
} else if (widget.type === "tubearchivist") {
headers.Authorization = `Token ${widget.key}`;
} else { } else {
headers["X-API-Key"] = `${widget.key}`; headers["X-API-Key"] = `${widget.key}`;
} }
@ -47,7 +52,11 @@ export default async function credentialedProxyHandler(req, res) {
} }
if (status >= 400) { if (status >= 400) {
logger.debug("HTTP Error %d calling %s//%s%s...", status, url.protocol, url.hostname, url.pathname); logger.error("HTTP Error %d calling %s", status, url.toString());
}
if (!validateWidgetData(widget, endpoint, data)) {
return res.status(500).json({error: {message: "Invalid data", url, data}});
} }
if (contentType) res.setHeader("Content-Type", contentType); if (contentType) res.setHeader("Content-Type", contentType);

View File

@ -1,5 +1,6 @@
import getServiceWidget from "utils/config/service-helpers"; import getServiceWidget from "utils/config/service-helpers";
import { formatApiCall } from "utils/proxy/api-helpers"; import { formatApiCall } from "utils/proxy/api-helpers";
import validateWidgetData from "utils/proxy/validate-widget-data";
import { httpProxy } from "utils/proxy/http"; import { httpProxy } from "utils/proxy/http";
import createLogger from "utils/logger"; import createLogger from "utils/logger";
import widgets from "widgets/widgets"; import widgets from "widgets/widgets";
@ -32,6 +33,11 @@ export default async function genericProxyHandler(req, res, map) {
}); });
let resultData = data; let resultData = data;
if (!validateWidgetData(widget, endpoint, resultData)) {
return res.status(status).json({error: {message: "Invalid data", url, data: resultData}});
}
if (status === 200 && map) { if (status === 200 && map) {
resultData = map(data); resultData = map(data);
} }
@ -44,6 +50,7 @@ export default async function genericProxyHandler(req, res, map) {
if (status >= 400) { if (status >= 400) {
logger.debug("HTTP Error %d calling %s//%s%s...", status, url.protocol, url.hostname, url.pathname); logger.debug("HTTP Error %d calling %s//%s%s...", status, url.protocol, url.hostname, url.pathname);
return res.status(status).json({error: {message: "HTTP Error", url, data}});
} }
return res.status(status).send(resultData); return res.status(status).send(resultData);

View File

@ -0,0 +1,82 @@
import { JSONRPCClient, JSONRPCErrorException } from "json-rpc-2.0";
import { formatApiCall } from "utils/proxy/api-helpers";
import { httpProxy } from "utils/proxy/http";
import getServiceWidget from "utils/config/service-helpers";
import createLogger from "utils/logger";
import widgets from "widgets/widgets";
const logger = createLogger("jsonrpcProxyHandler");
export async function sendJsonRpcRequest(url, method, params, username, password) {
const headers = {
"content-type": "application/json",
"accept": "application/json"
}
if (username && password) {
headers.authorization = `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`;
}
const client = new JSONRPCClient(async (rpcRequest) => {
const body = JSON.stringify(rpcRequest);
const httpRequestParams = {
method: "POST",
headers,
body
};
// eslint-disable-next-line no-unused-vars
const [status, contentType, data] = await httpProxy(url, httpRequestParams);
if (status === 200) {
const json = JSON.parse(data.toString());
// in order to get access to the underlying error object in the JSON response
// you must set `result` equal to undefined
if (json.error && (json.result === null)) {
json.result = undefined;
}
return client.receive(json);
}
return Promise.reject(data?.error ? data : new Error(data.toString()));
});
try {
const response = await client.request(method, params);
return [200, "application/json", JSON.stringify(response)];
}
catch (e) {
if (e instanceof JSONRPCErrorException) {
logger.debug("Error calling JSONPRC endpoint: %s. %s", url, e.message);
return [200, "application/json", JSON.stringify({result: null, error: {code: e.code, message: e.message}})];
}
logger.warn("Error calling JSONPRC endpoint: %s. %s", url, e);
return [500, "application/json", JSON.stringify({result: null, error: {code: 2, message: e.toString()}})];
}
}
export default async function jsonrpcProxyHandler(req, res) {
const { group, service, endpoint: method } = req.query;
if (group && service) {
const widget = await getServiceWidget(group, service);
const api = widgets?.[widget.type]?.api;
if (!api) {
return res.status(403).json({ error: "Service does not support API calls" });
}
if (widget) {
const url = formatApiCall(api, { ...widget });
// eslint-disable-next-line no-unused-vars
const [status, contentType, data] = await sendJsonRpcRequest(url, method, null, widget.username, widget.password);
return res.status(status).end(data);
}
}
logger.debug("Invalid or missing proxy service type '%s' in group '%s'", service, group);
return res.status(400).json({ error: "Invalid proxy service type" });
}

View File

@ -18,10 +18,15 @@ function addCookieHandler(url, params) {
}; };
} }
export function httpsRequest(url, params) { function handleRequest(requestor, url, params) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
addCookieHandler(url, params); addCookieHandler(url, params);
const request = https.request(url, params, (response) => { if (params?.body) {
params.headers = params.headers ?? {};
params.headers['content-length'] = Buffer.byteLength(params.body);
}
const request = requestor.request(url, params, (response) => {
const data = []; const data = [];
response.on("data", (chunk) => { response.on("data", (chunk) => {
@ -38,7 +43,7 @@ export function httpsRequest(url, params) {
reject([500, error]); reject([500, error]);
}); });
if (params.body) { if (params?.body) {
request.write(params.body); request.write(params.body);
} }
@ -46,32 +51,12 @@ export function httpsRequest(url, params) {
}); });
} }
export function httpsRequest(url, params) {
return handleRequest(https, url, params);
}
export function httpRequest(url, params) { export function httpRequest(url, params) {
return new Promise((resolve, reject) => { return handleRequest(http, url, params);
addCookieHandler(url, params);
const request = http.request(url, params, (response) => {
const data = [];
response.on("data", (chunk) => {
data.push(chunk);
});
response.on("end", () => {
addCookieToJar(url, response.headers);
resolve([response.statusCode, response.headers["content-type"], Buffer.concat(data), response.headers]);
});
});
request.on("error", (error) => {
reject([500, error]);
});
if (params.body) {
request.write(params.body);
}
request.end();
});
} }
export async function httpProxy(url, params = {}) { export async function httpProxy(url, params = {}) {
@ -96,8 +81,8 @@ export async function httpProxy(url, params = {}) {
return [status, contentType, data, responseHeaders]; return [status, contentType, data, responseHeaders];
} }
catch (err) { catch (err) {
logger.error("Error calling %s//%s%s...", url.protocol, url.hostname, url.pathname); logger.error("Error calling %s//%s%s...", constructedUrl.protocol, constructedUrl.hostname, constructedUrl.pathname);
logger.error(err); logger.error(err);
return [500, "application/json", { error: "Unexpected error" }, null]; return [500, "application/json", { error: {message: err?.message ?? "Unknown error", url, rawError: err} }, null];
} }
} }

View File

@ -3,5 +3,11 @@ import useSWR from "swr";
import { formatProxyUrl } from "./api-helpers"; import { formatProxyUrl } from "./api-helpers";
export default function useWidgetAPI(widget, ...options) { export default function useWidgetAPI(widget, ...options) {
return useSWR(formatProxyUrl(widget, ...options)); const config = {};
if (options?.refreshInterval) {
config.refreshInterval = options.refreshInterval;
}
const { data, error } = useSWR(formatProxyUrl(widget, ...options), config);
// make the data error the top-level error
return { data, error: data?.error ?? error }
} }

View File

@ -0,0 +1,22 @@
import widgets from "widgets/widgets";
export default function validateWidgetData(widget, endpoint, data) {
let valid = true;
let dataParsed;
try {
dataParsed = JSON.parse(data);
} catch (e) {
valid = false;
}
if (dataParsed && Object.entries(dataParsed).length) {
const validate = widgets[widget.type]?.mappings?.[endpoint]?.validate;
validate?.forEach(key => {
if (dataParsed[key] === undefined) {
valid = false;
}
});
}
return valid;
}

View File

@ -0,0 +1,211 @@
import * as Icons from "react-icons/wi";
// see https://open-meteo.com/en/docs
const conditions = [
{
code: 1,
icon: {
day: Icons.WiDayCloudy,
night: Icons.WiNightAltCloudy,
},
},
{
code: 2,
icon: {
day: Icons.WiDayCloudy,
night: Icons.WiNightAltCloudy,
},
},
{
code: 3,
icon: {
day: Icons.WiDayCloudy,
night: Icons.WiNightAltCloudy,
},
},
{
code: 45,
icon: {
day: Icons.WiDayFog,
night: Icons.WiNightFog,
},
},
{
code: 48,
icon: {
day: Icons.WiDayFog,
night: Icons.WiNightFog,
},
},
{
code: 51,
icon: {
day: Icons.WiDaySprinkle,
night: Icons.WiNightAltSprinkle,
},
},
{
code: 53,
icon: {
day: Icons.WiDaySprinkle,
night: Icons.WiNightAltSprinkle,
},
},
{
code: 55,
icon: {
day: Icons.WiDaySprinkle,
night: Icons.WiNightAltSprinkle,
},
},
{
code: 56,
icon: {
day: Icons.WiDaySleet,
night: Icons.WiNightAltSleet,
},
},
{
code: 57,
icon: {
day: Icons.WiDaySleet,
night: Icons.WiNightAltSleet,
},
},
{
code: 61,
icon: {
day: Icons.WiDayShowers,
night: Icons.WiNightAltShowers,
},
},
{
code: 63,
icon: {
day: Icons.WiDayShowers,
night: Icons.WiNightAltShowers,
},
},
{
code: 65,
icon: {
day: Icons.WiDayShowers,
night: Icons.WiNightAltShowers,
},
},
{
code: 66,
icon: {
day: Icons.WiDaySleet,
night: Icons.WiNightAltSleet,
},
},
{
code: 67,
icon: {
day: Icons.WiDaySleet,
night: Icons.WiNightAltSleet,
},
},
{
code: 71,
icon: {
day: Icons.WiDaySnow,
night: Icons.WiNightAltSnow,
},
},
{
code: 73,
icon: {
day: Icons.WiDaySnow,
night: Icons.WiNightAltSnow,
},
},
{
code: 75,
icon: {
day: Icons.WiDaySnow,
night: Icons.WiNightAltSnow,
},
},
{
code: 77,
icon: {
day: Icons.WiDaySnow,
night: Icons.WiNightAltSnow,
},
},
{
code: 80,
icon: {
day: Icons.WiDaySnow,
night: Icons.WiNightAltSnow,
},
},
{
code: 81,
icon: {
day: Icons.WiDaySnow,
night: Icons.WiNightAltSnow,
},
},
{
code: 82,
icon: {
day: Icons.WiDaySnow,
night: Icons.WiNightAltSnow,
},
},
{
code: 85,
icon: {
day: Icons.WiDaySnow,
night: Icons.WiNightAltSnow,
},
},
{
code: 86,
icon: {
day: Icons.WiDaySnow,
night: Icons.WiNightAltSnow,
},
},
{
code: 95,
icon: {
day: Icons.WiDayThunderstorm,
night: Icons.WiNightAltThunderstorm,
},
},
{
code: 96,
icon: {
day: Icons.WiDayThunderstorm,
night: Icons.WiNightAltThunderstorm,
},
},
{
code: 99,
icon: {
day: Icons.WiDayThunderstorm,
night: Icons.WiNightAltThunderstorm,
},
},
];
export default function mapIcon(weatherStatusCode, timeOfDay) {
const mapping = conditions.find((condition) => condition.code === weatherStatusCode);
if (mapping) {
if (timeOfDay === "day") {
return mapping.icon.day;
}
if (timeOfDay === "night") {
return mapping.icon.night;
}
}
return Icons.WiDaySunny;
}

View File

@ -12,7 +12,7 @@ export default function Component({ service }) {
const { data: adguardData, error: adguardError } = useWidgetAPI(widget, "stats"); const { data: adguardData, error: adguardError } = useWidgetAPI(widget, "stats");
if (adguardError) { if (adguardError) {
return <Container error={t("widget.api_error")} />; return <Container error={adguardError} />;
} }
if (!adguardData) { if (!adguardData) {

View File

@ -14,7 +14,8 @@ export default function Component({ service }) {
const { data: failedLoginsData, error: failedLoginsError } = useWidgetAPI(widget, "login_failed"); const { data: failedLoginsData, error: failedLoginsError } = useWidgetAPI(widget, "login_failed");
if (usersError || loginsError || failedLoginsError) { if (usersError || loginsError || failedLoginsError) {
return <Container error={t("widget.api_error")} />; const finalError = usersError ?? loginsError ?? failedLoginsError;
return <Container error={finalError} />;
} }
if (!usersData || !loginsData || !failedLoginsData) { if (!usersData || !loginsData || !failedLoginsData) {

View File

@ -0,0 +1,40 @@
import { useTranslation } from "next-i18next";
import Container from "components/services/widget/container";
import Block from "components/services/widget/block";
import useWidgetAPI from "utils/proxy/use-widget-api";
export default function Component({ service }) {
const { t } = useTranslation();
const { widget } = service;
const { data: statsData, error: statsError } = useWidgetAPI(widget, "stats");
const { data: filtersData, error: filtersError } = useWidgetAPI(widget, "filters");
const { data: indexersData, error: indexersError } = useWidgetAPI(widget, "indexers");
if (statsError || filtersError || indexersError) {
const finalError = statsError ?? filtersError ?? indexersError;
return <Container error={finalError} />;
}
if (!statsData || !filtersData || !indexersData) {
return (
<Container service={service}>
<Block label="autobrr.approvedPushes" />
<Block label="autobrr.rejectedPushes" />
<Block label="autobrr.filters" />
<Block label="autobrr.indexers" />
</Container>
);
}
return (
<Container service={service}>
<Block label="autobrr.approvedPushes" value={t("common.number", { value: statsData.push_approved_count })} />
<Block label="autobrr.rejectedPushes" value={t("common.number", { value: statsData.push_rejected_count })} />
<Block label="autobrr.filters" value={t("common.number", { value: filtersData.length })} />
<Block label="autobrr.indexers" value={t("common.number", { value: indexersData.length })} />
</Container>
);
}

View File

@ -0,0 +1,24 @@
import credentialedProxyHandler from "utils/proxy/handlers/credentialed";
const widget = {
api: "{url}/api/{endpoint}",
proxyHandler: credentialedProxyHandler,
mappings: {
stats: {
endpoint: "release/stats",
validate: [
"push_approved_count",
"push_rejected_count"
]
},
filters: {
endpoint: "filters",
},
indexers: {
endpoint: "release/indexers",
},
},
};
export default widget;

View File

@ -12,8 +12,9 @@ export default function Component({ service }) {
const { data: episodesData, error: episodesError } = useWidgetAPI(widget, "episodes"); const { data: episodesData, error: episodesError } = useWidgetAPI(widget, "episodes");
const { data: moviesData, error: moviesError } = useWidgetAPI(widget, "movies"); const { data: moviesData, error: moviesError } = useWidgetAPI(widget, "movies");
if (episodesError || moviesError) { if (moviesError || episodesError) {
return <Container error="widget.api_error" />; const finalError = moviesError ?? episodesError;
return <Container error={finalError} />;
} }
if (!episodesData || !moviesData) { if (!episodesData || !moviesData) {

View File

@ -9,10 +9,14 @@ export default function Component({ service }) {
const { widget } = service; const { widget } = service;
const { data } = useWidgetAPI(widget, "info"); const { data, error } = useWidgetAPI(widget, "info");
if (error) {
return <Container error={error} />;
}
if (!data) { if (!data) {
return <Container error="widget.api_error" />; return <Container service={service} />;
} }
const totalObserved = Object.keys(data).length; const totalObserved = Object.keys(data).length;

View File

@ -17,11 +17,12 @@ export default function Component({ service }) {
{ label: t("coinmarketcap.30days"), value: "30d" }, { label: t("coinmarketcap.30days"), value: "30d" },
]; ];
const [dateRange, setDateRange] = useState(dateRangeOptions[0].value);
const { widget } = service; const { widget } = service;
const { symbols } = widget; const { symbols } = widget;
const currencyCode = widget.currency ?? "USD"; const currencyCode = widget.currency ?? "USD";
const interval = widget.defaultinterval ?? dateRangeOptions[0].value;
const [dateRange, setDateRange] = useState(interval);
const { data: statsData, error: statsError } = useWidgetAPI(widget, "v1/cryptocurrency/quotes/latest", { const { data: statsData, error: statsError } = useWidgetAPI(widget, "v1/cryptocurrency/quotes/latest", {
symbol: `${symbols.join(",")}`, symbol: `${symbols.join(",")}`,
@ -37,7 +38,7 @@ export default function Component({ service }) {
} }
if (statsError) { if (statsError) {
return <Container error={t("widget.api_error")} />; return <Container error={statsError} />;
} }
if (!statsData || !dateRange) { if (!statsData || !dateRange) {

View File

@ -3,39 +3,52 @@ import dynamic from "next/dynamic";
const components = { const components = {
adguard: dynamic(() => import("./adguard/component")), adguard: dynamic(() => import("./adguard/component")),
authentik: dynamic(() => import("./authentik/component")), authentik: dynamic(() => import("./authentik/component")),
autobrr: dynamic(() => import("./autobrr/component")),
bazarr: dynamic(() => import("./bazarr/component")), bazarr: dynamic(() => import("./bazarr/component")),
changedetectionio: dynamic(() => import("./changedetectionio/component")), changedetectionio: dynamic(() => import("./changedetectionio/component")),
coinmarketcap: dynamic(() => import("./coinmarketcap/component")), coinmarketcap: dynamic(() => import("./coinmarketcap/component")),
deluge: dynamic(() => import("./deluge/component")),
diskstation: dynamic(() => import("./diskstation/component")),
docker: dynamic(() => import("./docker/component")), docker: dynamic(() => import("./docker/component")),
emby: dynamic(() => import("./emby/component")), emby: dynamic(() => import("./emby/component")),
flood: dynamic(() => import("./flood/component")),
gluetun: dynamic(() => import("./gluetun/component")),
gotify: dynamic(() => import("./gotify/component")), gotify: dynamic(() => import("./gotify/component")),
hdhomerun: dynamic(() => import("./hdhomerun/component")),
homebridge: dynamic(() => import("./homebridge/component")), homebridge: dynamic(() => import("./homebridge/component")),
jackett: dynamic(() => import("./jackett/component")), jackett: dynamic(() => import("./jackett/component")),
jellyfin: dynamic(() => import("./emby/component")), jellyfin: dynamic(() => import("./emby/component")),
jellyseerr: dynamic(() => import("./jellyseerr/component")), jellyseerr: dynamic(() => import("./jellyseerr/component")),
lidarr: dynamic(() => import("./lidarr/component")), lidarr: dynamic(() => import("./lidarr/component")),
mastodon: dynamic(() => import("./mastodon/component")), mastodon: dynamic(() => import("./mastodon/component")),
navidrome: dynamic(() => import("./navidrome/component")),
npm: dynamic(() => import("./npm/component")), npm: dynamic(() => import("./npm/component")),
nzbget: dynamic(() => import("./nzbget/component")), nzbget: dynamic(() => import("./nzbget/component")),
ombi: dynamic(() => import("./ombi/component")), ombi: dynamic(() => import("./ombi/component")),
overseerr: dynamic(() => import("./overseerr/component")), overseerr: dynamic(() => import("./overseerr/component")),
paperlessngx: dynamic(() => import("./paperlessngx/component")),
pihole: dynamic(() => import("./pihole/component")), pihole: dynamic(() => import("./pihole/component")),
plex: dynamic(() => import("./plex/component")), plex: dynamic(() => import("./plex/component")),
portainer: dynamic(() => import("./portainer/component")), portainer: dynamic(() => import("./portainer/component")),
prowlarr: dynamic(() => import("./prowlarr/component")), prowlarr: dynamic(() => import("./prowlarr/component")),
proxmox: dynamic(() => import("./proxmox/component")), proxmox: dynamic(() => import("./proxmox/component")),
pyload: dynamic(() => import("./pyload/component")),
qbittorrent: dynamic(() => import("./qbittorrent/component")), qbittorrent: dynamic(() => import("./qbittorrent/component")),
radarr: dynamic(() => import("./radarr/component")), radarr: dynamic(() => import("./radarr/component")),
readarr: dynamic(() => import("./readarr/component")), readarr: dynamic(() => import("./readarr/component")),
rutorrent: dynamic(() => import("./rutorrent/component")), rutorrent: dynamic(() => import("./rutorrent/component")),
sabnzbd: dynamic(() => import("./sabnzbd/component")), sabnzbd: dynamic(() => import("./sabnzbd/component")),
scrutiny: dynamic(() => import("./scrutiny/component")),
sonarr: dynamic(() => import("./sonarr/component")), sonarr: dynamic(() => import("./sonarr/component")),
speedtest: dynamic(() => import("./speedtest/component")), speedtest: dynamic(() => import("./speedtest/component")),
strelaysrv: dynamic(() => import("./strelaysrv/component")), strelaysrv: dynamic(() => import("./strelaysrv/component")),
tautulli: dynamic(() => import("./tautulli/component")), tautulli: dynamic(() => import("./tautulli/component")),
traefik: dynamic(() => import("./traefik/component")), traefik: dynamic(() => import("./traefik/component")),
transmission: dynamic(() => import("./transmission/component")), transmission: dynamic(() => import("./transmission/component")),
tubearchivist: dynamic(() => import("./tubearchivist/component")),
truenas: dynamic(() => import("./truenas/component")),
unifi: dynamic(() => import("./unifi/component")), unifi: dynamic(() => import("./unifi/component")),
watchtower: dynamic(() => import("./watchtower/component")),
}; };
export default components; export default components;

View File

@ -0,0 +1,52 @@
import { useTranslation } from "next-i18next";
import Container from "components/services/widget/container";
import Block from "components/services/widget/block";
import useWidgetAPI from "utils/proxy/use-widget-api";
export default function Component({ service }) {
const { t } = useTranslation();
const { widget } = service;
const { data: torrentData, error: torrentError } = useWidgetAPI(widget);
if (torrentError) {
return <Container error={torrentError} />;
}
if (!torrentData) {
return (
<Container service={service}>
<Block label="deluge.leech" />
<Block label="deluge.download" />
<Block label="deluge.seed" />
<Block label="deluge.upload" />
</Container>
);
}
const { torrents } = torrentData;
const keys = torrents ? Object.keys(torrents) : [];
let rateDl = 0;
let rateUl = 0;
let completed = 0;
for (let i = 0; i < keys.length; i += 1) {
const torrent = torrents[keys[i]];
rateDl += torrent.download_payload_rate;
rateUl += torrent.upload_payload_rate;
completed += torrent.total_remaining === 0 ? 1 : 0;
}
const leech = keys.length - completed || 0;
return (
<Container service={service}>
<Block label="deluge.leech" value={t("common.number", { value: leech })} />
<Block label="deluge.download" value={t("common.bitrate", { value: rateDl })} />
<Block label="deluge.seed" value={t("common.number", { value: completed })} />
<Block label="deluge.upload" value={t("common.bitrate", { value: rateUl })} />
</Container>
);
}

View File

@ -0,0 +1,63 @@
import { formatApiCall } from "utils/proxy/api-helpers";
import { sendJsonRpcRequest } from "utils/proxy/handlers/jsonrpc";
import getServiceWidget from "utils/config/service-helpers";
import createLogger from "utils/logger";
import widgets from "widgets/widgets";
const logger = createLogger("delugeProxyHandler");
const dataMethod = "web.update_ui";
const dataParams = [
["queue", "name", "total_wanted", "state", "progress", "download_payload_rate", "upload_payload_rate", "total_remaining"],
{}
];
const loginMethod = "auth.login";
async function sendRpc(url, method, params) {
const [status, contentType, data] = await sendJsonRpcRequest(url, method, params);
const json = JSON.parse(data.toString());
if (json?.error) {
if (json.error.code === 1) {
return [403, contentType, data];
}
return [500, contentType, data];
}
return [status, contentType, data];
}
function login(url, password) {
return sendRpc(url, loginMethod, [password]);
}
export default async function delugeProxyHandler(req, res) {
const { group, service } = req.query;
if (!group || !service) {
logger.debug("Invalid or missing service '%s' or group '%s'", service, group);
return res.status(400).json({ error: "Invalid proxy service type" });
}
const widget = await getServiceWidget(group, service);
if (!widget) {
logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group);
return res.status(400).json({ error: "Invalid proxy service type" });
}
const api = widgets?.[widget.type]?.api
const url = new URL(formatApiCall(api, { ...widget }));
let [status, contentType, data] = await sendRpc(url, dataMethod, dataParams);
if (status === 403) {
[status, contentType, data] = await login(url, widget.password);
if (status !== 200) {
return res.status(status).end(data);
}
// eslint-disable-next-line no-unused-vars
[status, contentType, data] = await sendRpc(url, dataMethod, dataParams);
}
return res.status(status).end(data);
}

View File

@ -0,0 +1,8 @@
import delugeProxyHandler from "./proxy";
const widget = {
api: "{url}/json",
proxyHandler: delugeProxyHandler,
};
export default widget;

View File

@ -0,0 +1,41 @@
import { useTranslation } from "next-i18next";
import Container from "components/services/widget/container";
import Block from "components/services/widget/block";
import useWidgetAPI from "utils/proxy/use-widget-api";
export default function Component({ service }) {
const { t } = useTranslation();
const { widget } = service;
const { data: listData, error: listError } = useWidgetAPI(widget, "list");
if (listError) {
return <Container error={listError} />;
}
const tasks = listData?.data?.tasks;
if (!tasks) {
return (
<Container service={service}>
<Block label="diskstation.leech" />
<Block label="diskstation.download" />
<Block label="diskstation.seed" />
<Block label="diskstation.upload" />
</Container>
);
}
const rateDl = tasks.reduce((acc, task) => acc + (task?.additional?.transfer?.speed_download ?? 0), 0);
const rateUl = tasks.reduce((acc, task) => acc + (task?.additional?.transfer?.speed_upload ?? 0), 0);
const completed = tasks.filter((task) => task?.additional?.transfer?.size_downloaded === task?.size)?.length || 0;
const leech = tasks.length - completed || 0;
return (
<Container service={service}>
<Block label="diskstation.leech" value={t("common.number", { value: leech })} />
<Block label="diskstation.download" value={t("common.bitrate", { value: rateDl })} />
<Block label="diskstation.seed" value={t("common.number", { value: completed })} />
<Block label="diskstation.upload" value={t("common.bitrate", { value: rateUl })} />
</Container>
);
}

View File

@ -0,0 +1,70 @@
import { formatApiCall } from "utils/proxy/api-helpers";
import { httpProxy } from "utils/proxy/http";
import createLogger from "utils/logger";
import widgets from "widgets/widgets";
import getServiceWidget from "utils/config/service-helpers";
const logger = createLogger("diskstationProxyHandler");
const authApi = "{url}/webapi/auth.cgi?api=SYNO.API.Auth&version=2&method=login&account={username}&passwd={password}&session=DownloadStation&format=cookie"
async function login(widget) {
const loginUrl = formatApiCall(authApi, widget);
const [status, contentType, data] = await httpProxy(loginUrl);
if (status !== 200) {
return [status, contentType, data];
}
const json = JSON.parse(data.toString());
if (json?.success !== true) {
// from https://global.download.synology.com/download/Document/Software/DeveloperGuide/Package/DownloadStation/All/enu/Synology_Download_Station_Web_API.pdf
/*
Code Description
400 No such account or incorrect password
401 Account disabled
402 Permission denied
403 2-step verification code required
404 Failed to authenticate 2-step verification code
*/
let message = "Authentication failed.";
if (json?.error?.code >= 403) message += " 2FA enabled.";
logger.warn("Unable to login. Code: %d", json?.error?.code);
return [401, "application/json", JSON.stringify({ code: json?.error?.code, message })];
}
return [status, contentType, data];
}
export default async function diskstationProxyHandler(req, res) {
const { group, service, endpoint } = req.query;
if (!group || !service) {
return res.status(400).json({ error: "Invalid proxy service type" });
}
const widget = await getServiceWidget(group, service);
const api = widgets?.[widget.type]?.api;
if (!api) {
return res.status(403).json({ error: "Service does not support API calls" });
}
const url = formatApiCall(api, { endpoint, ...widget });
let [status, contentType, data] = await httpProxy(url);
if (status !== 200) {
logger.debug("Error %d calling endpoint %s", status, url);
return res.status(status, data);
}
const json = JSON.parse(data.toString());
if (json?.success !== true) {
logger.debug("Logging in to DiskStation");
[status, contentType, data] = await login(widget);
if (status !== 200) {
return res.status(status).end(data)
}
[status, contentType, data] = await httpProxy(url);
}
if (contentType) res.setHeader("Content-Type", contentType);
return res.status(status).send(data);
}

View File

@ -0,0 +1,14 @@
import diskstationProxyHandler from "./proxy";
const widget = {
api: "{url}/webapi/DownloadStation/task.cgi?api=SYNO.DownloadStation.Task&version=1&method={endpoint}",
proxyHandler: diskstationProxyHandler,
mappings: {
"list": {
endpoint: "list&additional=transfer",
},
},
};
export default widget;

View File

@ -17,8 +17,9 @@ export default function Component({ service }) {
const { data: statsData, error: statsError } = useSWR(`/api/docker/stats/${widget.container}/${widget.server || ""}`); const { data: statsData, error: statsError } = useSWR(`/api/docker/stats/${widget.container}/${widget.server || ""}`);
if (statsError || statusError) { if (statsError || statsData?.error || statusError || statusData?.error) {
return <Container error={t("widget.api_error")} />; const finalError = statsError ?? statsData?.error ?? statusError ?? statusData?.error;
return <Container error={finalError} />;
} }
if (statusData && statusData.status !== "running") { if (statusData && statusData.status !== "running") {
@ -45,7 +46,9 @@ export default function Component({ service }) {
return ( return (
<Container service={service}> <Container service={service}>
<Block label="docker.cpu" value={t("common.percent", { value: calculateCPUPercent(statsData.stats) })} /> <Block label="docker.cpu" value={t("common.percent", { value: calculateCPUPercent(statsData.stats) })} />
<Block label="docker.mem" value={t("common.bytes", { value: statsData.stats.memory_stats.usage })} /> {statsData.stats.memory_stats.usage &&
<Block label="docker.mem" value={t("common.bytes", { value: statsData.stats.memory_stats.usage })} />
}
{network && ( {network && (
<> <>
<Block label="docker.rx" value={t("common.bytes", { value: network.rx_bytes })} /> <Block label="docker.rx" value={t("common.bytes", { value: network.rx_bytes })} />

View File

@ -1,10 +1,10 @@
import useSWR from "swr";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import { BsVolumeMuteFill, BsFillPlayFill, BsPauseFill, BsCpu, BsFillCpuFill } from "react-icons/bs"; import { BsVolumeMuteFill, BsFillPlayFill, BsPauseFill, BsCpu, BsFillCpuFill } from "react-icons/bs";
import { MdOutlineSmartDisplay } from "react-icons/md"; import { MdOutlineSmartDisplay } from "react-icons/md";
import Container from "components/services/widget/container"; import Container from "components/services/widget/container";
import { formatProxyUrl, formatProxyUrlWithSegments } from "utils/proxy/api-helpers"; import { formatProxyUrlWithSegments } from "utils/proxy/api-helpers";
import useWidgetAPI from "utils/proxy/use-widget-api";
function ticksToTime(ticks) { function ticksToTime(ticks) {
const milliseconds = ticks / 10000; const milliseconds = ticks / 10000;
@ -157,7 +157,7 @@ export default function Component({ service }) {
data: sessionsData, data: sessionsData,
error: sessionsError, error: sessionsError,
mutate: sessionMutate, mutate: sessionMutate,
} = useSWR(formatProxyUrl(widget, "Sessions"), { } = useWidgetAPI(widget, "Sessions", {
refreshInterval: 5000, refreshInterval: 5000,
}); });
@ -172,7 +172,7 @@ export default function Component({ service }) {
} }
if (sessionsError) { if (sessionsError) {
return <Container error={t("widget.api_error")} />; return <Container error={sessionsError} />;
} }
if (!sessionsData) { if (!sessionsData) {

View File

@ -10,7 +10,7 @@ const widget = {
}, },
PlayControl: { PlayControl: {
method: "POST", method: "POST",
enpoint: "Sessions/{sessionId}/Playing/{command}", endpoint: "Sessions/{sessionId}/Playing/{command}",
segments: ["sessionId", "command"], segments: ["sessionId", "command"],
}, },
}, },

View File

@ -0,0 +1,53 @@
import { useTranslation } from "next-i18next";
import Container from "components/services/widget/container";
import Block from "components/services/widget/block";
import useWidgetAPI from "utils/proxy/use-widget-api";
export default function Component({ service }) {
const { t } = useTranslation();
const { widget } = service;
const { data: torrentData, error: torrentError } = useWidgetAPI(widget, "torrents");
if (torrentError || !torrentData?.torrents) {
return <Container error={torrentError ?? {message: "No torrent data returned"}} />;
}
if (!torrentData || !torrentData.torrents) {
return (
<Container service={service}>
<Block label="flood.leech" />
<Block label="flood.download" />
<Block label="flood.seed" />
<Block label="flood.upload" />
</Container>
);
}
let rateDl = 0;
let rateUl = 0;
let completed = 0;
let leech = 0;
Object.values(torrentData.torrents).forEach(torrent => {
rateDl += torrent.downRate;
rateUl += torrent.upRate;
if(torrent.status.includes('complete')){
completed += 1;
}
if(torrent.status.includes('downloading')){
leech += 1;
}
})
return (
<Container service={service}>
<Block label="flood.leech" value={t("common.number", { value: leech })} />
<Block label="flood.download" value={t("common.bitrate", { value: rateDl })} />
<Block label="flood.seed" value={t("common.number", { value: completed })} />
<Block label="flood.upload" value={t("common.bitrate", { value: rateUl })} />
</Container>
);
}

View File

@ -0,0 +1,66 @@
import { formatApiCall } from "utils/proxy/api-helpers";
import { httpProxy } from "utils/proxy/http";
import getServiceWidget from "utils/config/service-helpers";
import createLogger from "utils/logger";
const logger = createLogger("floodProxyHandler");
async function login(widget) {
logger.debug("flood is rejecting the request, logging in.");
const loginUrl = new URL(`${widget.url}/api/auth/authenticate`).toString();
const loginParams = {
method: "POST",
headers: { "Content-Type": "application/json" },
body: null
};
if (widget.username && widget.password) {
loginParams.body = JSON.stringify({
"username": widget.username,
"password": widget.password
});
}
// eslint-disable-next-line no-unused-vars
const [status, contentType, data] = await httpProxy(loginUrl, loginParams);
return [status, data];
}
export default async function floodProxyHandler(req, res) {
const { group, service, endpoint } = req.query;
if (!group || !service) {
logger.debug("Invalid or missing service '%s' or group '%s'", service, group);
return res.status(400).json({ error: "Invalid proxy service type" });
}
const widget = await getServiceWidget(group, service);
if (!widget) {
logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group);
return res.status(400).json({ error: "Invalid proxy service type" });
}
const url = new URL(formatApiCall("{url}/api/{endpoint}", { endpoint, ...widget }));
const params = { method: "GET", headers: {} };
let [status, contentType, data] = await httpProxy(url, params);
if (status === 401) {
[status, data] = await login(widget);
if (status !== 200) {
logger.error("HTTP %d logging in to flood. Data: %s", status, data);
return res.status(status).end(data);
}
[status, contentType, data] = await httpProxy(url, params);
}
if (status !== 200) {
logger.error("HTTP %d getting data from flood. Data: %s", status, data);
}
if (contentType) res.setHeader("Content-Type", contentType);
return res.status(status).send(data);
}

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