diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 8f36dcc4d..dd84e0fc6 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -100,7 +100,7 @@ jobs: REVISION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }} # https://github.com/docker/setup-qemu-action#about # platforms: linux/amd64,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/arm/v7,linux/arm/v6 - platforms: linux/amd64,linux/arm64,linux/arm/v7 + platforms: linux/amd64,linux/arm64 cache-from: type=local,src=/tmp/.buildx-cache cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max diff --git a/public/locales/ar/common.json b/public/locales/ar/common.json new file mode 100644 index 000000000..683672ce3 --- /dev/null +++ b/public/locales/ar/common.json @@ -0,0 +1,302 @@ +{ + "widget": { + "missing_type": "نوع القطعة مفقود: {{type}}", + "api_error": "API خطأ", + "status": "الحالة" + }, + "weather": { + "current": "الموقع الحالي", + "allow": "اضغط للسماح", + "updating": "جاري التحديث", + "wait": "الرجاء الانتظار" + }, + "search": { + "placeholder": "بحث …" + }, + "resources": { + "cpu": "المعالج", + "total": "المجموع", + "free": "متاح", + "used": "مستخدم", + "load": "الضغط" + }, + "unifi": { + "users": "المستخدمون", + "uptime": "مدة تشغيل النظام", + "days": "ايام", + "wan": "WAN", + "lan": "LAN", + "wlan": "WLAN", + "devices": "الاجهزة", + "lan_devices": "LAN اجهزة", + "wlan_devices": "WLAN احهزة", + "lan_users": "LAN مستخدمين", + "wlan_users": "WLAN مستخدمين", + "up": "اعلي", + "down": "اسفل", + "wait": "الرجاء الانتظار" + }, + "wmo": { + "73-day": "Snow", + "0-day": "Sunny", + "0-night": "Clear", + "1-day": "Mainly Sunny", + "1-night": "Mainly Clear", + "2-day": "Partly Cloudy", + "2-night": "Partly Cloudy", + "3-day": "Cloudy", + "3-night": "Cloudy", + "45-day": "Foggy", + "45-night": "Foggy", + "48-day": "Foggy", + "48-night": "Foggy", + "51-day": "Light Drizzle", + "51-night": "Light Drizzle", + "53-day": "Drizzle", + "53-night": "Drizzle", + "55-day": "Heavy Drizzle", + "55-night": "Heavy Drizzle", + "56-day": "Light Freezing Drizzle", + "56-night": "Light Freezing Drizzle", + "57-day": "Freezing Drizzle", + "57-night": "Freezing Drizzle", + "61-day": "Light Rain", + "61-night": "Light Rain", + "63-day": "Rain", + "63-night": "Rain", + "65-day": "Heavy Rain", + "65-night": "Heavy Rain", + "66-day": "Freezing Rain", + "66-night": "Freezing Rain", + "67-day": "Freezing Rain", + "67-night": "Freezing Rain", + "71-day": "Light Snow", + "71-night": "Light Snow", + "73-night": "Snow", + "75-day": "Heavy Snow", + "75-night": "Heavy Snow", + "77-day": "Snow Grains", + "77-night": "Snow Grains", + "80-day": "Light Showers", + "80-night": "Light Showers", + "81-day": "Showers", + "81-night": "Showers", + "82-day": "Heavy Showers", + "82-night": "Heavy Showers", + "85-day": "Snow Showers", + "85-night": "Snow Showers", + "86-day": "Snow Showers", + "86-night": "Snow Showers", + "95-day": "Thunderstorm", + "95-night": "Thunderstorm", + "96-day": "Thunderstorm With Hail", + "96-night": "Thunderstorm With Hail", + "99-day": "Thunderstorm With Hail", + "99-night": "Thunderstorm With Hail" + }, + "docker": { + "rx": "RX", + "tx": "TX", + "mem": "الرام", + "cpu": "المعالج", + "offline": "غير متصل" + }, + "emby": { + "playing": "يعمل الان", + "transcoding": "التحويل", + "bitrate": "معدل البت", + "no_active": "No Active Streams" + }, + "changedetectionio": { + "totalObserved": "Total Observed", + "diffsDetected": "Diffs Detected" + }, + "tautulli": { + "playing": "Playing", + "transcoding": "Transcoding", + "bitrate": "Bitrate", + "no_active": "No Active Streams" + }, + "nzbget": { + "rate": "Rate", + "remaining": "Remaining", + "downloaded": "Downloaded" + }, + "plex": { + "streams": "Active Streams", + "movies": "Movies", + "tv": "TV Shows" + }, + "sabnzbd": { + "rate": "Rate", + "queue": "Queue", + "timeleft": "Time Left" + }, + "rutorrent": { + "active": "Active", + "upload": "Upload", + "download": "Download" + }, + "transmission": { + "download": "Download", + "upload": "Upload", + "leech": "Leech", + "seed": "Seed" + }, + "qbittorrent": { + "download": "Download", + "upload": "Upload", + "leech": "Leech", + "seed": "Seed" + }, + "sonarr": { + "wanted": "Wanted", + "queued": "Queued", + "series": "Series" + }, + "radarr": { + "wanted": "Wanted", + "missing": "Missing", + "queued": "Queued", + "movies": "Movies" + }, + "lidarr": { + "wanted": "Wanted", + "queued": "Queued", + "albums": "Albums" + }, + "readarr": { + "wanted": "Wanted", + "queued": "Queued", + "books": "Books" + }, + "bazarr": { + "missingEpisodes": "Missing Episodes", + "missingMovies": "Missing Movies" + }, + "ombi": { + "pending": "Pending", + "approved": "Approved", + "available": "Available" + }, + "jellyseerr": { + "pending": "Pending", + "approved": "Approved", + "available": "Available" + }, + "overseerr": { + "pending": "Pending", + "approved": "Approved", + "available": "Available" + }, + "pihole": { + "queries": "Queries", + "blocked": "Blocked", + "gravity": "Gravity" + }, + "adguard": { + "queries": "Queries", + "blocked": "Blocked", + "filtered": "Filtered", + "latency": "Latency" + }, + "speedtest": { + "upload": "Upload", + "download": "Download", + "ping": "Ping" + }, + "portainer": { + "running": "Running", + "stopped": "Stopped", + "total": "Total" + }, + "traefik": { + "routers": "Routers", + "services": "Services", + "middleware": "Middleware" + }, + "npm": { + "enabled": "Enabled", + "disabled": "Disabled", + "total": "Total" + }, + "coinmarketcap": { + "configure": "Configure one or more crypto currencies to track", + "1hour": "1 Hour", + "1day": "1 Day", + "7days": "7 Days", + "30days": "30 Days" + }, + "gotify": { + "apps": "Applications", + "clients": "Clients", + "messages": "Messages" + }, + "prowlarr": { + "enableIndexers": "Indexers", + "numberOfGrabs": "Grabs", + "numberOfQueries": "Queries", + "numberOfFailGrabs": "Fail Grabs", + "numberOfFailQueries": "Fail Queries" + }, + "jackett": { + "configured": "Configured", + "errored": "Errored" + }, + "strelaysrv": { + "numActiveSessions": "Sessions", + "numConnections": "Connections", + "dataRelayed": "Relayed", + "transferRate": "Rate" + }, + "mastodon": { + "user_count": "Users", + "status_count": "Posts", + "domain_count": "Domains" + }, + "authentik": { + "users": "Users", + "loginsLast24H": "Logins (24h)", + "failedLoginsLast24H": "Failed Logins (24h)" + }, + "proxmox": { + "mem": "MEM", + "cpu": "CPU", + "lxc": "LXC", + "vms": "VMs" + }, + "glances": { + "cpu": "CPU", + "mem": "MEM", + "wait": "Please wait" + }, + "quicklaunch": { + "bookmark": "Bookmark", + "service": "Service" + }, + "homebridge": { + "available_update": "System", + "updates": "Updates", + "update_available": "Update Available", + "up_to_date": "Up to Date", + "child_bridges": "Child Bridges", + "child_bridges_status": "{{ok}}/{{total}}" + }, + "watchtower": { + "containers_scanned": "Scanned", + "containers_updated": "Updated", + "containers_failed": "Failed" + }, + "autobrr": { + "approvedPushes": "Approved", + "rejectedPushes": "Rejected", + "filters": "Filters", + "indexers": "Indexers" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" + } +} diff --git a/public/locales/bg/common.json b/public/locales/bg/common.json index 0b2df53a0..a6a59141f 100644 --- a/public/locales/bg/common.json +++ b/public/locales/bg/common.json @@ -287,5 +287,16 @@ "filters": "Filters", "indexers": "Indexers", "approvedPushes": "Approved" + }, + "watchtower": { + "containers_scanned": "Scanned", + "containers_updated": "Updated", + "containers_failed": "Failed" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/public/locales/ca/common.json b/public/locales/ca/common.json index 321c5cee6..be893c616 100644 --- a/public/locales/ca/common.json +++ b/public/locales/ca/common.json @@ -287,5 +287,16 @@ "rejectedPushes": "Rejected", "filters": "Filters", "indexers": "Indexers" + }, + "watchtower": { + "containers_scanned": "Scanned", + "containers_updated": "Updated", + "containers_failed": "Failed" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/public/locales/de/common.json b/public/locales/de/common.json index 67fdc4157..28853ca07 100644 --- a/public/locales/de/common.json +++ b/public/locales/de/common.json @@ -287,5 +287,16 @@ "rejectedPushes": "Rejected", "filters": "Filters", "indexers": "Indexers" + }, + "watchtower": { + "containers_scanned": "Scanned", + "containers_updated": "Updated", + "containers_failed": "Failed" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 724d405d5..8784443a4 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -293,12 +293,23 @@ "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", diff --git a/public/locales/es/common.json b/public/locales/es/common.json index 0b3289560..e9732e84c 100644 --- a/public/locales/es/common.json +++ b/public/locales/es/common.json @@ -283,9 +283,20 @@ "child_bridges_status": "{{ok}}/{{total}}" }, "autobrr": { - "approvedPushes": "Approved", - "rejectedPushes": "Rejected", - "filters": "Filters", - "indexers": "Indexers" + "approvedPushes": "Aprobado", + "rejectedPushes": "Rechazado", + "filters": "Filtros", + "indexers": "Indexadores" + }, + "watchtower": { + "containers_scanned": "Scanned", + "containers_updated": "Updated", + "containers_failed": "Failed" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/public/locales/fi/common.json b/public/locales/fi/common.json index bcf4d9e7f..f8f1339dd 100644 --- a/public/locales/fi/common.json +++ b/public/locales/fi/common.json @@ -287,5 +287,16 @@ "rejectedPushes": "Rejected", "filters": "Filters", "indexers": "Indexers" + }, + "watchtower": { + "containers_scanned": "Scanned", + "containers_updated": "Updated", + "containers_failed": "Failed" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/public/locales/fr/common.json b/public/locales/fr/common.json index 6f1b2abf5..f71032b4f 100644 --- a/public/locales/fr/common.json +++ b/public/locales/fr/common.json @@ -283,9 +283,20 @@ "child_bridges_status": "{{ok}}/{{total}}" }, "autobrr": { - "approvedPushes": "Approved", - "rejectedPushes": "Rejected", - "filters": "Filters", - "indexers": "Indexers" + "approvedPushes": "Approuvé", + "rejectedPushes": "Rejeté", + "filters": "Filtres", + "indexers": "Indexeur" + }, + "watchtower": { + "containers_scanned": "Scanné", + "containers_updated": "Mis à jour", + "containers_failed": "Échoué" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/public/locales/he/common.json b/public/locales/he/common.json index 9c9378462..f63e1375a 100644 --- a/public/locales/he/common.json +++ b/public/locales/he/common.json @@ -287,5 +287,16 @@ "rejectedPushes": "Rejected", "filters": "Filters", "indexers": "Indexers" + }, + "watchtower": { + "containers_scanned": "Scanned", + "containers_updated": "Updated", + "containers_failed": "Failed" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/public/locales/hr/common.json b/public/locales/hr/common.json index 1905ff347..1ab626b59 100644 --- a/public/locales/hr/common.json +++ b/public/locales/hr/common.json @@ -287,5 +287,16 @@ "approvedPushes": "Approved", "filters": "Filters", "indexers": "Indexers" + }, + "watchtower": { + "containers_scanned": "Scanned", + "containers_updated": "Updated", + "containers_failed": "Failed" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/public/locales/hu/common.json b/public/locales/hu/common.json index b86bf0d4a..97a328638 100644 --- a/public/locales/hu/common.json +++ b/public/locales/hu/common.json @@ -287,5 +287,16 @@ "rejectedPushes": "Rejected", "filters": "Filters", "indexers": "Indexers" + }, + "watchtower": { + "containers_scanned": "Scanned", + "containers_updated": "Updated", + "containers_failed": "Failed" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/public/locales/it/common.json b/public/locales/it/common.json index 8e70bfa6d..58a29eddd 100644 --- a/public/locales/it/common.json +++ b/public/locales/it/common.json @@ -287,5 +287,16 @@ "rejectedPushes": "Rejected", "filters": "Filters", "indexers": "Indexers" + }, + "watchtower": { + "containers_scanned": "Scanned", + "containers_updated": "Updated", + "containers_failed": "Failed" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/public/locales/nb-NO/common.json b/public/locales/nb-NO/common.json index 2e327d327..2342b7e57 100644 --- a/public/locales/nb-NO/common.json +++ b/public/locales/nb-NO/common.json @@ -287,5 +287,16 @@ "rejectedPushes": "Rejected", "filters": "Filters", "indexers": "Indexers" + }, + "watchtower": { + "containers_scanned": "Scanned", + "containers_updated": "Updated", + "containers_failed": "Failed" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/public/locales/nl/common.json b/public/locales/nl/common.json index 13659416c..67c7b96e9 100644 --- a/public/locales/nl/common.json +++ b/public/locales/nl/common.json @@ -287,5 +287,16 @@ "rejectedPushes": "Rejected", "filters": "Filters", "indexers": "Indexers" + }, + "watchtower": { + "containers_scanned": "Scanned", + "containers_updated": "Updated", + "containers_failed": "Failed" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/public/locales/pl/common.json b/public/locales/pl/common.json index 9e8e43090..92bce0689 100644 --- a/public/locales/pl/common.json +++ b/public/locales/pl/common.json @@ -287,5 +287,16 @@ "rejectedPushes": "Rejected", "filters": "Filters", "indexers": "Indexers" + }, + "watchtower": { + "containers_scanned": "Scanned", + "containers_updated": "Updated", + "containers_failed": "Failed" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/public/locales/pt-BR/common.json b/public/locales/pt-BR/common.json index ccd8659e3..f512cf94d 100644 --- a/public/locales/pt-BR/common.json +++ b/public/locales/pt-BR/common.json @@ -287,5 +287,16 @@ "rejectedPushes": "Rejected", "filters": "Filters", "indexers": "Indexers" + }, + "watchtower": { + "containers_scanned": "Scanned", + "containers_updated": "Updated", + "containers_failed": "Failed" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/public/locales/pt/common.json b/public/locales/pt/common.json index d51ef6979..4e176a039 100644 --- a/public/locales/pt/common.json +++ b/public/locales/pt/common.json @@ -298,5 +298,16 @@ "rejectedPushes": "Rejected", "filters": "Filters", "indexers": "Indexers" + }, + "watchtower": { + "containers_scanned": "Scanned", + "containers_updated": "Updated", + "containers_failed": "Failed" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/public/locales/ro/common.json b/public/locales/ro/common.json index 4158681c4..19b85f450 100644 --- a/public/locales/ro/common.json +++ b/public/locales/ro/common.json @@ -287,5 +287,16 @@ "rejectedPushes": "Rejected", "filters": "Filters", "indexers": "Indexers" + }, + "watchtower": { + "containers_scanned": "Scanned", + "containers_updated": "Updated", + "containers_failed": "Failed" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/public/locales/ru/common.json b/public/locales/ru/common.json index a3dc98b0c..f71ac514f 100644 --- a/public/locales/ru/common.json +++ b/public/locales/ru/common.json @@ -287,5 +287,16 @@ "rejectedPushes": "Rejected", "filters": "Filters", "indexers": "Indexers" + }, + "watchtower": { + "containers_scanned": "Scanned", + "containers_updated": "Updated", + "containers_failed": "Failed" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/public/locales/sr/common.json b/public/locales/sr/common.json index 518a19efb..6c7de927b 100644 --- a/public/locales/sr/common.json +++ b/public/locales/sr/common.json @@ -287,5 +287,16 @@ "rejectedPushes": "Rejected", "filters": "Filters", "indexers": "Indexers" + }, + "watchtower": { + "containers_scanned": "Scanned", + "containers_updated": "Updated", + "containers_failed": "Failed" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/public/locales/sv/common.json b/public/locales/sv/common.json index febaec426..33235e38b 100644 --- a/public/locales/sv/common.json +++ b/public/locales/sv/common.json @@ -287,5 +287,16 @@ "rejectedPushes": "Rejected", "filters": "Filters", "indexers": "Indexers" + }, + "watchtower": { + "containers_scanned": "Scanned", + "containers_updated": "Updated", + "containers_failed": "Failed" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/public/locales/te/common.json b/public/locales/te/common.json index 6b0205fee..cc06942f7 100644 --- a/public/locales/te/common.json +++ b/public/locales/te/common.json @@ -283,9 +283,20 @@ "child_bridges_status": "{{ok}}/{{total}}" }, "autobrr": { - "rejectedPushes": "Rejected", - "approvedPushes": "Approved", - "filters": "Filters", - "indexers": "Indexers" + "rejectedPushes": "తిరస్కరించారు", + "approvedPushes": "ఆమోదించబడింది", + "filters": "ఫిల్టర్లు", + "indexers": "సూచికలు" + }, + "watchtower": { + "containers_scanned": "స్కాన్ చేశారు", + "containers_updated": "నవీకరించబడింది", + "containers_failed": "విఫలమయ్యారు" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/public/locales/tr/common.json b/public/locales/tr/common.json index ac6cf2d73..a4274a9b7 100644 --- a/public/locales/tr/common.json +++ b/public/locales/tr/common.json @@ -287,5 +287,16 @@ "rejectedPushes": "Rejected", "filters": "Filters", "indexers": "Indexers" + }, + "watchtower": { + "containers_scanned": "Scanned", + "containers_updated": "Updated", + "containers_failed": "Failed" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/public/locales/vi/common.json b/public/locales/vi/common.json index 28574310c..7905c5fe6 100644 --- a/public/locales/vi/common.json +++ b/public/locales/vi/common.json @@ -287,5 +287,16 @@ "rejectedPushes": "Rejected", "filters": "Filters", "indexers": "Indexers" + }, + "watchtower": { + "containers_scanned": "Scanned", + "containers_updated": "Updated", + "containers_failed": "Failed" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/public/locales/yue/common.json b/public/locales/yue/common.json index 0a17761e4..fd2c8abe6 100644 --- a/public/locales/yue/common.json +++ b/public/locales/yue/common.json @@ -287,5 +287,16 @@ "rejectedPushes": "Rejected", "filters": "Filters", "indexers": "Indexers" + }, + "watchtower": { + "containers_scanned": "Scanned", + "containers_updated": "Updated", + "containers_failed": "Failed" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/public/locales/zh-CN/common.json b/public/locales/zh-CN/common.json index 1a3b524bb..6410180b1 100644 --- a/public/locales/zh-CN/common.json +++ b/public/locales/zh-CN/common.json @@ -287,5 +287,16 @@ "rejectedPushes": "Rejected", "filters": "Filters", "indexers": "Indexers" + }, + "watchtower": { + "containers_scanned": "Scanned", + "containers_updated": "Updated", + "containers_failed": "Failed" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/public/locales/zh-Hant/common.json b/public/locales/zh-Hant/common.json index d80edd7de..3c24b83c9 100644 --- a/public/locales/zh-Hant/common.json +++ b/public/locales/zh-Hant/common.json @@ -287,5 +287,16 @@ "rejectedPushes": "Rejected", "filters": "Filters", "indexers": "Indexers" + }, + "watchtower": { + "containers_scanned": "Scanned", + "containers_updated": "Updated", + "containers_failed": "Failed" + }, + "tubearchivist": { + "downloads": "Queue", + "videos": "Videos", + "channels": "Channels", + "playlists": "Playlists" } } diff --git a/src/components/widgets/datetime/datetime.jsx b/src/components/widgets/datetime/datetime.jsx index f35b59394..dceaf06a3 100644 --- a/src/components/widgets/datetime/datetime.jsx +++ b/src/components/widgets/datetime/datetime.jsx @@ -27,10 +27,12 @@ export default function DateTime({ options }) { const dateFormat = new Intl.DateTimeFormat(i18n.language, { ...format }); return ( -
- - {dateFormat.format(date)} - +
+
+ + {dateFormat.format(date)} + +
); } diff --git a/src/pages/index.jsx b/src/pages/index.jsx index 1e2714c8b..88c25cc47 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -35,7 +35,7 @@ const Version = dynamic(() => import("components/version"), { ssr: false, }); -const rightAlignedWidgets = ["weatherapi", "openweathermap", "weather", "search", "datetime"]; +const rightAlignedWidgets = ["weatherapi", "openweathermap", "weather", "openmeteo", "search", "datetime"]; export async function getStaticProps() { let logger; @@ -272,7 +272,7 @@ function Home({ initialSettings }) { )} {bookmarks && ( -
+
{bookmarks.map((group) => ( ))} diff --git a/src/skeleton/bookmarks.yaml b/src/skeleton/bookmarks.yaml index 871e9134f..5a33593ad 100644 --- a/src/skeleton/bookmarks.yaml +++ b/src/skeleton/bookmarks.yaml @@ -1,6 +1,6 @@ --- # For configuration options and examples, please see: -# https://github.com/benphelps/homepage/wiki/Bookmarks +# https://gethomepage.dev/en/configs/bookmarks - Developer: - Github: diff --git a/src/skeleton/docker.yaml b/src/skeleton/docker.yaml index 724c22812..27850e836 100644 --- a/src/skeleton/docker.yaml +++ b/src/skeleton/docker.yaml @@ -1,6 +1,6 @@ --- # For configuration options and examples, please see: -# https://github.com/benphelps/homepage/wiki/Docker-Integration +# https://gethomepage.dev/en/configs/docker/ # my-docker: # host: 127.0.0.1 diff --git a/src/skeleton/services.yaml b/src/skeleton/services.yaml index 9514f67ed..323788988 100644 --- a/src/skeleton/services.yaml +++ b/src/skeleton/services.yaml @@ -1,6 +1,6 @@ --- # For configuration options and examples, please see: -# https://github.com/benphelps/homepage/wiki/Services +# https://gethomepage.dev/en/configs/services - My First Group: - My First Service: diff --git a/src/skeleton/settings.yaml b/src/skeleton/settings.yaml index 623781c63..2d0d0de09 100644 --- a/src/skeleton/settings.yaml +++ b/src/skeleton/settings.yaml @@ -1,6 +1,6 @@ --- # For configuration options and examples, please see: -# https://github.com/benphelps/homepage/wiki/Settings +# https://gethomepage.dev/en/configs/settings providers: openweathermap: openweathermapapikey diff --git a/src/skeleton/widgets.yaml b/src/skeleton/widgets.yaml index a5c6a9115..c21f674b3 100644 --- a/src/skeleton/widgets.yaml +++ b/src/skeleton/widgets.yaml @@ -1,6 +1,6 @@ --- # For configuration options and examples, please see: -# https://github.com/benphelps/homepage/wiki/Information-Widgets +# https://gethomepage.dev/en/configs/widgets - resources: cpu: true diff --git a/src/utils/proxy/handlers/credentialed.js b/src/utils/proxy/handlers/credentialed.js index c2c6e334c..54c393b17 100644 --- a/src/utils/proxy/handlers/credentialed.js +++ b/src/utils/proxy/handlers/credentialed.js @@ -33,6 +33,8 @@ export default async function credentialedProxyHandler(req, res) { headers.Authorization = `PVEAPIToken=${widget.username}=${widget.password}`; } else if (widget.type === "autobrr") { headers["X-API-Token"] = `${widget.key}`; + } else if (widget.type === "tubearchivist") { + headers.Authorization = `Token ${widget.key}`; } else { headers["X-API-Key"] = `${widget.key}`; } diff --git a/src/widgets/components.js b/src/widgets/components.js index e966e8488..33d09eac3 100644 --- a/src/widgets/components.js +++ b/src/widgets/components.js @@ -36,8 +36,10 @@ const components = { tautulli: dynamic(() => import("./tautulli/component")), traefik: dynamic(() => import("./traefik/component")), transmission: dynamic(() => import("./transmission/component")), + tubearchivist: dynamic(() => import("./tubearchivist/component")), truenas: dynamic(() => import("./truenas/component")), unifi: dynamic(() => import("./unifi/component")), + watchtower: dynamic(() => import("./watchtower/component")), }; export default components; diff --git a/src/widgets/emby/widget.js b/src/widgets/emby/widget.js index 1bb5a7260..27fc749b0 100644 --- a/src/widgets/emby/widget.js +++ b/src/widgets/emby/widget.js @@ -10,7 +10,7 @@ const widget = { }, PlayControl: { method: "POST", - enpoint: "Sessions/{sessionId}/Playing/{command}", + endpoint: "Sessions/{sessionId}/Playing/{command}", segments: ["sessionId", "command"], }, }, diff --git a/src/widgets/tubearchivist/component.jsx b/src/widgets/tubearchivist/component.jsx new file mode 100644 index 000000000..5b5484436 --- /dev/null +++ b/src/widgets/tubearchivist/component.jsx @@ -0,0 +1,40 @@ +import { useTranslation } from "next-i18next"; + +import Container from "components/services/widget/container"; +import Block from "components/services/widget/block"; +import useWidgetAPI from "utils/proxy/use-widget-api"; + +export default function Component({ service }) { + const { t } = useTranslation(); + + const { widget } = service; + + const { data: downloadsData, error: downloadsError } = useWidgetAPI(widget, "downloads"); + const { data: videosData, error: videosError } = useWidgetAPI(widget, "videos"); + const { data: channelsData, error: channelsError } = useWidgetAPI(widget, "channels"); + const { data: playlistsData, error: playlistsError } = useWidgetAPI(widget, "playlists"); + + if (downloadsError || videosError || channelsError || playlistsError) { + return ; + } + + if (!downloadsData || !videosData || !channelsData || !playlistsData) { + return ( + + + + + + + ); + } + + return ( + + + + + + + ); +} diff --git a/src/widgets/tubearchivist/widget.js b/src/widgets/tubearchivist/widget.js new file mode 100644 index 000000000..c73070f00 --- /dev/null +++ b/src/widgets/tubearchivist/widget.js @@ -0,0 +1,23 @@ +import credentialedProxyHandler from "utils/proxy/handlers/credentialed"; + +const widget = { + api: "{url}/api/{endpoint}", + proxyHandler: credentialedProxyHandler, + + mappings: { + downloads: { + endpoint: "download", + }, + videos: { + endpoint: "video", + }, + channels: { + endpoint: "channel", + }, + playlists: { + endpoint: "playlist", + }, + }, +}; + +export default widget; diff --git a/src/widgets/watchtower/component.jsx b/src/widgets/watchtower/component.jsx new file mode 100644 index 000000000..68c5531f6 --- /dev/null +++ b/src/widgets/watchtower/component.jsx @@ -0,0 +1,36 @@ +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: watchData, error: watchError } = useWidgetAPI(widget, "watchtower"); + + if (watchError || !watchData) { + return ; + } + + if (!watchData) { + return ( + + + + + + ); + } + + return ( + + + + + + ); +} diff --git a/src/widgets/watchtower/proxy.js b/src/widgets/watchtower/proxy.js new file mode 100644 index 000000000..2d54928c6 --- /dev/null +++ b/src/widgets/watchtower/proxy.js @@ -0,0 +1,48 @@ +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 = "watchtowerProxyHandler"; +const logger = createLogger(proxyName); + +export default async function watchtowerProxyHandler(req, res) { + const { group, service, endpoint } = req.query; + + if (!group || !service) { + logger.debug("Invalid or missing service '%s' or group '%s'", service, group); + return res.status(400).json({ error: "Invalid proxy service type" }); + } + + const widget = await getServiceWidget(group, service); + + if (!widget) { + logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); + return res.status(400).json({ error: "Invalid proxy service type" }); + } + + const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget })); + + const [status, contentType, data] = await httpProxy(url, { + method: "GET", + headers: { + "Authorization": `Bearer ${widget.key}`, + } + }); + + if (status !== 200 || !data) { + logger.error("Error getting data from WatchTower: %d. Data: %s", status, data); + } + + const cleanData = data.toString().split("\n").filter(s => s.startsWith("watchtower")) + const jsonRes = {} + + cleanData.map(e => e.split(" ")).forEach(strArray => { + const [key, value] = strArray + jsonRes[key] = value + }) + + if (contentType) res.setHeader("Content-Type", contentType); + return res.status(status).send(jsonRes); +} diff --git a/src/widgets/watchtower/widget.js b/src/widgets/watchtower/widget.js new file mode 100644 index 000000000..6e8fdf661 --- /dev/null +++ b/src/widgets/watchtower/widget.js @@ -0,0 +1,14 @@ +import watchtowerProxyHandler from "./proxy"; + +const widget = { + api: "{url}/{endpoint}", + proxyHandler: watchtowerProxyHandler, + + mappings: { + "watchtower": { + endpoint: "v1/metrics", + }, + }, +}; + +export default widget; diff --git a/src/widgets/widgets.js b/src/widgets/widgets.js index adb6335da..7bad4013b 100644 --- a/src/widgets/widgets.js +++ b/src/widgets/widgets.js @@ -31,8 +31,10 @@ import strelaysrv from "./strelaysrv/widget"; import tautulli from "./tautulli/widget"; import traefik from "./traefik/widget"; import transmission from "./transmission/widget"; +import tubearchivist from "./tubearchivist/widget"; import truenas from "./truenas/widget"; import unifi from "./unifi/widget"; +import watchtower from './watchtower/widget' const widgets = { adguard, @@ -69,9 +71,11 @@ const widgets = { tautulli, traefik, transmission, + tubearchivist, truenas, unifi, unifi_console: unifi, + watchtower, }; export default widgets;