diff --git a/.all-contributorsrc b/.all-contributorsrc index 1487861d088..f2d28077a7f 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1,10 +1,9 @@ { "projectName": "homepage", "projectOwner": "benphelps", - "repoType": "github", - "repoHost": "https://github.com", - "files": ["README.md"], - "imageSize": 50, - "contributorsSortAlphabetically": true, + "files": [ + "README.md" + ], + "imageSize": 100, "contributors": [] } diff --git a/README.md b/README.md index cdfa217e239..3dd0e7946a1 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ - Images built for AMD64 (x86_64), ARM64, ARMv7 and ARMv6 - Supports all Raspberry Pi's, most SBCs & Apple Silicon - 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/) - Service & Web Bookmarks - Docker Integration @@ -152,3 +152,9 @@ This is a [Next.js](https://nextjs.org/) application, see their doucmentation fo + + + + +[![All Contributors](https://img.shields.io/badge/all_contributors-13-orange.svg?style=flat-square)](#contributors) + diff --git a/public/locales/ar/common.json b/public/locales/ar/common.json index 3e40f83f0c7..6d565287e44 100644 --- a/public/locales/ar/common.json +++ b/public/locales/ar/common.json @@ -304,5 +304,20 @@ "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" } } diff --git a/public/locales/bg/common.json b/public/locales/bg/common.json index 98898d25454..0365e3292f6 100644 --- a/public/locales/bg/common.json +++ b/public/locales/bg/common.json @@ -304,5 +304,20 @@ "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" } } diff --git a/public/locales/ca/common.json b/public/locales/ca/common.json index 16e210ece49..fac4a04c247 100644 --- a/public/locales/ca/common.json +++ b/public/locales/ca/common.json @@ -304,5 +304,20 @@ "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" } } diff --git a/public/locales/cs/common.json b/public/locales/cs/common.json index 6a85b24aaef..7e9da1b5a25 100644 --- a/public/locales/cs/common.json +++ b/public/locales/cs/common.json @@ -1,308 +1,323 @@ { "tubearchivist": { - "videos": "Videos", - "channels": "Channels", - "playlists": "Playlists", - "downloads": "Queue" + "videos": "Videa", + "channels": "Kanály", + "playlists": "Playlisty", + "downloads": "Fronta" }, "truenas": { - "load": "System Load", - "uptime": "Uptime", - "alerts": "Alerts", + "load": "Vytížení systému", + "uptime": "Doba spuštění", + "alerts": "Upozornění", "time": "{{value, number(style: unit; unitDisplay: long;)}}" }, "widget": { - "missing_type": "Missing Widget Type: {{type}}", - "api_error": "API Error", + "missing_type": "Chybí typ widgetu: {{type}}", + "api_error": "Chyba API", "status": "Status" }, "weather": { - "current": "Current Location", - "allow": "Click to allow", - "updating": "Updating", - "wait": "Please wait" + "current": "Aktuální poloha", + "allow": "Klikni pro povolení", + "updating": "Probíhá aktualizace", + "wait": "Počkejte prosím" }, "search": { - "placeholder": "Search…" + "placeholder": "Hledat…" }, "resources": { "cpu": "CPU", - "total": "Total", - "free": "Free", - "used": "Used", - "load": "Load" + "total": "Celkem", + "free": "Volné", + "used": "Využité", + "load": "Vytížení" }, "unifi": { - "users": "Users", - "uptime": "System Uptime", - "days": "Days", + "users": "Uživatelé", + "uptime": "Čas od startu systému", + "days": "Dnů", "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" + "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": "MEM", + "mem": "RAM", "cpu": "CPU", "offline": "Offline" }, "emby": { - "playing": "Playing", - "transcoding": "Transcoding", + "playing": "Přehrává", + "transcoding": "Transkódování", "bitrate": "Bitrate", - "no_active": "No Active Streams" + "no_active": "Žádný aktivní stream" }, "changedetectionio": { - "totalObserved": "Total Observed", - "diffsDetected": "Diffs Detected" + "totalObserved": "Celkem zjištěno", + "diffsDetected": "Rozdíly detekovány" }, "tautulli": { - "playing": "Playing", - "transcoding": "Transcoding", + "playing": "Přehrává", + "transcoding": "Transkódování", "bitrate": "Bitrate", - "no_active": "No Active Streams" + "no_active": "Žádný aktivní stream" }, "nzbget": { - "rate": "Rate", - "remaining": "Remaining", - "downloaded": "Downloaded" + "rate": "Rychlost", + "remaining": "Zbývá", + "downloaded": "Staženo" }, "plex": { - "streams": "Active Streams", - "movies": "Movies", - "tv": "TV Shows" + "streams": "Aktivní streamy", + "movies": "Filmy", + "tv": "Seriály" }, "sabnzbd": { - "rate": "Rate", - "queue": "Queue", - "timeleft": "Time Left" + "rate": "Rychlost", + "queue": "Fronta", + "timeleft": "Zbývající čas" }, "rutorrent": { - "active": "Active", - "upload": "Upload", - "download": "Download" + "active": "Aktivní", + "upload": "Nahrávání", + "download": "Stahování" }, "transmission": { - "download": "Download", - "upload": "Upload", - "leech": "Leech", - "seed": "Seed" + "download": "Stahování", + "upload": "Nahrávání", + "leech": "Leecher", + "seed": "Seeder" }, "qbittorrent": { - "download": "Download", - "upload": "Upload", - "leech": "Leech", - "seed": "Seed" + "download": "Stahování", + "upload": "Nahrávání", + "leech": "Leecher", + "seed": "Seeder" }, "sonarr": { - "wanted": "Wanted", - "queued": "Queued", - "series": "Series" + "wanted": "Hledaný", + "queued": "Ve frontě", + "series": "Seriály" }, "radarr": { - "wanted": "Wanted", - "missing": "Missing", - "queued": "Queued", - "movies": "Movies" + "wanted": "Hledaný", + "missing": "Chybějící", + "queued": "Ve frontě", + "movies": "Filmy" }, "lidarr": { - "wanted": "Wanted", - "queued": "Queued", - "albums": "Albums" + "wanted": "Hledaný", + "queued": "Ve frontě", + "albums": "Alba" }, "readarr": { - "wanted": "Wanted", - "queued": "Queued", - "books": "Books" + "wanted": "Hledaný", + "queued": "Ve frontě", + "books": "Knihy" }, "bazarr": { - "missingEpisodes": "Missing Episodes", - "missingMovies": "Missing Movies" + "missingEpisodes": "Chybějící epizody", + "missingMovies": "Chybějící filmy" }, "ombi": { - "pending": "Pending", - "approved": "Approved", - "available": "Available" + "pending": "Čeká", + "approved": "Schváleno", + "available": "Dostupný" }, "jellyseerr": { - "pending": "Pending", - "approved": "Approved", - "available": "Available" + "pending": "Čeká", + "approved": "Schváleno", + "available": "Dostupný" }, "overseerr": { - "pending": "Pending", - "approved": "Approved", - "available": "Available" + "pending": "Čeká", + "approved": "Schváleno", + "available": "Dostupný" }, "pihole": { - "queries": "Queries", - "blocked": "Blocked", - "gravity": "Gravity" + "queries": "Dotazy", + "blocked": "Blokováno", + "gravity": "Gravitace" }, "adguard": { - "queries": "Queries", - "blocked": "Blocked", - "filtered": "Filtered", - "latency": "Latency" + "queries": "Dotazy", + "blocked": "Blokováno", + "filtered": "Filtrováno", + "latency": "Odezva" }, "speedtest": { - "upload": "Upload", - "download": "Download", + "upload": "Nahrávání", + "download": "Stahování", "ping": "Ping" }, "portainer": { - "running": "Running", - "stopped": "Stopped", - "total": "Total" + "running": "Běží", + "stopped": "Zastaveno", + "total": "Celkově" }, "traefik": { - "routers": "Routers", - "services": "Services", - "middleware": "Middleware" + "routers": "Routery", + "services": "Služby", + "middleware": "Prostředník" }, "npm": { - "enabled": "Enabled", - "disabled": "Disabled", - "total": "Total" + "enabled": "Povoleno", + "disabled": "Zakázáno", + "total": "Celkově" }, "coinmarketcap": { - "configure": "Configure one or more crypto currencies to track", - "1hour": "1 Hour", - "1day": "1 Day", - "7days": "7 Days", - "30days": "30 Days" + "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": "Mainly Clear", - "2-day": "Partly Cloudy", - "0-day": "Sunny", - "0-night": "Clear", - "1-day": "Mainly Sunny", - "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", - "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", - "51-night": "Light Drizzle", - "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", - "73-night": "Snow", - "75-day": "Heavy Snow", - "75-night": "Heavy Snow", - "77-day": "Snow Grains", - "71-night": "Light Snow", - "73-day": "Snow", - "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" + "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": "Applications", - "clients": "Clients", - "messages": "Messages" + "apps": "Aplikace", + "clients": "Klienti", + "messages": "Zprávy" }, "prowlarr": { - "enableIndexers": "Indexers", - "numberOfGrabs": "Grabs", - "numberOfQueries": "Queries", - "numberOfFailGrabs": "Fail Grabs", - "numberOfFailQueries": "Fail Queries" + "enableIndexers": "Indexery", + "numberOfGrabs": "Uchopení", + "numberOfQueries": "Dotazy", + "numberOfFailGrabs": "Neúspěšné uchopení", + "numberOfFailQueries": "Neúspěšné dotazy" }, "jackett": { - "configured": "Configured", - "errored": "Errored" + "configured": "Konfigurováno", + "errored": "Chybné" }, "strelaysrv": { - "numActiveSessions": "Sessions", - "numConnections": "Connections", - "dataRelayed": "Relayed", - "transferRate": "Rate" + "numActiveSessions": "Sezení", + "numConnections": "Připojení", + "dataRelayed": "Přenášení", + "transferRate": "Tempo" }, "mastodon": { - "user_count": "Users", - "status_count": "Posts", - "domain_count": "Domains" + "user_count": "Uživatelé", + "status_count": "Příspěvky", + "domain_count": "Domény" }, "authentik": { - "users": "Users", - "loginsLast24H": "Logins (24h)", - "failedLoginsLast24H": "Failed Logins (24h)" + "users": "Uživatelé", + "loginsLast24H": "Příhlášení (24h)", + "failedLoginsLast24H": "Neúspěšná přihlášení (24h)" }, "proxmox": { - "mem": "MEM", + "mem": "RAM", "cpu": "CPU", "lxc": "LXC", - "vms": "VMs" + "vms": "Virtuální Stroje" }, "glances": { "cpu": "CPU", - "mem": "MEM", - "wait": "Please wait" + "mem": "RAM", + "wait": "Prosím počkejte" }, "quicklaunch": { - "bookmark": "Bookmark", - "service": "Service" + "bookmark": "Záložka", + "service": "Služba" }, "homebridge": { - "update_available": "Update Available", - "up_to_date": "Up to Date", - "available_update": "System", - "updates": "Updates", - "child_bridges": "Child Bridges", + "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": "Scanned", - "containers_updated": "Updated", - "containers_failed": "Failed" + "containers_scanned": "Naskenováno", + "containers_updated": "Aktualizováno", + "containers_failed": "Chyba" }, "autobrr": { - "approvedPushes": "Approved", - "rejectedPushes": "Rejected", - "filters": "Filters", - "indexers": "Indexers" + "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" } } diff --git a/public/locales/da/common.json b/public/locales/da/common.json new file mode 100644 index 00000000000..99db4725d67 --- /dev/null +++ b/public/locales/da/common.json @@ -0,0 +1,323 @@ +{ + "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" + }, + "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" + }, + "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" + }, + "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" + } +} diff --git a/public/locales/de/common.json b/public/locales/de/common.json index 315ec0e4f67..f8c59567ca9 100644 --- a/public/locales/de/common.json +++ b/public/locales/de/common.json @@ -47,7 +47,7 @@ "wanted": "Gesucht", "queued": "In Warteschlange", "movies": "Filme", - "missing": "Missing" + "missing": "Fehlt" }, "readarr": { "wanted": "Gesucht", @@ -194,9 +194,9 @@ "wait": "Bitte warten", "lan": "LAN", "wlan": "WLAN", - "devices": "Devices", - "lan_devices": "LAN Devices", - "wlan_devices": "WLAN Devices" + "devices": "Geräte", + "lan_devices": "LAN-Geräte", + "wlan_devices": "WLAN Geräte" }, "plex": { "streams": "Aktive Streams", @@ -204,105 +204,120 @@ "tv": "TV Sendungen" }, "glances": { - "cpu": "CPU", + "cpu": "Prozessor", "mem": "RAM", "wait": "Bitte warten" }, "changedetectionio": { - "totalObserved": "Total Observed", - "diffsDetected": "Diffs Detected" + "totalObserved": "Gesamt beobachtet", + "diffsDetected": "Erkannte Differenzen" }, "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", - "57-day": "Freezing Drizzle", - "61-day": "Light Rain", - "65-night": "Heavy Rain", - "66-day": "Freezing Rain", - "66-night": "Freezing Rain", - "3-night": "Cloudy", - "45-day": "Foggy", - "45-night": "Foggy", - "48-day": "Foggy", - "48-night": "Foggy", - "51-day": "Light Drizzle", - "51-night": "Light Drizzle", - "55-day": "Heavy Drizzle", - "53-day": "Drizzle", - "53-night": "Drizzle", - "55-night": "Heavy Drizzle", - "56-day": "Light Freezing Drizzle", - "56-night": "Light Freezing Drizzle", - "57-night": "Freezing Drizzle", - "61-night": "Light Rain", - "63-day": "Rain", - "63-night": "Rain", - "65-day": "Heavy 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" + "0-day": "Sonnig", + "0-night": "Klar", + "1-day": "Überwiegend sonnig", + "1-night": "Überwiegend klar", + "2-day": "Teilweise bewölkt", + "2-night": "Teilweise bewölkt", + "3-day": "bewölkt", + "57-day": "Gefrierender Nieselregen", + "61-day": "Leichter Regen", + "65-night": "Starker Regen", + "66-day": "Gefrierender Regen", + "66-night": "Gefrierender Regen", + "3-night": "Bewölkt", + "45-day": "Neblig", + "45-night": "Neblig", + "48-day": "Neblig", + "48-night": "Neblig", + "51-day": "Leichter Nieselregen", + "51-night": "Leichter Nieselregen", + "55-day": "Starker Nieselregen", + "53-day": "Nieselregen", + "53-night": "Nieselregen", + "55-night": "Starker Nieselregen", + "56-day": "Leichter gefrierender Nieselregen", + "56-night": "Leichter eisiger Nieselregen", + "57-night": "Gefrierender Nieselregen", + "61-night": "Leichter Regen", + "63-day": "Regen", + "63-night": "Regen", + "65-day": "Starker Regen", + "67-day": "Gefrierender Regen", + "67-night": "Gefrierender Regen", + "71-day": "Leichter Schneefall", + "71-night": "Leichter Schnee", + "73-day": "Schnee", + "73-night": "Schnee", + "75-day": "Schwerer Schnee", + "75-night": "Schwerer Schnee", + "77-day": "Schneegriesel", + "77-night": "Schneegriesel", + "80-day": "Leichter Schauer", + "80-night": "Leichter Schauer", + "81-day": "Schauer", + "81-night": "Schauer", + "82-day": "Starke Regenschauer", + "82-night": "Starke Regenschauer", + "85-day": "Schneeschauer", + "85-night": "Schneeregen", + "86-day": "Schneeregen", + "86-night": "Schneeregen", + "95-day": "Gewitter", + "95-night": "Gewitter", + "96-day": "Gewitter mit Hagel", + "96-night": "Gewitter mit Hagel", + "99-day": "Gewitter mit Hagel", + "99-night": "Gewitter mit Hagel" }, "quicklaunch": { - "bookmark": "Bookmark", - "service": "Service" + "bookmark": "Lesezeichen", + "service": "Dienst" }, "homebridge": { "available_update": "System", - "updates": "Updates", - "update_available": "Update Available", - "up_to_date": "Up to Date", + "updates": "Aktualisierungen", + "update_available": "Aktualisierung verfügbar", + "up_to_date": "Aktuell", "child_bridges": "Child Bridges", "child_bridges_status": "{{ok}}/{{total}}" }, "autobrr": { - "approvedPushes": "Approved", - "rejectedPushes": "Rejected", - "filters": "Filters", - "indexers": "Indexers" + "approvedPushes": "Genehmigt", + "rejectedPushes": "Abgelehnt", + "filters": "Filter", + "indexers": "Indexer" }, "watchtower": { - "containers_scanned": "Scanned", - "containers_updated": "Updated", - "containers_failed": "Failed" + "containers_scanned": "Überprüft", + "containers_updated": "Aktualisiert", + "containers_failed": "Fehlgeschlagen" }, "tubearchivist": { - "downloads": "Queue", + "downloads": "Warteschlange", "videos": "Videos", - "channels": "Channels", - "playlists": "Playlists" + "channels": "Kanäle", + "playlists": "Wiedergabelisten" }, "truenas": { - "load": "System Load", - "uptime": "Uptime", - "alerts": "Alerts", + "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" } } diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 216cc83ded5..95c60cc0b89 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -168,6 +168,10 @@ "services": "Services", "middleware": "Middleware" }, + "navidrome": { + "nothing_streaming": "No Active Streams", + "please_wait": "Please Wait" + }, "npm": { "enabled": "Enabled", "disabled": "Disabled", @@ -319,5 +323,16 @@ "hdhomerun": { "channels": "Channels", "hd": "HD" + }, + "pyload": { + "speed": "Speed", + "active": "Active", + "queue": "Queue", + "total": "Total" + }, + "gluetun": { + "public_ip": "Public IP", + "region": "Region", + "country": "Country" } } diff --git a/public/locales/es/common.json b/public/locales/es/common.json index 95d5d3a49b1..4e98e30e64c 100644 --- a/public/locales/es/common.json +++ b/public/locales/es/common.json @@ -82,7 +82,7 @@ "traefik": { "routers": "Enrutadores", "services": "Servicios", - "middleware": "Middleware" + "middleware": "Software intermedio" }, "npm": { "enabled": "Activado", @@ -300,9 +300,24 @@ "playlists": "Listas de reproducción" }, "truenas": { - "load": "System Load", - "uptime": "Uptime", - "alerts": "Alerts", + "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": "Public IP", + "region": "Region", + "country": "Country" } } diff --git a/public/locales/fi/common.json b/public/locales/fi/common.json index 3e8c69bf8dd..07b480f0266 100644 --- a/public/locales/fi/common.json +++ b/public/locales/fi/common.json @@ -304,5 +304,20 @@ "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" } } diff --git a/public/locales/fr/common.json b/public/locales/fr/common.json index 3e0ffccbef2..b9b61611a38 100644 --- a/public/locales/fr/common.json +++ b/public/locales/fr/common.json @@ -304,5 +304,20 @@ "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": "Public IP", + "region": "Region", + "country": "Country" } } diff --git a/public/locales/he/common.json b/public/locales/he/common.json index fe7fd3aef47..296bfc4eb1b 100644 --- a/public/locales/he/common.json +++ b/public/locales/he/common.json @@ -304,5 +304,20 @@ "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" } } diff --git a/public/locales/hi/common.json b/public/locales/hi/common.json new file mode 100644 index 00000000000..d3075aba7eb --- /dev/null +++ b/public/locales/hi/common.json @@ -0,0 +1,323 @@ +{ + "widget": { + "missing_type": "Missing Widget Type: {{type}}", + "api_error": "API Error", + "status": "Status" + }, + "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" + }, + "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" + }, + "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" + } +} diff --git a/public/locales/hr/common.json b/public/locales/hr/common.json index 083faebd4c0..12c972625ee 100644 --- a/public/locales/hr/common.json +++ b/public/locales/hr/common.json @@ -189,8 +189,8 @@ "wan": "WAN", "lan_users": "LAN korisnici", "wlan_users": "WLAN korisnici", - "up": "Upaljen", - "down": "Ugašen", + "up": "SLANJE", + "down": "PRIMANJE", "wait": "Pričekaj", "lan": "LAN", "wlan": "WLAN", @@ -265,10 +265,10 @@ "86-night": "Snježni pljuskovi", "95-day": "Oluja", "95-night": "Oluja", - "96-day": "Oluja s grmljavinom", - "96-night": "Oluja s grmljavinom", - "99-day": "Oluja s grmljavinom", - "99-night": "Oluja s grmljavinom" + "96-day": "Oluja s tučom", + "96-night": "Oluja s tučom", + "99-day": "Oluja s tučom", + "99-night": "Oluja s tučom" }, "quicklaunch": { "bookmark": "Straničnik", @@ -304,5 +304,20 @@ "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": "Public IP", + "region": "Region", + "country": "Country" } } diff --git a/public/locales/hu/common.json b/public/locales/hu/common.json index 3af2cd6b336..f00dc97500e 100644 --- a/public/locales/hu/common.json +++ b/public/locales/hu/common.json @@ -304,5 +304,20 @@ "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" } } diff --git a/public/locales/it/common.json b/public/locales/it/common.json index 52306bac2d9..9478d420d6a 100644 --- a/public/locales/it/common.json +++ b/public/locales/it/common.json @@ -123,11 +123,11 @@ "messages": "Messaggi" }, "prowlarr": { - "enableIndexers": "Indexers", + "enableIndexers": "Indicizzatori", "numberOfGrabs": "Grabs", "numberOfQueries": "Queries", - "numberOfFailGrabs": "Fail Grabs", - "numberOfFailQueries": "Fail Queries" + "numberOfFailGrabs": "Grabs Falliti", + "numberOfFailQueries": "Queries Fallite" }, "transmission": { "download": "Download", @@ -184,7 +184,7 @@ }, "unifi": { "users": "Utenti", - "uptime": "System Uptime", + "uptime": "Uptime di Sistema", "days": "Giorni", "wan": "WAN", "lan_users": "Utenti LAN", @@ -209,16 +209,16 @@ "wait": "Attendere prego" }, "changedetectionio": { - "totalObserved": "Total Observed", - "diffsDetected": "Diffs Detected" + "totalObserved": "Totale Osservato", + "diffsDetected": "Differenze Rilevate" }, "wmo": { - "65-day": "Heavy Rain", + "65-day": "Pioggia Intensa", "2-night": "Parzialmente Nuvoloso", "0-day": "Solleggiato", - "0-night": "Clear", - "1-day": "Mainly Sunny", - "1-night": "Mainly Clear", + "0-night": "Pulisci", + "1-day": "Principalmente Soleggiato", + "1-night": "Principalmente Sereno", "2-day": "Parzialmente Nuvoloso", "3-day": "Nuvoloso", "3-night": "Nuvoloso", @@ -232,37 +232,37 @@ "53-night": "Pioggerella", "55-day": "Pioggerella Pesante", "55-night": "Pioggerella Pesante", - "56-day": "Light Freezing Drizzle", - "56-night": "Light Freezing Drizzle", - "57-day": "Freezing Drizzle", - "57-night": "Freezing Drizzle", + "56-day": "Leggera Pioggia Gelata", + "56-night": "Leggera Pioggia Gelata", + "57-day": "Pioggerella Gelata", + "57-night": "Pioggerella Gelata", "61-day": "Pioggia Leggera", "61-night": "Pioggia Leggera", "63-day": "Pioggia", "63-night": "Pioggia", - "65-night": "Heavy Rain", + "65-night": "Pioggia Intensa", "66-day": "Grandine", "66-night": "Grandine", "67-day": "Grandine", "67-night": "Grandine", - "71-day": "Light Snow", - "71-night": "Light Snow", + "71-day": "Leggera Nevicata", + "71-night": "Leggera Nevicata", "73-day": "Neve", "73-night": "Neve", - "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", + "75-day": "Nevicata Intensa", + "75-night": "Nevicata Intensa", + "77-day": "Fiocchi di Neve", + "77-night": "Fiocchi di Neve", + "80-day": "Leggeri Rovesci", + "80-night": "Leggeri Rovesci", + "81-day": "Rovesci", + "81-night": "Rovesci", + "82-day": "Intensi Rovesci", + "82-night": "Intensi Rovesci", + "85-day": "Rovesci di Neve", + "85-night": "Rovesci di Neve", + "86-day": "Rovesci di Neve", + "86-night": "Rovesci di Neve", "95-day": "Temporale", "95-night": "Temporale", "96-day": "Temporale con grandine", @@ -271,38 +271,53 @@ "99-night": "Temporale con grandine" }, "quicklaunch": { - "bookmark": "Bookmark", + "bookmark": "Segnalibro", "service": "Servizio" }, "homebridge": { - "available_update": "System", - "updates": "Updates", - "update_available": "Update Available", - "up_to_date": "Up to Date", + "available_update": "Sistema", + "updates": "Aggiornamenti", + "update_available": "Aggiornamento Disponibile", + "up_to_date": "Aggiornato", "child_bridges": "Child Bridges", "child_bridges_status": "{{ok}}/{{total}}" }, "autobrr": { - "approvedPushes": "Approved", - "rejectedPushes": "Rejected", - "filters": "Filters", - "indexers": "Indexers" + "approvedPushes": "Approvato", + "rejectedPushes": "Rifiutato", + "filters": "Filtri", + "indexers": "Indicizzatori" }, "watchtower": { - "containers_scanned": "Scanned", - "containers_updated": "Updated", - "containers_failed": "Failed" + "containers_scanned": "Scansionato", + "containers_updated": "Aggiornato", + "containers_failed": "Fallito" }, "tubearchivist": { - "downloads": "Queue", - "videos": "Videos", - "channels": "Channels", + "downloads": "Coda", + "videos": "Video", + "channels": "Canali", "playlists": "Playlists" }, "truenas": { - "load": "System Load", + "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" } } diff --git a/public/locales/ms/common.json b/public/locales/ms/common.json new file mode 100644 index 00000000000..761d85e9169 --- /dev/null +++ b/public/locales/ms/common.json @@ -0,0 +1,323 @@ +{ + "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" + }, + "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" + }, + "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" + }, + "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": "Public IP", + "region": "Region", + "country": "Country" + } +} diff --git a/public/locales/nb-NO/common.json b/public/locales/nb-NO/common.json index 3b54e638dd8..0f7680f76ec 100644 --- a/public/locales/nb-NO/common.json +++ b/public/locales/nb-NO/common.json @@ -304,5 +304,20 @@ "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" } } diff --git a/public/locales/nl/common.json b/public/locales/nl/common.json index bd53b72b0f5..ae5cd06e46c 100644 --- a/public/locales/nl/common.json +++ b/public/locales/nl/common.json @@ -304,5 +304,20 @@ "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" } } diff --git a/public/locales/pl/common.json b/public/locales/pl/common.json index d29ba776210..41495b3e20f 100644 --- a/public/locales/pl/common.json +++ b/public/locales/pl/common.json @@ -304,5 +304,20 @@ "uptime": "Uptime", "alerts": "Alerts", "time": "{{value, number(style: unit; unitDisplay: long;)}}" + }, + "navidrome": { + "please_wait": "Please Wait", + "nothing_streaming": "No Active Streams" + }, + "pyload": { + "speed": "Speed", + "active": "Active", + "queue": "Queue", + "total": "Total" + }, + "gluetun": { + "public_ip": "Public IP", + "region": "Region", + "country": "Country" } } diff --git a/public/locales/pt-BR/common.json b/public/locales/pt-BR/common.json index 899606f6209..a73d6b4837b 100644 --- a/public/locales/pt-BR/common.json +++ b/public/locales/pt-BR/common.json @@ -209,8 +209,8 @@ "wait": "Please wait" }, "changedetectionio": { - "totalObserved": "Total Observed", - "diffsDetected": "Diffs Detected" + "totalObserved": "Observados", + "diffsDetected": "Mudanças" }, "wmo": { "1-night": "Mainly Clear", @@ -304,5 +304,20 @@ "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" } } diff --git a/public/locales/pt/common.json b/public/locales/pt/common.json index a802e1c00ab..5f22a5b85d4 100644 --- a/public/locales/pt/common.json +++ b/public/locales/pt/common.json @@ -315,5 +315,20 @@ "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" } } diff --git a/public/locales/ro/common.json b/public/locales/ro/common.json index 3927aa00d3d..a57ea01b01e 100644 --- a/public/locales/ro/common.json +++ b/public/locales/ro/common.json @@ -304,5 +304,20 @@ "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" } } diff --git a/public/locales/ru/common.json b/public/locales/ru/common.json index 13912bd5b1e..762b3e90435 100644 --- a/public/locales/ru/common.json +++ b/public/locales/ru/common.json @@ -304,5 +304,20 @@ "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" } } diff --git a/public/locales/sr/common.json b/public/locales/sr/common.json index 5eab219310b..8fe0a6e0f78 100644 --- a/public/locales/sr/common.json +++ b/public/locales/sr/common.json @@ -304,5 +304,20 @@ "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" } } diff --git a/public/locales/sv/common.json b/public/locales/sv/common.json index 83bce26986d..87f2061f01d 100644 --- a/public/locales/sv/common.json +++ b/public/locales/sv/common.json @@ -304,5 +304,20 @@ "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" } } diff --git a/public/locales/te/common.json b/public/locales/te/common.json index cbe1bce55e3..7ad2dacebd3 100644 --- a/public/locales/te/common.json +++ b/public/locales/te/common.json @@ -304,5 +304,20 @@ "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" } } diff --git a/public/locales/tr/common.json b/public/locales/tr/common.json index c145d4bffd0..f431239de75 100644 --- a/public/locales/tr/common.json +++ b/public/locales/tr/common.json @@ -213,96 +213,111 @@ "diffsDetected": "Farklar Algılandı" }, "wmo": { - "99-day": "Thunderstorm With Hail", - "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", - "95-night": "Thunderstorm", - "82-night": "Heavy Showers", - "85-day": "Snow Showers", - "85-night": "Snow Showers", - "86-day": "Snow Showers", - "86-night": "Snow Showers", - "95-day": "Thunderstorm", - "96-day": "Thunderstorm With Hail", - "96-night": "Thunderstorm With Hail", - "99-night": "Thunderstorm With Hail" + "99-day": "Dolu İle Gök Gürültülü Fırtına", + "0-day": "Güneşli", + "0-night": "Açık", + "1-day": "Çoğunlukla Güneşli", + "1-night": "Çoğunlukla Açık", + "2-day": "Parçalı Bulutlu", + "2-night": "Parçalı Bulutlu", + "3-day": "Bulutlu", + "3-night": "Bulutlu", + "45-day": "Sisli", + "45-night": "Sisli", + "48-day": "Sisli", + "48-night": "Sisli", + "51-day": "Az Çiseleyen Yağmur", + "51-night": "Az Çiseleyen Yağmur", + "53-day": "Çiseleyen Yağmur", + "53-night": "Çiseleyen Yağmur", + "55-day": "Çok Çiseleyen Yağmur", + "55-night": "Çok Çiseleyen Yağmur", + "56-day": "Soğuk Az Çiseleyen Yağmur", + "56-night": "Soğuk Az Çiseleyen Yağmur", + "57-day": "Soğuk Çiseleyen Yağmur", + "57-night": "Soğuk Çiseleyen Yağmur", + "61-day": "Hafif Yağmur", + "61-night": "Hafif Yağmur", + "63-day": "Yağmur", + "63-night": "Yağmur", + "65-day": "Çok Yağmur", + "65-night": "Çok Yağmur", + "66-day": "Dondurucu Yağmur", + "66-night": "Dondurucu Yağmur", + "67-day": "Dondurucu Yağmur", + "67-night": "Dondurucu Yağmur", + "71-day": "Hafif Kar", + "71-night": "Hafif Kar", + "73-day": "Kar", + "73-night": "Kar", + "75-day": "Çok Kar", + "75-night": "Çok Kar", + "77-day": "Kar Taneleri", + "77-night": "Kar Taneleri", + "80-day": "Hafif Sağanak", + "80-night": "Hafif Sağanak", + "81-day": "Sağanak", + "81-night": "Sağanak", + "82-day": "Yoğun Sağanak", + "95-night": "Gök Gürültülü Fırtına", + "82-night": "Yoğun Sağanak", + "85-day": "Karlı Sağanak", + "85-night": "Karlı Sağanak", + "86-day": "Karlı Sağanak", + "86-night": "Karlı Sağanak", + "95-day": "Gök Gürültülü Fırtına", + "96-day": "Dolu İle Gök Gürültülü Fırtına", + "96-night": "Dolu İle Gök Gürültülü Fırtına", + "99-night": "Dolu İle Gök Gürültülü Fırtına" }, "quicklaunch": { - "bookmark": "Bookmark", - "service": "Service" + "bookmark": "Yer İmi", + "service": "Hizmet" }, "homebridge": { - "available_update": "System", - "updates": "Updates", - "update_available": "Update Available", - "up_to_date": "Up to Date", - "child_bridges": "Child Bridges", + "available_update": "Sistem", + "updates": "Güncellemeler", + "update_available": "Güncelleme Kullanılabilir", + "up_to_date": "Güncel", + "child_bridges": "Alt Köprüler", "child_bridges_status": "{{ok}}/{{total}}" }, "autobrr": { - "approvedPushes": "Approved", - "rejectedPushes": "Rejected", - "filters": "Filters", - "indexers": "Indexers" + "approvedPushes": "Onaylandı", + "rejectedPushes": "Reddedildi", + "filters": "Süzgeçler", + "indexers": "Dizin Oluşturucular" }, "watchtower": { - "containers_scanned": "Scanned", - "containers_updated": "Updated", - "containers_failed": "Failed" + "containers_scanned": "Tarandı", + "containers_updated": "Güncellendi", + "containers_failed": "Başarısız" }, "tubearchivist": { - "downloads": "Queue", - "videos": "Videos", - "channels": "Channels", - "playlists": "Playlists" + "downloads": "Kuyruk", + "videos": "Videolar", + "channels": "Kanallar", + "playlists": "Oynatma Listeleri" }, "truenas": { - "load": "System Load", - "uptime": "Uptime", - "alerts": "Alerts", + "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" } } diff --git a/public/locales/vi/common.json b/public/locales/vi/common.json index 593b9c18d67..cf3db360a85 100644 --- a/public/locales/vi/common.json +++ b/public/locales/vi/common.json @@ -304,5 +304,20 @@ "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" } } diff --git a/public/locales/yue/common.json b/public/locales/yue/common.json index b36caac6c1f..7932f90887f 100644 --- a/public/locales/yue/common.json +++ b/public/locales/yue/common.json @@ -304,5 +304,20 @@ "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" } } diff --git a/public/locales/zh-CN/common.json b/public/locales/zh-CN/common.json index 2a09311d524..5459d7c692a 100644 --- a/public/locales/zh-CN/common.json +++ b/public/locales/zh-CN/common.json @@ -47,7 +47,7 @@ "wanted": "想看", "queued": "队列", "movies": "电影", - "missing": "Missing" + "missing": "丢失" }, "readarr": { "wanted": "订阅", @@ -192,11 +192,11 @@ "up": "向上", "down": "向下", "wait": "请稍候", - "lan": "LAN", - "wlan": "WLAN", - "devices": "Devices", - "lan_devices": "LAN Devices", - "wlan_devices": "WLAN Devices" + "lan": "局域网", + "wlan": "无线局域网", + "devices": "设备", + "lan_devices": "局域网设备", + "wlan_devices": "无线局域网设备" }, "plex": { "streams": "活动流", @@ -209,26 +209,26 @@ "wait": "请稍等" }, "changedetectionio": { - "totalObserved": "Total Observed", - "diffsDetected": "Diffs Detected" + "totalObserved": "观察到的总数", + "diffsDetected": "检测到差异" }, "wmo": { - "0-day": "Sunny", - "0-night": "Clear", - "1-day": "Mainly Sunny", - "3-day": "Cloudy", - "3-night": "Cloudy", - "45-day": "Foggy", - "48-day": "Foggy", - "51-day": "Light Drizzle", + "0-day": "晴天", + "0-night": "晴朗", + "1-day": "主要是晴天", + "3-day": "阴天", + "3-night": "阴天", + "45-day": "有雾", + "48-day": "有雾", + "51-day": "小雨", "73-night": "Snow", "75-day": "Heavy Snow", - "1-night": "Mainly Clear", - "2-day": "Partly Cloudy", - "2-night": "Partly Cloudy", - "45-night": "Foggy", - "48-night": "Foggy", - "51-night": "Light Drizzle", + "1-night": "大部晴朗", + "2-day": "多云", + "2-night": "多云", + "45-night": "有雾", + "48-night": "有雾", + "51-night": "小雨", "53-day": "Drizzle", "53-night": "Drizzle", "55-day": "Heavy Drizzle", @@ -271,8 +271,8 @@ "99-night": "Thunderstorm With Hail" }, "quicklaunch": { - "bookmark": "Bookmark", - "service": "Service" + "bookmark": "书签", + "service": "服务" }, "homebridge": { "available_update": "System", @@ -302,7 +302,22 @@ "truenas": { "load": "System Load", "uptime": "Uptime", - "alerts": "Alerts", + "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" } } diff --git a/public/locales/zh-Hant/common.json b/public/locales/zh-Hant/common.json index 24b88590057..c4673c322f3 100644 --- a/public/locales/zh-Hant/common.json +++ b/public/locales/zh-Hant/common.json @@ -304,5 +304,20 @@ "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" } } diff --git a/src/components/bookmarks/group.jsx b/src/components/bookmarks/group.jsx index 1eb86e1a32f..2910245c369 100644 --- a/src/components/bookmarks/group.jsx +++ b/src/components/bookmarks/group.jsx @@ -3,7 +3,7 @@ import List from "components/bookmarks/list"; export default function BookmarksGroup({ group }) { return ( -
+

{group.name}

diff --git a/src/components/bookmarks/item.jsx b/src/components/bookmarks/item.jsx index b67cffac714..17fcbe9ea30 100644 --- a/src/components/bookmarks/item.jsx +++ b/src/components/bookmarks/item.jsx @@ -1,6 +1,7 @@ import { useContext } from "react"; import { SettingsContext } from "utils/contexts/settings"; +import ResolvedIcon from "components/resolvedicon"; export default function Item({ bookmark }) { const { hostname } = new URL(bookmark.href); @@ -16,7 +17,12 @@ export default function Item({ bookmark }) { >
- {bookmark.abbr} + {bookmark.icon && +
+ +
+ } + {!bookmark.icon && bookmark.abbr}
{bookmark.name}
diff --git a/src/components/quicklaunch.jsx b/src/components/quicklaunch.jsx index 077e6c5c01b..1836e9b7607 100644 --- a/src/components/quicklaunch.jsx +++ b/src/components/quicklaunch.jsx @@ -2,7 +2,7 @@ import { useTranslation } from "react-i18next"; import { useEffect, useState, useRef, useCallback, useContext } from "react"; import classNames from "classnames"; -import { resolveIcon } from "./services/item"; +import ResolvedIcon from "./resolvedicon"; import { SettingsContext } from "utils/contexts/settings"; @@ -135,7 +135,7 @@ export default function QuickLaunch({servicesAndBookmarks, searchString, setSear )} onClick={handleItemClick}>
- {r.icon && resolveIcon(r.icon)} + {r.icon && } {r.abbr && r.abbr}
diff --git a/src/components/resolvedicon.jsx b/src/components/resolvedicon.jsx new file mode 100644 index 00000000000..2a3701e836d --- /dev/null +++ b/src/components/resolvedicon.jsx @@ -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 logo; + } + + // mdi- prefixed, material design icons + if (icon.startsWith("mdi-")) { + const iconName = icon.replace("mdi-", "").replace(".svg", ""); + return ( +
+ ); + } + + // fallback to dashboard-icons + const iconName = icon.replace(".png", ""); + return ( + logo + ); +} \ No newline at end of file diff --git a/src/components/services/group.jsx b/src/components/services/group.jsx index daae190942c..13b745fdd70 100644 --- a/src/components/services/group.jsx +++ b/src/components/services/group.jsx @@ -1,6 +1,7 @@ import classNames from "classnames"; import List from "components/services/list"; +import ResolvedIcon from "components/resolvedicon"; export default function ServicesGroup({ services, layout }) { return ( @@ -11,7 +12,14 @@ export default function ServicesGroup({ services, layout }) { "flex-1 p-1" )} > -

{services.name}

+
+ {layout?.icon && +
+ +
+ } +

{services.name}

+
); diff --git a/src/components/services/item.jsx b/src/components/services/item.jsx index ea3bc6a0e97..56ed2b4b1e0 100644 --- a/src/components/services/item.jsx +++ b/src/components/services/item.jsx @@ -1,4 +1,3 @@ -import Image from "next/future/image"; import classNames from "classnames"; import { useContext, useState } from "react"; @@ -7,40 +6,7 @@ import Widget from "./widget"; import Docker from "widgets/docker/component"; import { SettingsContext } from "utils/contexts/settings"; - -export function resolveIcon(icon) { - // direct or relative URLs - if (icon.startsWith("http") || icon.startsWith("/")) { - return logo; - } - - // mdi- prefixed, material design icons - if (icon.startsWith("mdi-")) { - const iconName = icon.replace("mdi-", "").replace(".svg", ""); - return ( -
- ); - } - - // fallback to dashboard-icons - const iconName = icon.replace(".png", ""); - return ( - logo - ); -} +import ResolvedIcon from "components/resolvedicon"; export default function Item({ service }) { const hasLink = service.href && service.href !== "#"; @@ -75,10 +41,12 @@ export default function Item({ service }) { rel="noreferrer" className="flex-shrink-0 flex items-center justify-center w-12 " > - {resolveIcon(service.icon)} + ) : ( -
{resolveIcon(service.icon)}
+
+ +
))} {hasLink ? ( diff --git a/src/components/services/widget/block.jsx b/src/components/services/widget/block.jsx index 00a507720fc..2af53fff062 100644 --- a/src/components/services/widget/block.jsx +++ b/src/components/services/widget/block.jsx @@ -7,7 +7,7 @@ export default function Block({ value, label }) { return (
diff --git a/src/components/widgets/openweathermap/weather.jsx b/src/components/widgets/openweathermap/weather.jsx index 6a1f2a16d33..49f428a0415 100644 --- a/src/components/widgets/openweathermap/weather.jsx +++ b/src/components/widgets/openweathermap/weather.jsx @@ -54,7 +54,7 @@ function Widget({ options }) {
data.sys.sunrise && data.dt < data.sys.sundown ? "day" : "night"} + timeOfDay={data.dt > data.sys.sunrise && data.dt < data.sys.sunset ? "day" : "night"} />
diff --git a/src/pages/index.jsx b/src/pages/index.jsx index 88c25cc4798..d9e79786f1e 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -272,7 +272,7 @@ function Home({ initialSettings }) { )} {bookmarks && ( -
+
{bookmarks.map((group) => ( ))} diff --git a/src/widgets/components.js b/src/widgets/components.js index 1f6b55a980d..b781172bffe 100644 --- a/src/widgets/components.js +++ b/src/widgets/components.js @@ -9,6 +9,7 @@ const components = { coinmarketcap: dynamic(() => import("./coinmarketcap/component")), docker: dynamic(() => import("./docker/component")), emby: dynamic(() => import("./emby/component")), + gluetun: dynamic(() => import("./gluetun/component")), gotify: dynamic(() => import("./gotify/component")), hdhomerun: dynamic(() => import("./hdhomerun/component")), homebridge: dynamic(() => import("./homebridge/component")), @@ -17,6 +18,7 @@ const components = { jellyseerr: dynamic(() => import("./jellyseerr/component")), lidarr: dynamic(() => import("./lidarr/component")), mastodon: dynamic(() => import("./mastodon/component")), + navidrome: dynamic(() => import("./navidrome/component")), npm: dynamic(() => import("./npm/component")), nzbget: dynamic(() => import("./nzbget/component")), ombi: dynamic(() => import("./ombi/component")), @@ -26,6 +28,7 @@ const components = { portainer: dynamic(() => import("./portainer/component")), prowlarr: dynamic(() => import("./prowlarr/component")), proxmox: dynamic(() => import("./proxmox/component")), + pyload: dynamic(() => import("./pyload/component")), qbittorrent: dynamic(() => import("./qbittorrent/component")), radarr: dynamic(() => import("./radarr/component")), readarr: dynamic(() => import("./readarr/component")), diff --git a/src/widgets/emby/component.jsx b/src/widgets/emby/component.jsx index fa17158073a..59d66c0566b 100644 --- a/src/widgets/emby/component.jsx +++ b/src/widgets/emby/component.jsx @@ -171,7 +171,7 @@ export default function Component({ service }) { }); } - if (sessionsError) { + if (sessionsError || sessionsData?.error) { return ; } diff --git a/src/widgets/gluetun/component.jsx b/src/widgets/gluetun/component.jsx new file mode 100644 index 00000000000..f20c400b967 --- /dev/null +++ b/src/widgets/gluetun/component.jsx @@ -0,0 +1,35 @@ +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: gluetunData, error: gluetunError } = useWidgetAPI(widget, "ip"); + + if (gluetunError) { + return ; + } + + if (!gluetunData) { + return ( + + + + + + ); + } + + return ( + + + + + + ); +} diff --git a/src/widgets/gluetun/widget.js b/src/widgets/gluetun/widget.js new file mode 100644 index 00000000000..59aa39efe22 --- /dev/null +++ b/src/widgets/gluetun/widget.js @@ -0,0 +1,14 @@ +import genericProxyHandler from "utils/proxy/handlers/generic"; + +const widget = { + api: "{url}/v1/{endpoint}", + proxyHandler: genericProxyHandler, + + mappings: { + ip: { + endpoint: "publicip/ip", + }, + }, +}; + +export default widget; diff --git a/src/widgets/navidrome/component.jsx b/src/widgets/navidrome/component.jsx new file mode 100644 index 00000000000..f4f3e67214b --- /dev/null +++ b/src/widgets/navidrome/component.jsx @@ -0,0 +1,56 @@ +import { useTranslation } from "next-i18next"; + +import Container from "components/services/widget/container"; +import useWidgetAPI from "utils/proxy/use-widget-api"; + +function SinglePlayingEntry({ entry }) { + const { username, artist, title, album } = entry; + let fullTitle = title; + if (artist) fullTitle = `${artist} - ${title}`; + if (album) fullTitle += ` — ${album}`; + if (username) fullTitle += ` (${username})`; + + return ( +
+
+
{fullTitle}
+
+
+ ); +} + +export default function Component({ service }) { + const { t } = useTranslation(); + + const { widget } = service; + + const { data: navidromeData, error: navidromeError } = useWidgetAPI(widget, "getNowPlaying"); + + if (navidromeError || navidromeData?.error || navidromeData?.["subsonic-response"]?.error) { + return ; + } + + if (!navidromeData) { + return ( + + ); + } + + const { nowPlaying } = navidromeData["subsonic-response"]; + if (!nowPlaying.entry) { + // nothing playing + return ( + + ); + } + + const nowPlayingEntries = Object.values(nowPlaying.entry); + + return ( +
+ {nowPlayingEntries.map((entry) => ( + + ))} +
+ ); +} diff --git a/src/widgets/navidrome/widget.js b/src/widgets/navidrome/widget.js new file mode 100644 index 00000000000..9d7c03d45ca --- /dev/null +++ b/src/widgets/navidrome/widget.js @@ -0,0 +1,14 @@ +import genericProxyHandler from "utils/proxy/handlers/generic"; + +const widget = { + api: "{url}/rest/{endpoint}?u={user}&t={token}&s={salt}&v=1.16.1&c=homepage&f=json", + proxyHandler: genericProxyHandler, + + mappings: { + "getNowPlaying": { + endpoint: "getNowPlaying", + }, + }, +}; + +export default widget; diff --git a/src/widgets/npm/component.jsx b/src/widgets/npm/component.jsx index b35e27c85cf..92aef03590a 100644 --- a/src/widgets/npm/component.jsx +++ b/src/widgets/npm/component.jsx @@ -11,7 +11,7 @@ export default function Component({ service }) { const { data: infoData, error: infoError } = useWidgetAPI(widget, "nginx/proxy-hosts"); - if (infoError) { + if (infoError || infoData?.error) { return ; } diff --git a/src/widgets/npm/proxy.js b/src/widgets/npm/proxy.js index eed43b571a5..ff15db62bd7 100644 --- a/src/widgets/npm/proxy.js +++ b/src/widgets/npm/proxy.js @@ -1,6 +1,33 @@ +import cache from "memory-cache"; + import getServiceWidget from "utils/config/service-helpers"; import { formatApiCall } from "utils/proxy/api-helpers"; +import { httpProxy } from "utils/proxy/http"; import widgets from "widgets/widgets"; +import createLogger from "utils/logger"; + +const proxyName = "npmProxyHandler"; +const tokenCacheKey = `${proxyName}__token`; +const logger = createLogger(proxyName); + +async function login(loginUrl, username, password) { + const authResponse = await httpProxy(loginUrl, { + method: "POST", + body: JSON.stringify({ identity: username, secret: password }), + headers: { + "Content-Type": "application/json", + }, + }); + + const status = authResponse[0]; + const data = JSON.parse(Buffer.from(authResponse[2]).toString()); + + if (status === 200) { + cache.put(tokenCacheKey, data.token); + } + + return [status, data.token ?? data]; +} export default async function npmProxyHandler(req, res) { const { group, service, endpoint } = req.query; @@ -14,27 +41,54 @@ export default async function npmProxyHandler(req, res) { if (widget) { const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget })); - const loginUrl = `${widget.url}/api/tokens`; - const body = { identity: widget.username, secret: widget.password }; - const authResponse = await fetch(loginUrl, { - method: "POST", - body: JSON.stringify(body), - headers: { - "Content-Type": "application/json", - }, - }).then((response) => response.json()); + let status; + let contentType; + let data; + + let token = cache.get(tokenCacheKey); + if (!token) { + [status, token] = await login(loginUrl, widget.username, widget.password); + if (status !== 200) { + logger.debug(`HTTTP ${status} logging into npm api: ${data}`); + return res.status(status).send(data); + } + } - const apiResponse = await fetch(url, { + [status, contentType, data] = await httpProxy(url, { method: "GET", headers: { "Content-Type": "application/json", - Authorization: `Bearer ${authResponse.token}`, + Authorization: `Bearer ${token}`, }, - }).then((response) => response.json()); + }); + + if (status === 403) { + logger.debug(`HTTTP ${status} retrieving data from npm api, logging in and trying again.`); + cache.del(tokenCacheKey); + [status, token] = await login(loginUrl, widget.username, widget.password); + + if (status !== 200) { + logger.debug(`HTTTP ${status} logging into npm api: ${data}`); + return res.status(status).send(data); + } + + // eslint-disable-next-line no-unused-vars + [status, contentType, data] = await httpProxy(url, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + } + + if (status !== 200) { + return res.status(status).send(data); + } - return res.send(apiResponse); + return res.send(data); } } diff --git a/src/widgets/pyload/component.jsx b/src/widgets/pyload/component.jsx new file mode 100644 index 00000000000..958733c31d8 --- /dev/null +++ b/src/widgets/pyload/component.jsx @@ -0,0 +1,35 @@ +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: pyloadData, error: pyloadError } = useWidgetAPI(widget, "status"); + + if (pyloadError || pyloadData?.error) { + return ; + } + + if (!pyloadData) { + return ( + + + + + + + ); + } + + return ( + + + + + + + ); +} diff --git a/src/widgets/pyload/proxy.js b/src/widgets/pyload/proxy.js new file mode 100644 index 00000000000..46b28684a4a --- /dev/null +++ b/src/widgets/pyload/proxy.js @@ -0,0 +1,102 @@ +import cache from 'memory-cache'; + +import getServiceWidget from 'utils/config/service-helpers'; +import { formatApiCall } from 'utils/proxy/api-helpers'; +import widgets from 'widgets/widgets'; +import createLogger from 'utils/logger'; +import { httpProxy } from 'utils/proxy/http'; + +const proxyName = 'pyloadProxyHandler'; +const logger = createLogger(proxyName); +const sessionCacheKey = `${proxyName}__sessionId`; +const isNgCacheKey = `${proxyName}__isNg`; + +async function fetchFromPyloadAPI(url, sessionId, params) { + const options = { + body: params + ? Object.keys(params) + .map((prop) => `${prop}=${params[prop]}`) + .join('&') + : `session=${sessionId}`, + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + }; + + // see https://github.com/benphelps/homepage/issues/517 + const isNg = cache.get(isNgCacheKey); + if (isNg && !params) { + delete options.body; + options.headers.Cookie = cache.get(sessionCacheKey); + } + + // eslint-disable-next-line no-unused-vars + const [status, contentType, data, responseHeaders] = await httpProxy(url, options); + let returnData; + try { + returnData = JSON.parse(Buffer.from(data).toString()); + } catch(e) { + logger.error(`Error logging into pyload API: ${JSON.stringify(data)}`); + returnData = data; + } + return [status, returnData, responseHeaders]; +} + +async function login(loginUrl, username, password = '') { + const [status, sessionId, responseHeaders] = await fetchFromPyloadAPI(loginUrl, null, { username, password }); + + // this API actually returns status 200 even on login failure + if (status !== 200 || sessionId === false) { + logger.error(`HTTP ${status} logging into Pyload API, returned: ${JSON.stringify(sessionId)}`); + } else if (responseHeaders['set-cookie']?.join().includes('pyload_session')) { + // Support pyload-ng, see https://github.com/benphelps/homepage/issues/517 + cache.put(isNgCacheKey, true); + const sessionCookie = responseHeaders['set-cookie'][0]; + cache.put(sessionCacheKey, sessionCookie, 60 * 60 * 23 * 1000); // cache for 23h + } else { + cache.put(sessionCacheKey, sessionId); + } + + return sessionId; +} + +export default async function pyloadProxyHandler(req, res) { + const { group, service, endpoint } = req.query; + + try { + if (group && service) { + const widget = await getServiceWidget(group, service); + + if (widget) { + const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget })); + const loginUrl = `${widget.url}/api/login`; + + let sessionId = cache.get(sessionCacheKey) ?? await login(loginUrl, widget.username, widget.password); + let [status, data] = await fetchFromPyloadAPI(url, sessionId); + + if (status === 403 || status === 401) { + logger.info('Failed to retrieve data from Pyload API, trying to login again...'); + cache.del(sessionCacheKey); + sessionId = await login(loginUrl, widget.username, widget.password); + [status, data] = await fetchFromPyloadAPI(url, sessionId); + } + + if (data?.error || status !== 200) { + try { + return res.status(status).send(Buffer.from(data).toString()); + } catch (e) { + return res.status(status).send(data); + } + } + + return res.json(data); + } + } + } catch (e) { + logger.error(e); + return res.status(500).send(e.toString()); + } + + return res.status(400).json({ error: 'Invalid proxy service type' }); +} diff --git a/src/widgets/pyload/widget.js b/src/widgets/pyload/widget.js new file mode 100644 index 00000000000..71073c0f134 --- /dev/null +++ b/src/widgets/pyload/widget.js @@ -0,0 +1,14 @@ +import pyloadProxyHandler from "./proxy"; + +const widget = { + api: "{url}/api/{endpoint}", + proxyHandler: pyloadProxyHandler, + + mappings: { + "status": { + endpoint: "statusServer", + } + } +} + +export default widget; diff --git a/src/widgets/widgets.js b/src/widgets/widgets.js index 310030c3ad7..fe432832044 100644 --- a/src/widgets/widgets.js +++ b/src/widgets/widgets.js @@ -5,6 +5,7 @@ import bazarr from "./bazarr/widget"; import changedetectionio from "./changedetectionio/widget"; import coinmarketcap from "./coinmarketcap/widget"; import emby from "./emby/widget"; +import gluetun from "./gluetun/widget"; import gotify from "./gotify/widget"; import hdhomerun from "./hdhomerun/widget"; import homebridge from "./homebridge/widget"; @@ -12,6 +13,7 @@ import jackett from "./jackett/widget"; import jellyseerr from "./jellyseerr/widget"; import lidarr from "./lidarr/widget"; import mastodon from "./mastodon/widget"; +import navidrome from "./navidrome/widget"; import npm from "./npm/widget"; import nzbget from "./nzbget/widget"; import ombi from "./ombi/widget"; @@ -21,6 +23,7 @@ import plex from "./plex/widget"; import portainer from "./portainer/widget"; import prowlarr from "./prowlarr/widget"; import proxmox from "./proxmox/widget"; +import pyload from "./pyload/widget"; import qbittorrent from "./qbittorrent/widget"; import radarr from "./radarr/widget"; import readarr from "./readarr/widget"; @@ -45,6 +48,7 @@ const widgets = { changedetectionio, coinmarketcap, emby, + gluetun, gotify, hdhomerun, homebridge, @@ -53,6 +57,7 @@ const widgets = { jellyseerr, lidarr, mastodon, + navidrome, npm, nzbget, ombi, @@ -62,6 +67,7 @@ const widgets = { portainer, prowlarr, proxmox, + pyload, qbittorrent, radarr, readarr,