diff --git a/docs/widgets/info/glances.md b/docs/widgets/info/glances.md index b7fd7efd4..52c5cf285 100644 --- a/docs/widgets/info/glances.md +++ b/docs/widgets/info/glances.md @@ -12,6 +12,7 @@ The Glances widget allows you to monitor the resources (CPU, memory, storage, te url: http://host.or.ip:port username: user # optional if auth enabled in Glances password: pass # optional if auth enabled in Glances + version: 4 # required only if running glances v4 or higher, defaults to 3 cpu: true # optional, enabled by default, disable by setting to false mem: true # optional, enabled by default, disable by setting to false cputemp: true # disabled by default diff --git a/docs/widgets/services/authentik.md b/docs/widgets/services/authentik.md index 3b84009fc..a92b84ec3 100644 --- a/docs/widgets/services/authentik.md +++ b/docs/widgets/services/authentik.md @@ -7,14 +7,15 @@ Learn more about [Authentik](https://github.com/goauthentik/authentik). This widget reads the number of active users in the system, as well as logins for the last 24 hours. -You will need to generate an API token for an existing user. To do so follow these steps: +You will need to generate an API token for an existing user under `Admin Portal` > `Directory` > `Tokens & App passwords`. +Make sure to set Intent to "API Token". -1. Navigate to the Authentik Admin Portal -2. Expand Directory, the click Tokens & App passwords -3. Click the Create button -4. Fill out the dialog making sure to set Intent to API Token -5. Click the Create button on the dialog -6. Click the copy button on the far right of the newly created API Token +The account you made the API token for also needs the following **Assigned global permissions** in Authentik: + +- authentik Core + - User +- authentik Events + - Event Allowed fields: `["users", "loginsLast24H", "failedLoginsLast24H"]`. diff --git a/docs/widgets/services/crowdsec.md b/docs/widgets/services/crowdsec.md new file mode 100644 index 000000000..608367dfd --- /dev/null +++ b/docs/widgets/services/crowdsec.md @@ -0,0 +1,19 @@ +--- +title: Crowdsec +description: Crowdsec Widget Configuration +--- + +Learn more about [Crowdsec](https://crowdsec.net). + +See the [crowdsec docs](https://docs.crowdsec.net/docs/local_api/intro/#machines) for information about registering a machine, +in most instances you can use the default credentials (`/etc/crowdsec/local_api_credentials.yaml`). + +Allowed fields: ["alerts", "bans"] + +```yaml +widget: + type: crowdsec + url: http://crowdsechostorip:port + username: localhost # machine_id in crowdsec + passowrd: password +``` diff --git a/docs/widgets/services/glances.md b/docs/widgets/services/glances.md index 134dcb5f6..562cf57a2 100644 --- a/docs/widgets/services/glances.md +++ b/docs/widgets/services/glances.md @@ -17,8 +17,11 @@ widget: url: http://glances.host.or.ip:port username: user # optional if auth enabled in Glances password: pass # optional if auth enabled in Glances + version: 4 # required only if running glances v4 or higher, defaults to 3 metric: cpu diskUnits: bytes # optional, bytes (default) or bbytes. Only applies to disk + refreshInterval: 5000 # optional - in milliseconds, defaults to 1000 or more, depending on the metric + pointsLimit: 15 # optional, defaults to 15 ``` _Please note, this widget does not need an `href`, `icon` or `description` on its parent service. To achieve the same effect as the examples above, see as an example:_ diff --git a/docs/widgets/services/jackett.md b/docs/widgets/services/jackett.md index 22e089a4f..e102743be 100644 --- a/docs/widgets/services/jackett.md +++ b/docs/widgets/services/jackett.md @@ -5,7 +5,7 @@ description: Jackett Widget Configuration Learn more about [Jackett](https://github.com/Jackett/Jackett). -Jackett must not have any authentication for the widget to work. +If Jackett has an admin password set, you must set the `password` field for the widget to work. Allowed fields: `["configured", "errored"]`. @@ -13,5 +13,5 @@ Allowed fields: `["configured", "errored"]`. widget: type: jackett url: http://jackett.host.or.ip - key: jackettapikey + password: jackettadminpassword # optional ``` diff --git a/mkdocs.yml b/mkdocs.yml index a0994fadd..e58cb1e4e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -44,6 +44,7 @@ nav: - widgets/services/channelsdvrserver.md - widgets/services/cloudflared.md - widgets/services/coin-market-cap.md + - widgets/services/crowdsec.md - widgets/services/customapi.md - widgets/services/deluge.md - widgets/services/diskstation.md diff --git a/public/locales/af/common.json b/public/locales/af/common.json index 9145dec2f..654130bb0 100644 --- a/public/locales/af/common.json +++ b/public/locales/af/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Vanlyn", + "offline_alt": "Vanlyn", "online": "Aanlyn", "total": "Totaal", "unknown": "Onbekend" @@ -863,5 +864,13 @@ "users": "Gebruikers", "recipes": "Resepte", "keywords": "Sleutelwoorde" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "Met Waarborg", + "locations": "Plekke", + "labels": "Etikette", + "users": "Gebruikers", + "totalValue": "Totale Waarde" } } diff --git a/public/locales/ar/common.json b/public/locales/ar/common.json index 93da6cc1e..28497fd4f 100644 --- a/public/locales/ar/common.json +++ b/public/locales/ar/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "غير متصل", + "offline_alt": "غير متصل", "online": "مُتّصل", "total": "المجموع", "unknown": "مجهول" @@ -863,5 +864,13 @@ "users": "المستخدمون", "recipes": "وصفات", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "المستخدمون", + "totalValue": "Total Value" } } diff --git a/public/locales/bg/common.json b/public/locales/bg/common.json index 04aef92fd..3fc1676b8 100644 --- a/public/locales/bg/common.json +++ b/public/locales/bg/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Изключен", + "offline_alt": "Изключен", "online": "Online", "total": "Общо", "unknown": "Неизв." @@ -863,5 +864,13 @@ "users": "Потребители", "recipes": "Рецепти", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "Потребители", + "totalValue": "Total Value" } } diff --git a/public/locales/ca/common.json b/public/locales/ca/common.json index 87c9afe34..4c7796ff9 100644 --- a/public/locales/ca/common.json +++ b/public/locales/ca/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Fora de línia", + "offline_alt": "Fora de línia", "online": "Online", "total": "Total", "unknown": "Desconegut" @@ -863,5 +864,13 @@ "users": "Usuaris", "recipes": "Recipes", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "Usuaris", + "totalValue": "Total Value" } } diff --git a/public/locales/cs/common.json b/public/locales/cs/common.json index de7999ae7..810432074 100644 --- a/public/locales/cs/common.json +++ b/public/locales/cs/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Offline", + "offline_alt": "Offline", "online": "Online", "total": "Celkem", "unknown": "Neznámý" @@ -863,5 +864,13 @@ "users": "Uživatelé", "recipes": "Recipes", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "Uživatelé", + "totalValue": "Total Value" } } diff --git a/public/locales/da/common.json b/public/locales/da/common.json index 310d2e677..390cb1f60 100644 --- a/public/locales/da/common.json +++ b/public/locales/da/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Offline", + "offline_alt": "Offline", "online": "Online", "total": "Total", "unknown": "Ukendt" @@ -863,5 +864,13 @@ "users": "Brugere", "recipes": "Opskrifter", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "Brugere", + "totalValue": "Total Value" } } diff --git a/public/locales/de/common.json b/public/locales/de/common.json index 7238a6855..529c5ea51 100644 --- a/public/locales/de/common.json +++ b/public/locales/de/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Offline", + "offline_alt": "Offline", "online": "Online", "total": "Gesamt", "unknown": "Unbekannt" @@ -863,5 +864,13 @@ "users": "Benutzer", "recipes": "Rezepte", "keywords": "Schlagwörter" + }, + "homebox": { + "items": "Objekte", + "totalWithWarranty": "Mit Garantie", + "locations": "Orte", + "labels": "Labels", + "users": "Benutzer", + "totalValue": "Gesamtwert" } } diff --git a/public/locales/el/common.json b/public/locales/el/common.json index 7f9900250..d006f1cce 100644 --- a/public/locales/el/common.json +++ b/public/locales/el/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Εκτός σύνδεσης", + "offline_alt": "Εκτός σύνδεσης", "online": "Συνδεδεμένοι", "total": "Σύνολο", "unknown": "Άγνωστο" @@ -863,5 +864,13 @@ "users": "Χρήστες", "recipes": "Recipes", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "Χρήστες", + "totalValue": "Total Value" } } diff --git a/public/locales/en/common.json b/public/locales/en/common.json index c7339c0b3..98daae9e5 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -872,5 +872,9 @@ "labels": "Labels", "users": "Users", "totalValue": "Total Value" + }, + "crowdsec": { + "alerts": "Alerts", + "bans": "Bans" } } diff --git a/public/locales/eo/common.json b/public/locales/eo/common.json index 0eae83daa..3b1fa0f51 100644 --- a/public/locales/eo/common.json +++ b/public/locales/eo/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Malkonekta", + "offline_alt": "Malkonekta", "online": "Online", "total": "Totalo", "unknown": "Nekonata" @@ -863,5 +864,13 @@ "users": "Uzantoj", "recipes": "Recipes", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "Uzantoj", + "totalValue": "Total Value" } } diff --git a/public/locales/es/common.json b/public/locales/es/common.json index aac49d638..c65cff848 100644 --- a/public/locales/es/common.json +++ b/public/locales/es/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Desconectado", + "offline_alt": "Desconectado", "online": "En línea", "total": "Total", "unknown": "Desconocido" @@ -544,7 +545,7 @@ "channels": "Canales", "hd": "Alta definición", "tunerCount": "Tuners", - "channelNumber": "Channel", + "channelNumber": "Canal", "channelNetwork": "Network", "signalStrength": "Strength", "signalQuality": "Quality", @@ -850,9 +851,9 @@ "playDuration": "Time Watched", "sceneSize": "Scenes Size", "sceneDuration": "Scenes Duration", - "images": "Images", + "images": "Imágenes", "imageSize": "Images Size", - "galleries": "Galleries", + "galleries": "Galerías", "performers": "Performers", "studios": "Studios", "movies": "Películas", @@ -863,5 +864,13 @@ "users": "Usuarios", "recipes": "Recetas", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "Con Garantía", + "locations": "Ubicaciones", + "labels": "Labels", + "users": "Usuarios", + "totalValue": "Total Value" } } diff --git a/public/locales/eu/common.json b/public/locales/eu/common.json index 4d7109e8f..0748eab09 100644 --- a/public/locales/eu/common.json +++ b/public/locales/eu/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Offline", + "offline_alt": "Offline", "online": "Online", "total": "Guztira", "unknown": "Ezezaguna" @@ -863,5 +864,13 @@ "users": "Users", "recipes": "Recipes", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "Users", + "totalValue": "Total Value" } } diff --git a/public/locales/fi/common.json b/public/locales/fi/common.json index eccbbfd0e..ec4c11b73 100644 --- a/public/locales/fi/common.json +++ b/public/locales/fi/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Offline", + "offline_alt": "Offline", "online": "Online", "total": "Yhteensä", "unknown": "Unknown" @@ -863,5 +864,13 @@ "users": "Users", "recipes": "Recipes", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "Users", + "totalValue": "Total Value" } } diff --git a/public/locales/fr/common.json b/public/locales/fr/common.json index 5602b7b9b..d2cd1a5cf 100644 --- a/public/locales/fr/common.json +++ b/public/locales/fr/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Hors ligne", + "offline_alt": "Hors ligne", "online": "En ligne", "total": "Total", "unknown": "Inconnu" @@ -863,5 +864,13 @@ "users": "Utilisateurs", "recipes": "Recettes", "keywords": "Mots-clés" + }, + "homebox": { + "items": "Objets", + "totalWithWarranty": "Avec garantie", + "locations": "Emplacements", + "labels": "Étiquettes", + "users": "Utilisateurs", + "totalValue": "Total Value" } } diff --git a/public/locales/he/common.json b/public/locales/he/common.json index 6897b7090..d18f98564 100644 --- a/public/locales/he/common.json +++ b/public/locales/he/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "כבוי", + "offline_alt": "כבוי", "online": "Online", "total": "סה\"כ", "unknown": "Unknown" @@ -863,5 +864,13 @@ "users": "Users", "recipes": "Recipes", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "Users", + "totalValue": "Total Value" } } diff --git a/public/locales/hi/common.json b/public/locales/hi/common.json index 65ed254a5..f05d60e0d 100644 --- a/public/locales/hi/common.json +++ b/public/locales/hi/common.json @@ -11,14 +11,14 @@ "percent": "{{value, percent}}", "number": "{{value, number}}", "ms": "{{value, number}}", - "date": "{{value, date}}", + "date": "{value, date}", "relativeDate": "{{value, relativeDate}}", "uptime": "{{value, uptime}}", - "months": "mo", + "months": "माह", "days": "d", - "hours": "h", + "hours": "घं.", "minutes": "m", - "seconds": "s" + "seconds": "पल" }, "widget": { "missing_type": "Missing Widget Type: {{type}}", @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Offline", + "offline_alt": "Offline", "online": "Online", "total": "Total", "unknown": "Unknown" @@ -411,7 +412,7 @@ "free": "Free", "used": "Used", "days": "d", - "hours": "h", + "hours": "घं.", "crit": "Crit", "read": "Read", "write": "Write", @@ -863,5 +864,13 @@ "users": "Users", "recipes": "Recipes", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "Users", + "totalValue": "Total Value" } } diff --git a/public/locales/hr/common.json b/public/locales/hr/common.json index 84a2126cc..03cc89192 100644 --- a/public/locales/hr/common.json +++ b/public/locales/hr/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Offline", + "offline_alt": "Offline", "online": "Online", "total": "Ukupno", "unknown": "Nepoznato" @@ -863,5 +864,13 @@ "users": "Korisnici", "recipes": "Recepti", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "Korisnici", + "totalValue": "Total Value" } } diff --git a/public/locales/hu/common.json b/public/locales/hu/common.json index ae844fd6b..d1ac7035d 100644 --- a/public/locales/hu/common.json +++ b/public/locales/hu/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Nem elérhető", + "offline_alt": "Nem elérhető", "online": "Csatlakozva", "total": "Összes", "unknown": "Ismeretlen" @@ -124,8 +125,8 @@ "flood": { "download": "Letöltés", "upload": "Feltöltés", - "leech": "Letöltés", - "seed": "Feltöltés" + "leech": "Leech", + "seed": "Seed" }, "freshrss": { "subscriptions": "Előfizetések", @@ -202,14 +203,14 @@ "transmission": { "download": "Letöltés", "upload": "Feltöltés", - "leech": "Letöltés", - "seed": "Feltöltés" + "leech": "Leech", + "seed": "Seed" }, "qbittorrent": { "download": "Letöltés", "upload": "Feltöltés", - "leech": "Letöltés", - "seed": "Feltöltés" + "leech": "Leech", + "seed": "Seed" }, "qnap": { "cpuUsage": "Processzor Használat", @@ -222,14 +223,14 @@ "deluge": { "download": "Letöltés", "upload": "Feltöltés", - "leech": "Letöltés", - "seed": "Feltöltés" + "leech": "Leech", + "seed": "Seed" }, "downloadstation": { "download": "Letöltés", "upload": "Feltöltés", - "leech": "Letöltés", - "seed": "Feltöltés" + "leech": "Leech", + "seed": "Seed" }, "sonarr": { "wanted": "Keresett", @@ -396,7 +397,7 @@ "proxmox": { "mem": "RAM", "cpu": "Processzor", - "lxc": "LXC", + "lxc": "LXC-k", "vms": "VM-ek" }, "glances": { @@ -525,7 +526,7 @@ "playlists": "Lejátszási listák" }, "truenas": { - "load": "Rendszerterheltség", + "load": "Rendszerterhelés", "uptime": "Üzemidő", "alerts": "Riasztások" }, @@ -543,14 +544,14 @@ "hdhomerun": { "channels": "Csatornák", "hd": "HD", - "tunerCount": "Tuners", - "channelNumber": "Channel", - "channelNetwork": "Network", - "signalStrength": "Strength", - "signalQuality": "Quality", - "symbolQuality": "Quality", + "tunerCount": "Tuner-ek", + "channelNumber": "Csatorna", + "channelNetwork": "Hálózat", + "signalStrength": "Erősség", + "signalQuality": "Minőség", + "symbolQuality": "Minőség", "networkRate": "Bitráta", - "clientIP": "Client" + "clientIP": "Kliens" }, "scrutiny": { "passed": "Megfelelt", @@ -797,10 +798,10 @@ }, "openwrt": { "uptime": "Üzemidő", - "cpuLoad": "CPU Load Avg (5m)", + "cpuLoad": "Átlag CPU terhelés (5p)", "up": "Fel", "down": "Le", - "bytesTx": "Transmitted", + "bytesTx": "Továbbított", "bytesRx": "Fogadott" }, "uptimerobot": { @@ -833,35 +834,43 @@ "criticals": "Kritikusok" }, "plantit": { - "events": "Events", - "plants": "Plants", + "events": "Események", + "plants": "Növények", "photos": "Fényképek", - "species": "Species" + "species": "Fajok" }, "gitea": { - "notifications": "Notifications", + "notifications": "Üzenetek", "issues": "Problémák", - "pulls": "Pull Requests" + "pulls": "Pull request-ek" }, "stash": { - "scenes": "Scenes", - "scenesPlayed": "Scenes Played", - "playCount": "Total Plays", - "playDuration": "Time Watched", - "sceneSize": "Scenes Size", - "sceneDuration": "Scenes Duration", - "images": "Images", - "imageSize": "Images Size", - "galleries": "Galleries", - "performers": "Performers", - "studios": "Studios", + "scenes": "Jelenetek", + "scenesPlayed": "Lejátszott jelenetek", + "playCount": "Összes leátszás", + "playDuration": "Nézett idő", + "sceneSize": "Jelenetek mérete", + "sceneDuration": "Jelenetek hossza", + "images": "Képek", + "imageSize": "Képek mérete", + "galleries": "Galériák", + "performers": "Előadók", + "studios": "Stúdiók", "movies": "Film", "tags": "Címkék", - "oCount": "O Count" + "oCount": "O szám" }, "tandoor": { "users": "Felhasználók", "recipes": "Receptek", - "keywords": "Keywords" + "keywords": "Kulcsszavak" + }, + "homebox": { + "items": "Tárgyak", + "totalWithWarranty": "Garanciával", + "locations": "Helyek", + "labels": "Címkék", + "users": "Felhasználók", + "totalValue": "Teljes érték" } } diff --git a/public/locales/id/common.json b/public/locales/id/common.json index 794c6567d..38d44f4b1 100644 --- a/public/locales/id/common.json +++ b/public/locales/id/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Offline", + "offline_alt": "Offline", "online": "Online", "total": "Total", "unknown": "Tidak Diketahui" @@ -863,5 +864,13 @@ "users": "Pengguna", "recipes": "Resep", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "Pengguna", + "totalValue": "Total Value" } } diff --git a/public/locales/it/common.json b/public/locales/it/common.json index 99f3e7ed7..421807f2e 100644 --- a/public/locales/it/common.json +++ b/public/locales/it/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Non in linea", + "offline_alt": "Non in linea", "online": "Online", "total": "Totale", "unknown": "Sconosciuto" @@ -863,5 +864,13 @@ "users": "Utenti", "recipes": "Ricette", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "Utenti", + "totalValue": "Total Value" } } diff --git a/public/locales/ja/common.json b/public/locales/ja/common.json index e85208151..a4507bf4e 100644 --- a/public/locales/ja/common.json +++ b/public/locales/ja/common.json @@ -14,7 +14,7 @@ "date": "{{value, date}}", "relativeDate": "{{value, relativeDate}}", "uptime": "{{value, uptime}}", - "months": "mo", + "months": "月", "days": "日", "hours": "時間", "minutes": "分", @@ -92,7 +92,7 @@ "siteMonitor": { "http_status": "HTTP ステータス", "error": "エラー", - "response": "Response", + "response": "応答", "down": "下へ", "up": "上へ", "not_available": "利用できません。" @@ -109,6 +109,7 @@ }, "esphome": { "offline": "オフライン", + "offline_alt": "オフライン", "online": "オンライン", "total": "合計", "unknown": "不明" @@ -133,21 +134,21 @@ }, "fritzbox": { "connectionStatus": "状態", - "connectionStatusUnconfigured": "Unconfigured", - "connectionStatusConnecting": "Connecting", - "connectionStatusAuthenticating": "Authenticating", - "connectionStatusPendingDisconnect": "Pending Disconnect", - "connectionStatusDisconnecting": "Disconnecting", - "connectionStatusDisconnected": "Disconnected", + "connectionStatusUnconfigured": "未設定", + "connectionStatusConnecting": "接続中", + "connectionStatusAuthenticating": "認証中", + "connectionStatusPendingDisconnect": "接続を切断する", + "connectionStatusDisconnecting": "接続を切断中", + "connectionStatusDisconnected": "切断されました", "connectionStatusConnected": "接続済み", "uptime": "稼働時間", - "maxDown": "Max. Down", - "maxUp": "Max. Up", + "maxDown": "最大ダウン", + "maxUp": "最大アップ", "down": "下へ", "up": "上へ", "received": "受信済み", "sent": "送信済み", - "externalIPAddress": "Ext. IP" + "externalIPAddress": "退出ID" }, "caddy": { "upstreams": "アップストリーム", @@ -543,7 +544,7 @@ "hdhomerun": { "channels": "チャンネル", "hd": "HD", - "tunerCount": "Tuners", + "tunerCount": "チューナー", "channelNumber": "チャンネル", "channelNetwork": "ネットワーク", "signalStrength": "強さ", @@ -562,7 +563,7 @@ "total": "合計" }, "peanut": { - "battery_charge": "Battery Charge", + "battery_charge": "バッテリー充電", "ups_load": "UPS 負荷", "ups_status": "UPS 状態", "online": "オンライン", @@ -825,43 +826,51 @@ "noEventsFound": "予定が見つかりません" }, "romm": { - "platforms": "Platforms", - "totalRoms": "Total ROMs" + "platforms": "プラットフォーム", + "totalRoms": "ROMの合計" }, "netdata": { "warnings": "警告", "criticals": "重大" }, "plantit": { - "events": "Events", - "plants": "Plants", + "events": "イベント", + "plants": "植物", "photos": "写真", - "species": "Species" + "species": "種" }, "gitea": { - "notifications": "Notifications", + "notifications": "通知", "issues": "課題", - "pulls": "Pull Requests" + "pulls": "プルリクエスト" }, "stash": { - "scenes": "Scenes", - "scenesPlayed": "Scenes Played", - "playCount": "Total Plays", - "playDuration": "Time Watched", - "sceneSize": "Scenes Size", - "sceneDuration": "Scenes Duration", - "images": "Images", - "imageSize": "Images Size", - "galleries": "Galleries", - "performers": "Performers", - "studios": "Studios", + "scenes": "シーン", + "scenesPlayed": "再生されたシーン", + "playCount": "合計再生数", + "playDuration": "視聴時間", + "sceneSize": "シーンサイズ", + "sceneDuration": "シーンの長さ", + "images": "画像", + "imageSize": "画像サイズ", + "galleries": "ギャラリー", + "performers": "出演者", + "studios": "スタジオ", "movies": "映画", "tags": "タグ", - "oCount": "O Count" + "oCount": "O カウント" }, "tandoor": { "users": "ユーザ", "recipes": "レシピ", - "keywords": "Keywords" + "keywords": "キーワード" + }, + "homebox": { + "items": "アイテム", + "totalWithWarranty": "保証付き", + "locations": "場所", + "labels": "ラベル", + "users": "ユーザ", + "totalValue": "合計値" } } diff --git a/public/locales/ko/common.json b/public/locales/ko/common.json index d80382c94..da8aa4925 100644 --- a/public/locales/ko/common.json +++ b/public/locales/ko/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "중지", + "offline_alt": "중지", "online": "Online", "total": "총합", "unknown": "알 수 없음" @@ -863,5 +864,13 @@ "users": "사용자", "recipes": "Recipes", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "사용자", + "totalValue": "Total Value" } } diff --git a/public/locales/lv/common.json b/public/locales/lv/common.json index f41ed97d3..8211b753d 100644 --- a/public/locales/lv/common.json +++ b/public/locales/lv/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Bezsaistē", + "offline_alt": "Bezsaistē", "online": "Online", "total": "Kopā", "unknown": "Nezināms" @@ -863,5 +864,13 @@ "users": "Lietotāji", "recipes": "Recipes", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "Lietotāji", + "totalValue": "Total Value" } } diff --git a/public/locales/ms/common.json b/public/locales/ms/common.json index f67cfaf61..46f08be87 100644 --- a/public/locales/ms/common.json +++ b/public/locales/ms/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Luar talian", + "offline_alt": "Luar talian", "online": "Dalam Talian", "total": "Jumlah", "unknown": "Tidak Diketahui" @@ -863,5 +864,13 @@ "users": "Pengguna", "recipes": "Resipi", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "Pengguna", + "totalValue": "Total Value" } } diff --git a/public/locales/nl/common.json b/public/locales/nl/common.json index cdf955058..f1cd7aacd 100644 --- a/public/locales/nl/common.json +++ b/public/locales/nl/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Onbereikbaar", + "offline_alt": "Onbereikbaar", "online": "Bereikbaar", "total": "Totaal", "unknown": "Onbekend" @@ -863,5 +864,13 @@ "users": "Gebruikers", "recipes": "Recepten", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "Met garantie", + "locations": "Locaties", + "labels": "Labels", + "users": "Gebruikers", + "totalValue": "Totale waarde" } } diff --git a/public/locales/no/common.json b/public/locales/no/common.json index 65ed254a5..86d6b20bf 100644 --- a/public/locales/no/common.json +++ b/public/locales/no/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Offline", + "offline_alt": "Offline", "online": "Online", "total": "Total", "unknown": "Unknown" @@ -863,5 +864,13 @@ "users": "Users", "recipes": "Recipes", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "Users", + "totalValue": "Total Value" } } diff --git a/public/locales/pl/common.json b/public/locales/pl/common.json index 6b6ac5b70..80b2d9ceb 100644 --- a/public/locales/pl/common.json +++ b/public/locales/pl/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Nieosiągalny", + "offline_alt": "Nieosiągalny", "online": "Dostępny", "total": "Całkowite", "unknown": "Nieznany" @@ -863,5 +864,13 @@ "users": "Użytkownicy", "recipes": "Recipes", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "Użytkownicy", + "totalValue": "Total Value" } } diff --git a/public/locales/pt/common.json b/public/locales/pt/common.json index b726a7194..aafdd8e0d 100644 --- a/public/locales/pt/common.json +++ b/public/locales/pt/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Desligado", + "offline_alt": "Desligado", "online": "Online", "total": "Total", "unknown": "Desconhecido" @@ -863,5 +864,13 @@ "users": "Utilizadores", "recipes": "Receitas", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "Utilizadores", + "totalValue": "Total Value" } } diff --git a/public/locales/pt_BR/common.json b/public/locales/pt_BR/common.json index 76f24bdfc..9cef642f3 100644 --- a/public/locales/pt_BR/common.json +++ b/public/locales/pt_BR/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Desligado", + "offline_alt": "Desligado", "online": "Online", "total": "Total", "unknown": "Desconhecido" @@ -863,5 +864,13 @@ "users": "Utilizadores", "recipes": "Recipes", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "Utilizadores", + "totalValue": "Total Value" } } diff --git a/public/locales/ro/common.json b/public/locales/ro/common.json index 8d4376fd7..987b1197a 100644 --- a/public/locales/ro/common.json +++ b/public/locales/ro/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Offline", + "offline_alt": "Offline", "online": "Online", "total": "Total", "unknown": "Necunoscut" @@ -863,5 +864,13 @@ "users": "Utilizatori", "recipes": "Recipes", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "Utilizatori", + "totalValue": "Total Value" } } diff --git a/public/locales/ru/common.json b/public/locales/ru/common.json index a3f9c0fda..81472ced5 100644 --- a/public/locales/ru/common.json +++ b/public/locales/ru/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Не в сети", + "offline_alt": "Не в сети", "online": "В сети", "total": "Всего", "unknown": "Неизвестен" @@ -830,38 +831,46 @@ }, "netdata": { "warnings": "Предупреждения", - "criticals": "Криты" + "criticals": "Критические" }, "plantit": { - "events": "Events", - "plants": "Plants", + "events": "События", + "plants": "Растения", "photos": "Фото", - "species": "Species" + "species": "Виды" }, "gitea": { - "notifications": "Notifications", + "notifications": "Уведомления", "issues": "Вопросы", - "pulls": "Pull Requests" + "pulls": "Запросы на слияние (Pull Request)" }, "stash": { - "scenes": "Scenes", - "scenesPlayed": "Scenes Played", - "playCount": "Total Plays", - "playDuration": "Time Watched", - "sceneSize": "Scenes Size", - "sceneDuration": "Scenes Duration", - "images": "Images", - "imageSize": "Images Size", - "galleries": "Galleries", - "performers": "Performers", - "studios": "Studios", + "scenes": "Сцены", + "scenesPlayed": "Проигранных сцен", + "playCount": "Всего проиграно", + "playDuration": "Просмотрено времени", + "sceneSize": "Размер сцены", + "sceneDuration": "Длительность сцен", + "images": "Изображения", + "imageSize": "Размер изображений", + "galleries": "Галереи", + "performers": "Исполнители", + "studios": "Студии", "movies": "Фильмы", "tags": "Теги", - "oCount": "O Count" + "oCount": "0" }, "tandoor": { "users": "Пользователи", "recipes": "Рецепты", - "keywords": "Keywords" + "keywords": "Ключевые слова" + }, + "homebox": { + "items": "Элементы", + "totalWithWarranty": "С гарантией", + "locations": "Местоположения", + "labels": "Ярлыки", + "users": "Пользователи", + "totalValue": "Общая стоимость" } } diff --git a/public/locales/sk/common.json b/public/locales/sk/common.json index a1e50792e..794bf9c6f 100644 --- a/public/locales/sk/common.json +++ b/public/locales/sk/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Nedostupný", + "offline_alt": "Nedostupný", "online": "Online", "total": "Celkovo", "unknown": "Neznáme" @@ -833,28 +834,28 @@ "criticals": "Kritické" }, "plantit": { - "events": "Events", - "plants": "Plants", + "events": "Udalosti", + "plants": "Rastliny", "photos": "Fotografie", - "species": "Species" + "species": "Druhy" }, "gitea": { - "notifications": "Notifications", + "notifications": "Oznámenia", "issues": "Problémy", - "pulls": "Pull Requests" + "pulls": "Pull requesty" }, "stash": { - "scenes": "Scenes", + "scenes": "Scény", "scenesPlayed": "Scenes Played", - "playCount": "Total Plays", - "playDuration": "Time Watched", - "sceneSize": "Scenes Size", - "sceneDuration": "Scenes Duration", - "images": "Images", - "imageSize": "Images Size", - "galleries": "Galleries", - "performers": "Performers", - "studios": "Studios", + "playCount": "Celkovo prehraní", + "playDuration": "Pozeraný čas", + "sceneSize": "Veľkosť obrazovky", + "sceneDuration": "Dĺžka scény", + "images": "Obrázky", + "imageSize": "Veľkosť obrázkov", + "galleries": "Galérie", + "performers": "Herci", + "studios": "Štúdiá", "movies": "Filmy", "tags": "Štítky", "oCount": "O Count" @@ -862,6 +863,14 @@ "tandoor": { "users": "Používatelia", "recipes": "Recepty", - "keywords": "Keywords" + "keywords": "Kľúčové slová" + }, + "homebox": { + "items": "Položky", + "totalWithWarranty": "So zárukou", + "locations": "Umiestnenia", + "labels": "Labels", + "users": "Používatelia", + "totalValue": "Total Value" } } diff --git a/public/locales/sl/common.json b/public/locales/sl/common.json index fd2e59123..d48cd7530 100644 --- a/public/locales/sl/common.json +++ b/public/locales/sl/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Ni povezan", + "offline_alt": "Ni povezan", "online": "Na spletu", "total": "Skupaj", "unknown": "Neznano" @@ -863,5 +864,13 @@ "users": "Uporabniki", "recipes": "Recepti", "keywords": "Ključne besede" + }, + "homebox": { + "items": "Predmeti", + "totalWithWarranty": "Z garancijo", + "locations": "Lokacije", + "labels": "Oznake", + "users": "Uporabniki", + "totalValue": "Skupna vrednost" } } diff --git a/public/locales/sr/common.json b/public/locales/sr/common.json index 65ed254a5..86d6b20bf 100644 --- a/public/locales/sr/common.json +++ b/public/locales/sr/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Offline", + "offline_alt": "Offline", "online": "Online", "total": "Total", "unknown": "Unknown" @@ -863,5 +864,13 @@ "users": "Users", "recipes": "Recipes", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "Users", + "totalValue": "Total Value" } } diff --git a/public/locales/sv/common.json b/public/locales/sv/common.json index e39ba7718..9311ed8d3 100644 --- a/public/locales/sv/common.json +++ b/public/locales/sv/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Offline", + "offline_alt": "Offline", "online": "Online", "total": "Total", "unknown": "Unknown" @@ -863,5 +864,13 @@ "users": "Användare", "recipes": "Recipes", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "Användare", + "totalValue": "Total Value" } } diff --git a/public/locales/te/common.json b/public/locales/te/common.json index 8c794cee4..90ff4f229 100644 --- a/public/locales/te/common.json +++ b/public/locales/te/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "ఆఫ్‌లైన్", + "offline_alt": "ఆఫ్‌లైన్", "online": "Online", "total": "మొత్తం", "unknown": "Unknown" @@ -863,5 +864,13 @@ "users": "వినియోగదారులు", "recipes": "Recipes", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "వినియోగదారులు", + "totalValue": "Total Value" } } diff --git a/public/locales/th/common.json b/public/locales/th/common.json index 612194a14..29b5b8c12 100644 --- a/public/locales/th/common.json +++ b/public/locales/th/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "ออฟไลน์", + "offline_alt": "ออฟไลน์", "online": "Online", "total": "ทั้งหมด", "unknown": "ไม่ทราบ" @@ -863,5 +864,13 @@ "users": "ผู้ใช้", "recipes": "Recipes", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "ผู้ใช้", + "totalValue": "Total Value" } } diff --git a/public/locales/tr/common.json b/public/locales/tr/common.json index 6d8a212c3..98960ac1c 100644 --- a/public/locales/tr/common.json +++ b/public/locales/tr/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Çevrimdışı", + "offline_alt": "Çevrimdışı", "online": "Çevrimiçi", "total": "Toplam", "unknown": "Bilinmiyor" @@ -136,18 +137,18 @@ "connectionStatusUnconfigured": "Yapılandırılmamış", "connectionStatusConnecting": "Bağlanıyor", "connectionStatusAuthenticating": "Kimlik doğrulanıyor", - "connectionStatusPendingDisconnect": "Pending Disconnect", + "connectionStatusPendingDisconnect": "Bağlantının Kesilmesi Bekleniyor", "connectionStatusDisconnecting": "Bağlantı kesiliyor...", "connectionStatusDisconnected": "Bağlantı kesildi", "connectionStatusConnected": "Bağlandı", "uptime": "Çalışma Süresi", - "maxDown": "Max. Down", - "maxUp": "Max. Up", + "maxDown": "Max. Indirme", + "maxUp": "Max. Gönderme", "down": "İndirme", "up": "Yükleme", "received": "Alınan", "sent": "Gönderilen", - "externalIPAddress": "Ext. IP" + "externalIPAddress": "Harici IP" }, "caddy": { "upstreams": "Akış", @@ -169,7 +170,7 @@ "transcoding": "Dönüştürülüyor", "bitrate": "Bit Oranı", "no_active": "Aktif akış yok", - "plex_connection_error": "Check Plex Connection" + "plex_connection_error": "Plex Bağlantısı Kontrol Ediliyor" }, "omada": { "connectedAp": "Bağlı AP'ler", @@ -426,7 +427,7 @@ "custom": "Özel", "visit": "Ziyaret", "url": "URL", - "searchsuggestion": "Suggestion" + "searchsuggestion": "Öneri" }, "wmo": { "0-day": "Güneşli", @@ -498,14 +499,14 @@ "down": "İndirme" }, "healthchecks": { - "new": "New", + "new": "Yeni", "up": "Yükleme", - "grace": "In Grace Period", + "grace": "Tolerans Döneminde", "down": "İndirme", - "paused": "Paused", + "paused": "Durduruldu", "status": "Durum", "last_ping": "Son Ping", - "never": "No pings yet" + "never": "Henüz ping yok" }, "watchtower": { "containers_scanned": "Tarandı", @@ -543,14 +544,14 @@ "hdhomerun": { "channels": "Kanallar", "hd": "HD", - "tunerCount": "Tuners", - "channelNumber": "Channel", - "channelNetwork": "Network", - "signalStrength": "Strength", - "signalQuality": "Quality", - "symbolQuality": "Quality", + "tunerCount": "Ayarlayıcılar", + "channelNumber": "Kanal", + "channelNetwork": "Ağ", + "signalStrength": "Sağlamlık", + "signalQuality": "Kalite", + "symbolQuality": "Kalite", "networkRate": "Bit Oranı", - "clientIP": "Client" + "clientIP": "Alıcı" }, "scrutiny": { "passed": "Geçti", @@ -563,11 +564,11 @@ }, "peanut": { "battery_charge": "Pil Yüzdesi", - "ups_load": "UPS Load", - "ups_status": "UPS Status", + "ups_load": "UPS Yükü", + "ups_status": "UPS Durumu", "online": "Çevrimiçi", "on_battery": "Pilde", - "low_battery": "Low Battery" + "low_battery": "Düşük Pil" }, "nextdns": { "wait": "Lütfen Bekleyin", @@ -577,7 +578,7 @@ "cpuLoad": "CPU Yükü", "memoryUsed": "Bellek Kullanımı", "uptime": "Çalışma Süresi", - "numberOfLeases": "Leases" + "numberOfLeases": "Kiralama" }, "xteve": { "streams_all": "Tüm Akışlar", @@ -585,9 +586,9 @@ "streams_xepg": "XEPG Kanalları" }, "opendtu": { - "yieldDay": "Today", - "absolutePower": "Power", - "relativePower": "Power %", + "yieldDay": "Bugün", + "absolutePower": "Güç", + "relativePower": "Güç %", "limit": "Limit" }, "opnsense": { @@ -606,25 +607,25 @@ "printer_state": "Durum", "temp_tool": "Araç sıcaklığı", "temp_bed": "Yatak sıcaklığı", - "job_completion": "Completion" + "job_completion": "Tamamlanma" }, "cloudflared": { - "origin_ip": "Origin IP", + "origin_ip": "Gerçek IP", "status": "Durum" }, "pfsense": { - "load": "Load Avg", - "memory": "Mem Usage", - "wanStatus": "WAN Status", + "load": "Ort. Yükleme", + "memory": "Bellek Kullanımı", + "wanStatus": "WAN Durumu", "up": "Yükleme", "down": "İndirme", "temp": "Sıcaklık", - "disk": "Disk Usage", + "disk": "Disk Kullanımı", "wanIP": "WAN IP" }, "proxmoxbackupserver": { - "datastore_usage": "Datastore", - "failed_tasks_24h": "Failed Tasks 24h", + "datastore_usage": "Veri deposu", + "failed_tasks_24h": "Başarısız Görevler 24h", "cpu_usage": "CPU", "memory_usage": "Bellek" }, @@ -638,14 +639,14 @@ "up": "Sites Up", "down": "Sites Down", "uptime": "Çalışma Süresi", - "incident": "Incident", + "incident": "Olay", "m": "dk" }, "atsumeru": { "series": "Diziler", - "archives": "Archives", - "chapters": "Chapters", - "categories": "Categories" + "archives": "Arşivler", + "chapters": "Bölümler", + "categories": "Kategoriler" }, "komga": { "libraries": "Kütüphane", @@ -672,42 +673,42 @@ "queue": "Kuyruk", "processing": "İşleniyor", "processed": "İşlendi", - "time": "Time" + "time": "Zaman" }, "grafana": { - "dashboards": "Dashboards", - "datasources": "Data Sources", - "totalalerts": "Total Alerts", - "alertstriggered": "Alerts Triggered" + "dashboards": "Kontrol Paneli", + "datasources": "Veri Kaynakları", + "totalalerts": "Toplam Uyarılar", + "alertstriggered": "Uyarılar Tetiklendi" }, "nextcloud": { - "cpuload": "Cpu Load", - "memoryusage": "Memory Usage", - "freespace": "Free Space", - "activeusers": "Active Users", - "numfiles": "Files", - "numshares": "Shared Items" + "cpuload": "Cpu Yükü", + "memoryusage": "Bellek Kullanımı", + "freespace": "Boş Alan", + "activeusers": "Aktif Kullanıcılar", + "numfiles": "Dosyalar", + "numshares": "Paylaşılan Öğeler" }, "kopia": { "status": "Durum", - "size": "Size", - "lastrun": "Last Run", - "nextrun": "Next Run", + "size": "Boyut", + "lastrun": "Son Çalışma", + "nextrun": "Sonraki Çalışma", "failed": "Başarısız" }, "unmanic": { - "active_workers": "Active Workers", - "total_workers": "Total Workers", - "records_total": "Queue Length" + "active_workers": "Aktif Kullanıcılar", + "total_workers": "Toplam Kullanıcılar", + "records_total": "Sıra Uzunluğu" }, "pterodactyl": { - "servers": "Servers", - "nodes": "Nodes" + "servers": "Sunucular", + "nodes": "Düğümler" }, "prometheus": { "targets_up": "Targets Up", "targets_down": "Targets Down", - "targets_total": "Total Targets" + "targets_total": "Toplam Hedef" }, "gatus": { "up": "Sites Up", @@ -715,50 +716,50 @@ "uptime": "Çalışma Süresi" }, "ghostfolio": { - "gross_percent_today": "Today", - "gross_percent_1y": "One year", - "gross_percent_max": "All time" + "gross_percent_today": "Bugün", + "gross_percent_1y": "Bir yıl", + "gross_percent_max": "Tüm zaman" }, "audiobookshelf": { - "podcasts": "Podcasts", + "podcasts": "Podcast", "books": "Kitaplar", - "podcastsDuration": "Duration", - "booksDuration": "Duration" + "podcastsDuration": "Süre", + "booksDuration": "Süre" }, "homeassistant": { "people_home": "People Home", - "lights_on": "Lights On", - "switches_on": "Switches On" + "lights_on": "Işıklar Açık", + "switches_on": "Aç" }, "whatsupdocker": { - "monitoring": "Monitoring", + "monitoring": "İzleme", "updates": "Güncellemeler" }, "calibreweb": { "books": "Kitaplar", - "authors": "Authors", - "categories": "Categories", + "authors": "Yazarlar", + "categories": "Kategoriler", "series": "Diziler" }, "jdownloader": { "downloadCount": "Kuyruk", "downloadBytesRemaining": "Kalan", - "downloadTotalBytes": "Size", + "downloadTotalBytes": "Boyut", "downloadSpeed": "Hız" }, "kavita": { "seriesCount": "Diziler", - "totalFiles": "Files" + "totalFiles": "Dosyalar" }, "azuredevops": { - "result": "Result", + "result": "Sonuç", "status": "Durum", "buildId": "Build ID", - "succeeded": "Succeeded", - "notStarted": "Not Started", + "succeeded": "Başarılı", + "notStarted": "Henüz Başlamadı", "failed": "Başarısız", - "canceled": "Canceled", - "inProgress": "In Progress", + "canceled": "İptal edildi", + "inProgress": "Sürüyor", "totalPrs": "Total PRs", "myPrs": "My PRs", "approved": "Onaylı" @@ -767,28 +768,28 @@ "status": "Durum", "online": "Çevrimiçi", "offline": "Çevrimdışı", - "name": "Name", - "map": "Map", - "currentPlayers": "Current players", + "name": "İsim", + "map": "Harita", + "currentPlayers": "Mevcut oyuncular", "players": "Oyuncular", - "maxPlayers": "Max players", - "bots": "Bots", + "maxPlayers": "Maks. oyuncu", + "bots": "Botlar", "ping": "Gecikme" }, "urbackup": { - "ok": "Ok", - "errored": "Errors", - "noRecent": "Out of Date", - "totalUsed": "Used Storage" + "ok": "Tamam", + "errored": "Hatalar", + "noRecent": "Tarihi geçmiş", + "totalUsed": "Kullanılan depolama alanı" }, "mealie": { - "recipes": "Recipes", + "recipes": "Tarifler", "users": "Kullanıcılar", - "categories": "Categories", - "tags": "Tags" + "categories": "Kategoriler", + "tags": "Etiketler" }, "openmediavault": { - "downloading": "Downloading", + "downloading": "İndiriliyor", "total": "Toplam", "running": "Çalışan", "stopped": "Durduruldu", @@ -797,71 +798,79 @@ }, "openwrt": { "uptime": "Çalışma Süresi", - "cpuLoad": "CPU Load Avg (5m)", + "cpuLoad": "CPU Yükü Ortalaması (5dk)", "up": "Yükleme", "down": "İndirme", - "bytesTx": "Transmitted", + "bytesTx": "İletilen", "bytesRx": "Alınan" }, "uptimerobot": { "status": "Durum", "uptime": "Çalışma Süresi", - "lastDown": "Last Downtime", - "downDuration": "Downtime Duration", + "lastDown": "Son Kesinti", + "downDuration": "Kesinti Süresi", "sitesUp": "Sites Up", "sitesDown": "Sites Down", - "paused": "Paused", - "notyetchecked": "Not Yet Checked", + "paused": "Durduruldu", + "notyetchecked": "Henüz Kontrol Edilmedi", "up": "Yükleme", - "seemsdown": "Seems Down", + "seemsdown": "Kapalı görünüyor", "down": "İndirme", "unknown": "Bilinmiyor" }, "calendar": { - "inCinemas": "In cinemas", - "physicalRelease": "Physical release", - "digitalRelease": "Digital release", - "noEventsToday": "No events for today!", - "noEventsFound": "No events found" + "inCinemas": "Sinemalarda", + "physicalRelease": "Fiziksel Yayınlanan", + "digitalRelease": "Dijital Yayınlanan", + "noEventsToday": "Bugün için etkinlik yok!", + "noEventsFound": "Etkinlik bulunamadı" }, "romm": { - "platforms": "Platforms", - "totalRoms": "Total ROMs" + "platforms": "Platformlar", + "totalRoms": "Toplam ROM'lar" }, "netdata": { - "warnings": "Warnings", - "criticals": "Criticals" + "warnings": "Uyarılar", + "criticals": "Kritik" }, "plantit": { - "events": "Events", + "events": "Etkinlikler", "plants": "Plants", "photos": "Fotoğraflar", - "species": "Species" + "species": "Türler" }, "gitea": { - "notifications": "Notifications", + "notifications": "Bildirimler", "issues": "Sorunlar", - "pulls": "Pull Requests" + "pulls": "Değişiklik İstekleri" }, "stash": { - "scenes": "Scenes", - "scenesPlayed": "Scenes Played", - "playCount": "Total Plays", - "playDuration": "Time Watched", - "sceneSize": "Scenes Size", - "sceneDuration": "Scenes Duration", - "images": "Images", - "imageSize": "Images Size", - "galleries": "Galleries", + "scenes": "Sahneler", + "scenesPlayed": "Oynanan Sahneler", + "playCount": "Toplam Oynatma", + "playDuration": "İzlenen Süre", + "sceneSize": "Sahne Boyutu", + "sceneDuration": "Sahne Süresi", + "images": "Görseller", + "imageSize": "Görsel Boyutu", + "galleries": "Galeriler", "performers": "Performers", - "studios": "Studios", + "studios": "Stüdyolar", "movies": "Filmler", - "tags": "Tags", + "tags": "Etiketler", "oCount": "O Count" }, "tandoor": { "users": "Kullanıcılar", - "recipes": "Recipes", - "keywords": "Keywords" + "recipes": "Tarifler", + "keywords": "Anahtar Sözcükler" + }, + "homebox": { + "items": "Ögeler", + "totalWithWarranty": "Garantili", + "locations": "Konum", + "labels": "Etiketler", + "users": "Kullanıcılar", + "totalValue": "Toplam Değer" } } diff --git a/public/locales/uk/common.json b/public/locales/uk/common.json index 0e62bc3ff..1a69825c6 100644 --- a/public/locales/uk/common.json +++ b/public/locales/uk/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Офлайн", + "offline_alt": "Офлайн", "online": "Онлайн", "total": "Усього", "unknown": "Невідомий" @@ -863,5 +864,13 @@ "users": "Користувачі", "recipes": "Recipes", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "Користувачі", + "totalValue": "Total Value" } } diff --git a/public/locales/vi/common.json b/public/locales/vi/common.json index 11df7eb5f..23827ddc8 100644 --- a/public/locales/vi/common.json +++ b/public/locales/vi/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "Ngoại tuyến", + "offline_alt": "Ngoại tuyến", "online": "Online", "total": "Tổng", "unknown": "Unknown" @@ -863,5 +864,13 @@ "users": "Users", "recipes": "Recipes", "keywords": "Keywords" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "Users", + "totalValue": "Total Value" } } diff --git a/public/locales/yue/common.json b/public/locales/yue/common.json index 2a4f6b0b2..3b32c0819 100644 --- a/public/locales/yue/common.json +++ b/public/locales/yue/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "離線", + "offline_alt": "離線", "online": "在線", "total": "全部", "unknown": "未知" @@ -862,6 +863,14 @@ "tandoor": { "users": "使用者", "recipes": "食譜", - "keywords": "Keywords" + "keywords": "關鍵字" + }, + "homebox": { + "items": "項目", + "totalWithWarranty": "With Warranty", + "locations": "位置", + "labels": "標籤", + "users": "使用者", + "totalValue": "總共" } } diff --git a/public/locales/zh-Hans/common.json b/public/locales/zh-Hans/common.json index 9919d6491..3957ccc87 100644 --- a/public/locales/zh-Hans/common.json +++ b/public/locales/zh-Hans/common.json @@ -109,6 +109,7 @@ }, "esphome": { "offline": "离线", + "offline_alt": "离线", "online": "在线", "total": "总计", "unknown": "未知" @@ -141,13 +142,13 @@ "connectionStatusDisconnected": "未连接", "connectionStatusConnected": "已连接", "uptime": "运行时间", - "maxDown": "", + "maxDown": "最大下载速度", "maxUp": "", "down": "离线", "up": "在线", - "received": "已接收", + "received": "最大上传数", "sent": "已发送", - "externalIPAddress": "Ext. IP" + "externalIPAddress": "外部IP" }, "caddy": { "upstreams": "上行", @@ -543,8 +544,8 @@ "hdhomerun": { "channels": "频道", "hd": "HD", - "tunerCount": "Tuners", - "channelNumber": "Channel", + "tunerCount": "电台数", + "channelNumber": "频道数", "channelNetwork": "网络", "signalStrength": "强度", "signalQuality": "质量", @@ -801,7 +802,7 @@ "up": "在线", "down": "离线", "bytesTx": "已传输", - "bytesRx": "已接收" + "bytesRx": "最大上传数" }, "uptimerobot": { "status": "状态", @@ -833,28 +834,28 @@ "criticals": "严重" }, "plantit": { - "events": "Events", - "plants": "Plants", + "events": "事件", + "plants": "植物", "photos": "照片", - "species": "Species" + "species": "物种" }, "gitea": { - "notifications": "Notifications", + "notifications": "通知", "issues": "出版", - "pulls": "Pull Requests" + "pulls": "PR" }, "stash": { - "scenes": "Scenes", - "scenesPlayed": "Scenes Played", - "playCount": "Total Plays", - "playDuration": "Time Watched", - "sceneSize": "Scenes Size", - "sceneDuration": "Scenes Duration", - "images": "Images", - "imageSize": "Images Size", - "galleries": "Galleries", - "performers": "Performers", - "studios": "Studios", + "scenes": "场景", + "scenesPlayed": "已播放场景", + "playCount": "播放总数", + "playDuration": "播放时间", + "sceneSize": "场景大小", + "sceneDuration": "场景时长", + "images": "图片", + "imageSize": "图像大小", + "galleries": "图库", + "performers": "演员", + "studios": "工作室", "movies": "电影", "tags": "标签", "oCount": "O Count" @@ -862,6 +863,14 @@ "tandoor": { "users": "用户数", "recipes": "食谱", - "keywords": "Keywords" + "keywords": "关键词" + }, + "homebox": { + "items": "Items", + "totalWithWarranty": "With Warranty", + "locations": "Locations", + "labels": "Labels", + "users": "用户数", + "totalValue": "Total Value" } } diff --git a/public/locales/zh-Hant/common.json b/public/locales/zh-Hant/common.json index a97ac9ee9..2ee4e8311 100644 --- a/public/locales/zh-Hant/common.json +++ b/public/locales/zh-Hant/common.json @@ -50,7 +50,7 @@ "uptime": "運作時間" }, "unifi": { - "users": "使用者", + "users": "用戶", "uptime": "運行時間", "days": "天", "wan": "WAN", @@ -109,6 +109,7 @@ }, "esphome": { "offline": "離線", + "offline_alt": "離線", "online": "在線", "total": "全部", "unknown": "未知" @@ -368,7 +369,7 @@ "transferRate": "速率" }, "mastodon": { - "user_count": "使用者", + "user_count": "用戶", "status_count": "文章", "domain_count": "網域" }, @@ -389,7 +390,7 @@ "unread": "未讀" }, "authentik": { - "users": "使用者", + "users": "用戶", "loginsLast24H": "登入 (過去 24 小時)", "failedLoginsLast24H": "登入失敗 (過去 24 小時)" }, @@ -629,7 +630,7 @@ "memory_usage": "記憶體" }, "immich": { - "users": "使用者", + "users": "用戶", "photos": "照片", "videos": "影片", "storage": "儲存空間" @@ -783,7 +784,7 @@ }, "mealie": { "recipes": "食譜", - "users": "使用者", + "users": "用戶", "categories": "類別", "tags": "標籤" }, @@ -860,8 +861,16 @@ "oCount": "O Count" }, "tandoor": { - "users": "使用者", + "users": "用戶", "recipes": "食譜", - "keywords": "Keywords" + "keywords": "關鍵字" + }, + "homebox": { + "items": "項目", + "totalWithWarranty": "With Warranty", + "locations": "位置", + "labels": "標籤", + "users": "用戶", + "totalValue": "總共" } } diff --git a/src/components/tab.jsx b/src/components/tab.jsx index 699b19123..e0c2f46ed 100644 --- a/src/components/tab.jsx +++ b/src/components/tab.jsx @@ -3,13 +3,19 @@ import classNames from "classnames"; import { TabContext } from "utils/contexts/tab"; -export function slugify(tabName) { - return tabName !== undefined ? encodeURIComponent(tabName.toString().replace(/\s+/g, "-").toLowerCase()) : ""; +function slugify(tabName) { + return tabName.toString().replace(/\s+/g, "-").toLowerCase(); +} + +export function slugifyAndEncode(tabName) { + return tabName !== undefined ? encodeURIComponent(slugify(tabName)) : ""; } export default function Tab({ tab }) { const { activeTab, setActiveTab } = useContext(TabContext); + const matchesTab = decodeURI(activeTab) === slugify(tab); + return (
  • { - setActiveTab(slugify(tab)); - window.location.hash = `#${slugify(tab)}`; + setActiveTab(slugifyAndEncode(tab)); + window.location.hash = `#${slugifyAndEncode(tab)}`; }} > {tab} diff --git a/src/pages/api/widgets/glances.js b/src/pages/api/widgets/glances.js index 0d87a9ae0..199c133e3 100644 --- a/src/pages/api/widgets/glances.js +++ b/src/pages/api/widgets/glances.js @@ -13,7 +13,7 @@ async function retrieveFromGlancesAPI(privateWidgetOptions, endpoint) { throw new Error(errorMessage); } - const apiUrl = `${url}/api/3/${endpoint}`; + const apiUrl = `${url}/api/${privateWidgetOptions.version}/${endpoint}`; const headers = { "Accept-Encoding": "application/json", }; @@ -42,9 +42,10 @@ async function retrieveFromGlancesAPI(privateWidgetOptions, endpoint) { } export default async function handler(req, res) { - const { index, cputemp: includeCpuTemp, uptime: includeUptime, disk: includeDisks } = req.query; + const { index, cputemp: includeCpuTemp, uptime: includeUptime, disk: includeDisks, version } = req.query; const privateWidgetOptions = await getPrivateWidgetOptions("glances", index); + privateWidgetOptions.version = version ?? 3; try { const cpuData = await retrieveFromGlancesAPI(privateWidgetOptions, "cpu"); diff --git a/src/pages/index.jsx b/src/pages/index.jsx index 10b2f6d5a..5e1bd6e22 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -10,7 +10,7 @@ import { BiError } from "react-icons/bi"; import { serverSideTranslations } from "next-i18next/serverSideTranslations"; import { useRouter } from "next/router"; -import Tab, { slugify } from "components/tab"; +import Tab, { slugifyAndEncode } from "components/tab"; import ServicesGroup from "components/services/group"; import BookmarksGroup from "components/bookmarks/group"; import Widget from "components/widgets/widget"; @@ -258,13 +258,13 @@ function Home({ initialSettings }) { useEffect(() => { if (!activeTab) { - const initialTab = decodeURI(asPath.substring(asPath.indexOf("#") + 1)); - setActiveTab(initialTab === "/" ? slugify(tabs["0"]) : initialTab); + const initialTab = asPath.substring(asPath.indexOf("#") + 1); + setActiveTab(initialTab === "/" ? slugifyAndEncode(tabs["0"]) : initialTab); } }); const servicesAndBookmarksGroups = useMemo(() => { - const tabGroupFilter = (g) => g && [activeTab, ""].includes(slugify(settings.layout?.[g.name]?.tab)); + const tabGroupFilter = (g) => g && [activeTab, ""].includes(slugifyAndEncode(settings.layout?.[g.name]?.tab)); const undefinedGroupFilter = (g) => settings.layout?.[g.name] === undefined; const layoutGroups = Object.keys(settings.layout ?? {}) diff --git a/src/utils/config/service-helpers.js b/src/utils/config/service-helpers.js index c4ca2a65b..bee7db4e2 100644 --- a/src/utils/config/service-helpers.js +++ b/src/utils/config/service-helpers.js @@ -394,6 +394,7 @@ export function cleanServiceGroups(groups) { enableNowPlaying, // glances + version, chart, metric, pointsLimit, @@ -528,6 +529,7 @@ export function cleanServiceGroups(groups) { if (snapshotPath) cleanedService.widget.snapshotPath = snapshotPath; } if (type === "glances") { + if (version) cleanedService.widget.version = version; if (metric) cleanedService.widget.metric = metric; if (chart !== undefined) { cleanedService.widget.chart = chart; diff --git a/src/utils/proxy/http.js b/src/utils/proxy/http.js index ff34ce0d6..8a9ce380c 100644 --- a/src/utils/proxy/http.js +++ b/src/utils/proxy/http.js @@ -103,7 +103,7 @@ export async function httpProxy(url, params = {}) { try { const [status, contentType, data, responseHeaders] = await request; - return [status, contentType, data, responseHeaders]; + return [status, contentType, data, responseHeaders, params]; } catch (err) { logger.error( "Error calling %s//%s%s%s...", diff --git a/src/widgets/components.js b/src/widgets/components.js index f3d567bb7..8c85bd770 100644 --- a/src/widgets/components.js +++ b/src/widgets/components.js @@ -15,6 +15,7 @@ const components = { channelsdvrserver: dynamic(() => import("./channelsdvrserver/component")), cloudflared: dynamic(() => import("./cloudflared/component")), coinmarketcap: dynamic(() => import("./coinmarketcap/component")), + crowdsec: dynamic(() => import("./crowdsec/component")), iframe: dynamic(() => import("./iframe/component")), customapi: dynamic(() => import("./customapi/component")), deluge: dynamic(() => import("./deluge/component")), diff --git a/src/widgets/crowdsec/component.jsx b/src/widgets/crowdsec/component.jsx new file mode 100644 index 000000000..2e98cee9f --- /dev/null +++ b/src/widgets/crowdsec/component.jsx @@ -0,0 +1,34 @@ +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: alerts, error: alertsError } = useWidgetAPI(widget, "alerts"); + const { data: bans, error: bansError } = useWidgetAPI(widget, "bans"); + + if (alertsError || bansError) { + return ; + } + + if (!alerts && !bans) { + return ( + + + + + ); + } + + return ( + + + + + ); +} diff --git a/src/widgets/crowdsec/proxy.js b/src/widgets/crowdsec/proxy.js new file mode 100644 index 000000000..e78fbc5ef --- /dev/null +++ b/src/widgets/crowdsec/proxy.js @@ -0,0 +1,86 @@ +import cache from "memory-cache"; + +import { httpProxy } from "utils/proxy/http"; +import { formatApiCall } from "utils/proxy/api-helpers"; +import getServiceWidget from "utils/config/service-helpers"; +import createLogger from "utils/logger"; +import widgets from "widgets/widgets"; + +const proxyName = "crowdsecProxyHandler"; +const logger = createLogger(proxyName); +const sessionTokenCacheKey = `${proxyName}__sessionToken`; + +async function login(widget, service) { + const url = formatApiCall(widgets[widget.type].loginURL, widget); + const [status, , data] = await httpProxy(url, { + method: "POST", + headers: { + "Content-Type": "application/json", + "User-Agent": "Mozilla/5.0", // Crowdsec requires a user-agent + }, + body: JSON.stringify({ + machine_id: widget.username, + password: widget.password, + scenarios: [], + }), + }); + + const dataParsed = JSON.parse(data); + + if (!(status === 200) || !dataParsed.token) { + logger.error("Failed to login to Crowdsec API, status: %d", status); + cache.del(`${sessionTokenCacheKey}.${service}`); + } + cache.put(`${sessionTokenCacheKey}.${service}`, dataParsed.token, new Date(dataParsed.expire) - new Date()); +} + +export default async function crowdsecProxyHandler(req, res) { + const { group, service, endpoint } = req.query; + + if (!group || !service) { + logger.error("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 || !widgets[widget.type].api) { + logger.error("Invalid or missing widget for service '%s' in group '%s'", service, group); + return res.status(400).json({ error: "Invalid widget configuration" }); + } + + if (!cache.get(`${sessionTokenCacheKey}.${service}`)) { + await login(widget, service); + } + + const token = cache.get(`${sessionTokenCacheKey}.${service}`); + if (!token) { + return res.status(500).json({ error: "Failed to authenticate with Crowdsec" }); + } + + const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget })); + + try { + const params = { + method: "GET", + headers: { + "User-Agent": "Mozilla/5.0", // Crowdsec requires a user-agent + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }; + + logger.debug("Calling Crowdsec API endpoint: %s", endpoint); + + const [status, , data] = await httpProxy(url, params); + + if (status !== 200) { + logger.error("Error calling Crowdsec API: %d. Data: %s", status, data); + return res.status(status).json({ error: "Crowdsec API Error", data }); + } + + return res.status(status).send(data); + } catch (error) { + logger.error("Exception calling Crowdsec API: %s", error.message); + return res.status(500).json({ error: "Crowdsec API Error", message: error.message }); + } +} diff --git a/src/widgets/crowdsec/widget.js b/src/widgets/crowdsec/widget.js new file mode 100644 index 000000000..d29fa1f16 --- /dev/null +++ b/src/widgets/crowdsec/widget.js @@ -0,0 +1,18 @@ +import crowdsecProxyHandler from "./proxy"; + +const widget = { + api: "{url}/v1/{endpoint}", + loginURL: "{url}/v1/watchers/login", + proxyHandler: crowdsecProxyHandler, + + mappings: { + alerts: { + endpoint: "alerts", + }, + bans: { + endpoint: "alerts?decision_type=ban&origin=crowdsec&has_active_decision=1", + }, + }, +}; + +export default widget; diff --git a/src/widgets/glances/metrics/cpu.jsx b/src/widgets/glances/metrics/cpu.jsx index c36aba9d2..bd12dc29a 100644 --- a/src/widgets/glances/metrics/cpu.jsx +++ b/src/widgets/glances/metrics/cpu.jsx @@ -16,15 +16,16 @@ const defaultInterval = 1000; export default function Component({ service }) { const { t } = useTranslation(); const { widget } = service; - const { chart, refreshInterval = defaultInterval, pointsLimit = defaultPointsLimit } = widget; + const { chart, refreshInterval = defaultInterval, pointsLimit = defaultPointsLimit, version = 3 } = widget; const [dataPoints, setDataPoints] = useState(new Array(pointsLimit).fill({ value: 0 }, 0, pointsLimit)); const { data, error } = useWidgetAPI(service.widget, "cpu", { refreshInterval: Math.max(defaultInterval, refreshInterval), + version, }); - const { data: systemData, error: systemError } = useWidgetAPI(service.widget, "system"); + const { data: quicklookData, error: quicklookError } = useWidgetAPI(service.widget, "quicklook", { version }); useEffect(() => { if (data) { @@ -71,22 +72,15 @@ export default function Component({ service }) { /> )} - {!chart && systemData && !systemError && ( + {!chart && quicklookData && !quicklookError && ( -
    - {systemData.linux_distro && `${systemData.linux_distro} - `} - {systemData.os_version && systemData.os_version} -
    +
    {quicklookData.cpu_name && quicklookData.cpu_name}
    )} - {systemData && !systemError && ( + {quicklookData && !quicklookError && ( - {systemData.linux_distro && chart &&
    {systemData.linux_distro}
    } - - {systemData.os_version && chart &&
    {systemData.os_version}
    } - - {systemData.hostname &&
    {systemData.hostname}
    } + {quicklookData.cpu_name && chart &&
    {quicklookData.cpu_name}
    }
    )} diff --git a/src/widgets/glances/metrics/disk.jsx b/src/widgets/glances/metrics/disk.jsx index d5cac4770..662822efd 100644 --- a/src/widgets/glances/metrics/disk.jsx +++ b/src/widgets/glances/metrics/disk.jsx @@ -16,7 +16,7 @@ const defaultInterval = 1000; export default function Component({ service }) { const { t } = useTranslation(); const { widget } = service; - const { chart, refreshInterval = defaultInterval, pointsLimit = defaultPointsLimit } = widget; + const { chart, refreshInterval = defaultInterval, pointsLimit = defaultPointsLimit, version = 3 } = widget; const [, diskName] = widget.metric.split(":"); const [dataPoints, setDataPoints] = useState( @@ -26,6 +26,7 @@ export default function Component({ service }) { const { data, error } = useWidgetAPI(service.widget, "diskio", { refreshInterval: Math.max(defaultInterval, refreshInterval), + version, }); const calculateRates = (d) => diff --git a/src/widgets/glances/metrics/fs.jsx b/src/widgets/glances/metrics/fs.jsx index 16d8d153b..1a26c2ab0 100644 --- a/src/widgets/glances/metrics/fs.jsx +++ b/src/widgets/glances/metrics/fs.jsx @@ -11,12 +11,13 @@ const defaultInterval = 1000; export default function Component({ service }) { const { t } = useTranslation(); const { widget } = service; - const { chart, refreshInterval = defaultInterval } = widget; + const { chart, refreshInterval = defaultInterval, version = 3 } = widget; const [, fsName] = widget.metric.split("fs:"); const diskUnits = widget.diskUnits === "bbytes" ? "common.bbytes" : "common.bytes"; const { data, error } = useWidgetAPI(widget, "fs", { refreshInterval: Math.max(defaultInterval, refreshInterval), + version, }); if (error) { diff --git a/src/widgets/glances/metrics/gpu.jsx b/src/widgets/glances/metrics/gpu.jsx index c33c63968..cc8504fa7 100644 --- a/src/widgets/glances/metrics/gpu.jsx +++ b/src/widgets/glances/metrics/gpu.jsx @@ -16,13 +16,14 @@ const defaultInterval = 1000; export default function Component({ service }) { const { t } = useTranslation(); const { widget } = service; - const { chart, refreshInterval = defaultInterval, pointsLimit = defaultPointsLimit } = widget; + const { chart, refreshInterval = defaultInterval, pointsLimit = defaultPointsLimit, version = 3 } = widget; const [, gpuName] = widget.metric.split(":"); const [dataPoints, setDataPoints] = useState(new Array(pointsLimit).fill({ a: 0, b: 0 }, 0, pointsLimit)); const { data, error } = useWidgetAPI(widget, "gpu", { refreshInterval: Math.max(defaultInterval, refreshInterval), + version, }); useEffect(() => { diff --git a/src/widgets/glances/metrics/info.jsx b/src/widgets/glances/metrics/info.jsx index e7555bced..a90cbdb52 100644 --- a/src/widgets/glances/metrics/info.jsx +++ b/src/widgets/glances/metrics/info.jsx @@ -74,14 +74,16 @@ const defaultSystemInterval = 30000; // This data (OS, hostname, distribution) i export default function Component({ service }) { const { widget } = service; - const { chart, refreshInterval = defaultInterval } = widget; + const { chart, refreshInterval = defaultInterval, version = 3 } = widget; const { data: quicklookData, errorL: quicklookError } = useWidgetAPI(service.widget, "quicklook", { refreshInterval, + version, }); const { data: systemData, errorL: systemError } = useWidgetAPI(service.widget, "system", { refreshInterval: defaultSystemInterval, + version, }); if (quicklookError) { @@ -122,7 +124,10 @@ export default function Component({ service }) { )} {!chart && quicklookData?.swap === 0 && ( -
    {quicklookData.cpu_name}
    +
    + {systemData && systemData.linux_distro && `${systemData.linux_distro} - `} + {systemData && systemData.os_version} +
    )}
    {!chart && }
    @@ -137,7 +142,7 @@ export default function Component({ service }) { )} {!chart && ( - + )} diff --git a/src/widgets/glances/metrics/memory.jsx b/src/widgets/glances/metrics/memory.jsx index d6cc5e6c9..87ec0f787 100644 --- a/src/widgets/glances/metrics/memory.jsx +++ b/src/widgets/glances/metrics/memory.jsx @@ -17,12 +17,13 @@ export default function Component({ service }) { const { t } = useTranslation(); const { widget } = service; const { chart } = widget; - const { refreshInterval = defaultInterval(chart), pointsLimit = defaultPointsLimit } = widget; + const { refreshInterval = defaultInterval(chart), pointsLimit = defaultPointsLimit, version = 3 } = widget; const [dataPoints, setDataPoints] = useState(new Array(pointsLimit).fill({ value: 0 }, 0, pointsLimit)); const { data, error } = useWidgetAPI(service.widget, "mem", { refreshInterval: Math.max(defaultInterval(chart), refreshInterval), + version, }); useEffect(() => { diff --git a/src/widgets/glances/metrics/net.jsx b/src/widgets/glances/metrics/net.jsx index 3bd92c229..a51c8388b 100644 --- a/src/widgets/glances/metrics/net.jsx +++ b/src/widgets/glances/metrics/net.jsx @@ -17,7 +17,10 @@ export default function Component({ service }) { const { t } = useTranslation(); const { widget } = service; const { chart, metric } = widget; - const { refreshInterval = defaultInterval(chart), pointsLimit = defaultPointsLimit } = widget; + const { refreshInterval = defaultInterval(chart), pointsLimit = defaultPointsLimit, version = 3 } = widget; + + const rxKey = version === 3 ? "rx" : "bytes_recv"; + const txKey = version === 3 ? "tx" : "bytes_sent"; const [, interfaceName] = metric.split(":"); @@ -25,6 +28,7 @@ export default function Component({ service }) { const { data, error } = useWidgetAPI(widget, "network", { refreshInterval: Math.max(defaultInterval(chart), refreshInterval), + version, }); useEffect(() => { @@ -36,8 +40,8 @@ export default function Component({ service }) { const newDataPoints = [ ...prevDataPoints, { - a: (interfaceData.rx * 8) / interfaceData.time_since_update, - b: (interfaceData.tx * 8) / interfaceData.time_since_update, + a: (interfaceData[rxKey] * 8) / interfaceData.time_since_update, + b: (interfaceData[txKey] * 8) / interfaceData.time_since_update, }, ]; if (newDataPoints.length > pointsLimit) { @@ -97,7 +101,7 @@ export default function Component({ service }) {
    {t("common.bitrate", { - value: (interfaceData.rx * 8) / interfaceData.time_since_update, + value: (interfaceData[rxKey] * 8) / interfaceData.time_since_update, maximumFractionDigits: 0, })}{" "} {t("docker.rx")} @@ -115,7 +119,7 @@ export default function Component({ service }) {
    {t("common.bitrate", { - value: (interfaceData.tx * 8) / interfaceData.time_since_update, + value: (interfaceData[txKey] * 8) / interfaceData.time_since_update, maximumFractionDigits: 0, })}{" "} {t("docker.tx")} diff --git a/src/widgets/glances/metrics/process.jsx b/src/widgets/glances/metrics/process.jsx index 0b2e8e4bd..24b447cb9 100644 --- a/src/widgets/glances/metrics/process.jsx +++ b/src/widgets/glances/metrics/process.jsx @@ -22,10 +22,13 @@ const defaultInterval = 1000; export default function Component({ service }) { const { t } = useTranslation(); const { widget } = service; - const { chart, refreshInterval = defaultInterval } = widget; + const { chart, refreshInterval = defaultInterval, version = 3 } = widget; + + const memoryInfoKey = version === 3 ? 0 : "data"; const { data, error } = useWidgetAPI(service.widget, "processlist", { refreshInterval: Math.max(defaultInterval, refreshInterval), + version, }); if (error) { @@ -66,7 +69,7 @@ export default function Component({ service }) {
    {item.cpu_percent.toFixed(1)}%
    {t("common.bytes", { - value: item.memory_info[0], + value: item.memory_info[memoryInfoKey], maximumFractionDigits: 0, })}
    diff --git a/src/widgets/glances/metrics/sensor.jsx b/src/widgets/glances/metrics/sensor.jsx index 60ea07c8a..9dc28bb1e 100644 --- a/src/widgets/glances/metrics/sensor.jsx +++ b/src/widgets/glances/metrics/sensor.jsx @@ -16,13 +16,14 @@ const defaultInterval = 1000; export default function Component({ service }) { const { t } = useTranslation(); const { widget } = service; - const { chart, refreshInterval = defaultInterval, pointsLimit = defaultPointsLimit } = widget; + const { chart, refreshInterval = defaultInterval, pointsLimit = defaultPointsLimit, version = 3 } = widget; const [, sensorName] = widget.metric.split(":"); const [dataPoints, setDataPoints] = useState(new Array(pointsLimit).fill({ value: 0 }, 0, pointsLimit)); const { data, error } = useWidgetAPI(service.widget, "sensors", { refreshInterval: Math.max(defaultInterval, refreshInterval), + version, }); useEffect(() => { diff --git a/src/widgets/glances/widget.js b/src/widgets/glances/widget.js index 3da1c6d12..a824e4c1b 100644 --- a/src/widgets/glances/widget.js +++ b/src/widgets/glances/widget.js @@ -1,7 +1,7 @@ import credentialedProxyHandler from "utils/proxy/handlers/credentialed"; const widget = { - api: "{url}/api/3/{endpoint}", + api: "{url}/api/{version}/{endpoint}", proxyHandler: credentialedProxyHandler, }; diff --git a/src/widgets/jackett/proxy.js b/src/widgets/jackett/proxy.js new file mode 100644 index 000000000..5292695fc --- /dev/null +++ b/src/widgets/jackett/proxy.js @@ -0,0 +1,68 @@ +import { httpProxy } from "utils/proxy/http"; +import { formatApiCall } from "utils/proxy/api-helpers"; +import getServiceWidget from "utils/config/service-helpers"; +import createLogger from "utils/logger"; +import widgets from "widgets/widgets"; + +const logger = createLogger("jackettProxyHandler"); + +async function fetchJackettCookie(widget, loginURL) { + const url = new URL(formatApiCall(loginURL, widget)); + const loginData = `password=${encodeURIComponent(widget.password)}`; + const [status, , , , params] = await httpProxy(url, { + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + body: loginData, + }); + + if (!(status === 200) || !params?.headers?.Cookie) { + logger.error("Failed to fetch Jackett cookie, status: %d", status); + return null; + } + return params.headers.Cookie; +} + +export default async function jackettProxyHandler(req, res) { + const { group, service, endpoint } = req.query; + + if (!group || !service) { + logger.error("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 || !widgets[widget.type].api) { + logger.error("Invalid or missing widget for service '%s' in group '%s'", service, group); + return res.status(400).json({ error: "Invalid widget configuration" }); + } + + if (widget.password) { + const jackettCookie = await fetchJackettCookie(widget, widgets[widget.type].loginURL); + if (!jackettCookie) { + return res.status(500).json({ error: "Failed to authenticate with Jackett" }); + } + // Add the cookie to the widget for use in subsequent requests + widget.headers = { ...widget.headers, Cookie: jackettCookie }; + } + + const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget })); + + try { + const [status, , data] = await httpProxy(url, { + method: "GET", + headers: widget.headers, + }); + + if (status !== 200) { + logger.error("Error calling Jackett API: %d. Data: %s", status, data); + return res.status(status).json({ error: "Failed to call Jackett API", data }); + } + + return res.status(status).send(data); + } catch (error) { + logger.error("Exception calling Jackett API: %s", error.message); + return res.status(500).json({ error: "Server error", message: error.message }); + } +} diff --git a/src/widgets/jackett/widget.js b/src/widgets/jackett/widget.js index 9d2a9b5cf..0af816e52 100644 --- a/src/widgets/jackett/widget.js +++ b/src/widgets/jackett/widget.js @@ -1,8 +1,9 @@ -import genericProxyHandler from "utils/proxy/handlers/generic"; +import jackettProxyHandler from "./proxy"; const widget = { api: "{url}/api/v2.0/{endpoint}?apikey={key}&configured=true", - proxyHandler: genericProxyHandler, + proxyHandler: jackettProxyHandler, + loginURL: "{url}/UI/Dashboard", mappings: { indexers: { diff --git a/src/widgets/widgets.js b/src/widgets/widgets.js index a9cae230f..6e02d9329 100644 --- a/src/widgets/widgets.js +++ b/src/widgets/widgets.js @@ -12,6 +12,7 @@ import changedetectionio from "./changedetectionio/widget"; import channelsdvrserver from "./channelsdvrserver/widget"; import cloudflared from "./cloudflared/widget"; import coinmarketcap from "./coinmarketcap/widget"; +import crowdsec from "./crowdsec/widget"; import customapi from "./customapi/widget"; import deluge from "./deluge/widget"; import diskstation from "./diskstation/widget"; @@ -125,6 +126,7 @@ const widgets = { channelsdvrserver, cloudflared, coinmarketcap, + crowdsec, customapi, deluge, diskstation,