mirror of
https://github.com/karl0ss/homepage.git
synced 2025-05-02 13:33:40 +01:00
Merge main
This commit is contained in:
commit
95b6ea0e23
@ -16,7 +16,7 @@
|
||||
- Container status (Running / Stopped) & statistics (CPU, Memory, Network)
|
||||
- Automatic service discovery (via labels)
|
||||
* Service Integration
|
||||
- Sonarr, Radarr, Readarr, Emby, Jellyfin, Tautulli (Plex)
|
||||
- Sonarr, Radarr, Readarr, Prowlarr, Emby, Jellyfin, Tautulli (Plex)
|
||||
- Ombi, Overseerr, Jellyseerr, NZBGet, SABnzbd, ruTorrent
|
||||
- Portainer, Traefik, Speedtest Tracker, PiHole, Nginx Proxy Manager, Gotify
|
||||
* Information Providers
|
||||
@ -78,6 +78,8 @@ pnpm install
|
||||
pnpm build
|
||||
```
|
||||
|
||||
If this is your first time starting, copy the `src/skeleton` directory to `config/` to populate initial example config files.
|
||||
|
||||
Finally, run the server:
|
||||
|
||||
```bash
|
||||
@ -131,4 +133,4 @@ Huge thanks to the all the contributors who have helped make this project what i
|
||||
* [Nonoss117](https://github.com/benphelps/homepage/commits?author=Nonoss117) - French Translation
|
||||
* [quod](https://github.com/benphelps/homepage/commits?author=quod) - Fixed Typos
|
||||
* [schklom](https://github.com/benphelps/homepage/commits?author=schklom) - ARM64, ARMv7 and ARMv6
|
||||
* [xicopitz](https://github.com/benphelps/homepage/commits?author=xicopitz) - Gotify Integration
|
||||
* [xicopitz](https://github.com/benphelps/homepage/commits?author=xicopitz) - Gotify & Prowlarr Integration
|
||||
|
@ -7,6 +7,7 @@ const nextConfig = {
|
||||
domains: ["cdn.jsdelivr.net"],
|
||||
unoptimized: true,
|
||||
},
|
||||
experimental: { images: { allowFutureImage: true } }
|
||||
};
|
||||
|
||||
module.exports = nextConfig;
|
||||
|
@ -10,7 +10,8 @@
|
||||
"resources": {
|
||||
"total": "Gesamt",
|
||||
"free": "Frei",
|
||||
"used": "Gebraucht"
|
||||
"used": "Gebraucht",
|
||||
"load": "Load"
|
||||
},
|
||||
"docker": {
|
||||
"rx": "Rx",
|
||||
@ -114,5 +115,12 @@
|
||||
"apps": "Applications",
|
||||
"clients": "Clients",
|
||||
"messages": "Messages"
|
||||
},
|
||||
"prowlarr": {
|
||||
"enableIndexers": "Indexers",
|
||||
"numberOfGrabs": "Grabs",
|
||||
"numberOfQueries": "Queries",
|
||||
"numberOfFailGrabs": "Fail Grabs",
|
||||
"numberOfFailQueries": "Fail Queries"
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,8 @@
|
||||
"resources": {
|
||||
"total": "Total",
|
||||
"free": "Free",
|
||||
"used": "Used"
|
||||
"used": "Used",
|
||||
"load": "Load"
|
||||
},
|
||||
"docker": {
|
||||
"rx": "RX",
|
||||
@ -131,5 +132,12 @@
|
||||
"apps": "Applications",
|
||||
"clients": "Clients",
|
||||
"messages": "Messages"
|
||||
},
|
||||
"prowlarr":{
|
||||
"enableIndexers": "Indexers",
|
||||
"numberOfGrabs": "Grabs",
|
||||
"numberOfQueries": "Queries",
|
||||
"numberOfFailGrabs": "Fail Grabs",
|
||||
"numberOfFailQueries": "Fail Queries"
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,8 @@
|
||||
"resources": {
|
||||
"total": "Total",
|
||||
"free": "Libre",
|
||||
"used": "Usado"
|
||||
"used": "Usado",
|
||||
"load": "Load"
|
||||
},
|
||||
"docker": {
|
||||
"rx": "Recibido",
|
||||
@ -47,9 +48,9 @@
|
||||
"movies": "Películas"
|
||||
},
|
||||
"readarr": {
|
||||
"wanted": "Wanted",
|
||||
"queued": "Queued",
|
||||
"books": "Books"
|
||||
"wanted": "Más deseado",
|
||||
"queued": "Puesto en cola",
|
||||
"books": "Libros"
|
||||
},
|
||||
"ombi": {
|
||||
"pending": "Pendiente",
|
||||
@ -98,21 +99,28 @@
|
||||
"available": "Disponible"
|
||||
},
|
||||
"sabnzbd": {
|
||||
"rate": "Rate",
|
||||
"queue": "Queue",
|
||||
"timeleft": "Time Left"
|
||||
"rate": "Tasa de descarga",
|
||||
"queue": "Puesto en cola",
|
||||
"timeleft": "Tiempo Restante"
|
||||
},
|
||||
"nzbget": {
|
||||
"rate": "Rate",
|
||||
"remaining": "Remaining",
|
||||
"downloaded": "Downloaded"
|
||||
"rate": "Tasa de descarga",
|
||||
"remaining": "Restante",
|
||||
"downloaded": "Descargado"
|
||||
},
|
||||
"coinmarketcap": {
|
||||
"configure": "Configure one or more crypto currencies to track"
|
||||
"configure": "Configurar una o varias criptomonedas para su seguimiento"
|
||||
},
|
||||
"gotify": {
|
||||
"apps": "Applications",
|
||||
"clients": "Clients",
|
||||
"messages": "Messages"
|
||||
"apps": "Aplicaciones",
|
||||
"clients": "Clientes",
|
||||
"messages": "Mensajes"
|
||||
},
|
||||
"prowlarr": {
|
||||
"enableIndexers": "Indexers",
|
||||
"numberOfGrabs": "Grabs",
|
||||
"numberOfQueries": "Queries",
|
||||
"numberOfFailGrabs": "Fail Grabs",
|
||||
"numberOfFailQueries": "Fail Queries"
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,8 @@
|
||||
"resources": {
|
||||
"total": "Total",
|
||||
"free": "Libre",
|
||||
"used": "Utilisée"
|
||||
"used": "Utilisé",
|
||||
"load": "Charge"
|
||||
},
|
||||
"docker": {
|
||||
"rx": "Rx",
|
||||
@ -32,53 +33,53 @@
|
||||
"no_active": "Aucun flux actif"
|
||||
},
|
||||
"rutorrent": {
|
||||
"active": "Active",
|
||||
"active": "Actif",
|
||||
"upload": "Téléverser",
|
||||
"download": "Télécharger"
|
||||
},
|
||||
"sonarr": {
|
||||
"wanted": "Recherchée",
|
||||
"wanted": "Demandé",
|
||||
"queued": "En queue",
|
||||
"series": "Séries"
|
||||
},
|
||||
"radarr": {
|
||||
"wanted": "Recherchée",
|
||||
"wanted": "Demandé",
|
||||
"queued": "En queue",
|
||||
"movies": "Films"
|
||||
},
|
||||
"readarr": {
|
||||
"wanted": "Wanted",
|
||||
"queued": "Queued",
|
||||
"books": "Books"
|
||||
"wanted": "Demandé",
|
||||
"queued": "En Queue",
|
||||
"books": "Livres"
|
||||
},
|
||||
"ombi": {
|
||||
"pending": "En attente",
|
||||
"approved": "Approuvée",
|
||||
"approved": "Validé",
|
||||
"available": "Disponible"
|
||||
},
|
||||
"jellyseerr": {
|
||||
"pending": "En attente",
|
||||
"approved": "Approuvée",
|
||||
"approved": "Validé",
|
||||
"available": "Disponible"
|
||||
},
|
||||
"pihole": {
|
||||
"queries": "Requêtes",
|
||||
"blocked": "Bloquée",
|
||||
"blocked": "Bloqué",
|
||||
"gravity": "La gravité"
|
||||
},
|
||||
"speedtest": {
|
||||
"upload": "Téléversement",
|
||||
"download": "Téléchargement",
|
||||
"ping": "Ping-ping"
|
||||
"ping": "Ping"
|
||||
},
|
||||
"portainer": {
|
||||
"running": "Fonctionnement",
|
||||
"running": "Démarré",
|
||||
"stopped": "Arrêté",
|
||||
"total": "Total"
|
||||
},
|
||||
"traefik": {
|
||||
"routers": "Routeurs",
|
||||
"services": "Prestations de service",
|
||||
"services": "Services",
|
||||
"middleware": "Middleware"
|
||||
},
|
||||
"npm": {
|
||||
@ -105,25 +106,32 @@
|
||||
},
|
||||
"overseerr": {
|
||||
"pending": "En attente",
|
||||
"approved": "Approuvée",
|
||||
"approved": "Validé",
|
||||
"available": "Disponible"
|
||||
},
|
||||
"sabnzbd": {
|
||||
"rate": "Rate",
|
||||
"rate": "Taux",
|
||||
"queue": "Queue",
|
||||
"timeleft": "Time Left"
|
||||
"timeleft": "Temps restant"
|
||||
},
|
||||
"nzbget": {
|
||||
"remaining": "Remaining",
|
||||
"downloaded": "Downloaded",
|
||||
"rate": "Rate"
|
||||
"remaining": "Restant",
|
||||
"downloaded": "Téléchargé",
|
||||
"rate": "Évaluer"
|
||||
},
|
||||
"coinmarketcap": {
|
||||
"configure": "Configure one or more crypto currencies to track"
|
||||
"configure": "Configurer une ou plusieurs crypto-monnaies à suivre"
|
||||
},
|
||||
"gotify": {
|
||||
"apps": "Applications",
|
||||
"clients": "Clients",
|
||||
"messages": "Messages"
|
||||
},
|
||||
"prowlarr": {
|
||||
"enableIndexers": "Indexeurs",
|
||||
"numberOfGrabs": "Capture",
|
||||
"numberOfQueries": "Demandes",
|
||||
"numberOfFailGrabs": "Capture échouée",
|
||||
"numberOfFailQueries": "Demande échouée"
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,8 @@
|
||||
"resources": {
|
||||
"total": "Totale",
|
||||
"free": "Libero",
|
||||
"used": "In utilizzo"
|
||||
"used": "In utilizzo",
|
||||
"load": "Load"
|
||||
},
|
||||
"rutorrent": {
|
||||
"active": "Attivo",
|
||||
@ -114,5 +115,12 @@
|
||||
"apps": "Applications",
|
||||
"clients": "Clients",
|
||||
"messages": "Messages"
|
||||
},
|
||||
"prowlarr": {
|
||||
"enableIndexers": "Indexers",
|
||||
"numberOfGrabs": "Grabs",
|
||||
"numberOfQueries": "Queries",
|
||||
"numberOfFailGrabs": "Fail Grabs",
|
||||
"numberOfFailQueries": "Fail Queries"
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,8 @@
|
||||
"resources": {
|
||||
"total": "Totalt",
|
||||
"free": "Ledig",
|
||||
"used": "Brukt"
|
||||
"used": "Brukt",
|
||||
"load": "Last inn"
|
||||
},
|
||||
"docker": {
|
||||
"rx": "Mottatt",
|
||||
@ -23,13 +24,13 @@
|
||||
"playing": "Spiller",
|
||||
"transcoding": "Transkoding",
|
||||
"bitrate": "Bitrate",
|
||||
"no_active": "No Active Streams"
|
||||
"no_active": "Ingen aktive strømmer"
|
||||
},
|
||||
"tautulli": {
|
||||
"playing": "Spiller",
|
||||
"transcoding": "Transkoding",
|
||||
"bitrate": "Bitrate",
|
||||
"no_active": "No Active Streams"
|
||||
"no_active": "Ingen aktive strømmer"
|
||||
},
|
||||
"rutorrent": {
|
||||
"active": "Aktiv",
|
||||
@ -93,26 +94,33 @@
|
||||
"current": "Nåværende posisjon"
|
||||
},
|
||||
"overseerr": {
|
||||
"pending": "Pending",
|
||||
"approved": "Approved",
|
||||
"available": "Available"
|
||||
"pending": "Venter",
|
||||
"approved": "Godkjent",
|
||||
"available": "Tilgjengelig"
|
||||
},
|
||||
"sabnzbd": {
|
||||
"rate": "Rate",
|
||||
"queue": "Queue",
|
||||
"timeleft": "Time Left"
|
||||
"rate": "Takt",
|
||||
"queue": "Kø",
|
||||
"timeleft": "Gjenstående tid"
|
||||
},
|
||||
"nzbget": {
|
||||
"rate": "Rate",
|
||||
"downloaded": "Downloaded",
|
||||
"remaining": "Remaining"
|
||||
"rate": "Takt",
|
||||
"downloaded": "Nedlastet",
|
||||
"remaining": "Gjenstående"
|
||||
},
|
||||
"coinmarketcap": {
|
||||
"configure": "Configure one or more crypto currencies to track"
|
||||
"configure": "Sett opp én eller flere kryptovalutaer å holde øye med"
|
||||
},
|
||||
"gotify": {
|
||||
"apps": "Applications",
|
||||
"clients": "Clients",
|
||||
"messages": "Messages"
|
||||
"apps": "Programmer",
|
||||
"clients": "Klienter",
|
||||
"messages": "Meldinger"
|
||||
},
|
||||
"prowlarr": {
|
||||
"enableIndexers": "Indekserere",
|
||||
"numberOfGrabs": "Hentninger",
|
||||
"numberOfQueries": "Spørringer",
|
||||
"numberOfFailGrabs": "Mislykkede hentinger",
|
||||
"numberOfFailQueries": "Mislykkede spørringer"
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,8 @@
|
||||
"resources": {
|
||||
"total": "Totaal",
|
||||
"free": "Vrij",
|
||||
"used": "Gebruikt"
|
||||
"used": "Gebruikt",
|
||||
"load": "Load"
|
||||
},
|
||||
"docker": {
|
||||
"rx": "RX",
|
||||
@ -114,5 +115,12 @@
|
||||
"apps": "Applications",
|
||||
"clients": "Clients",
|
||||
"messages": "Messages"
|
||||
},
|
||||
"prowlarr": {
|
||||
"enableIndexers": "Indexers",
|
||||
"numberOfGrabs": "Grabs",
|
||||
"numberOfQueries": "Queries",
|
||||
"numberOfFailGrabs": "Fail Grabs",
|
||||
"numberOfFailQueries": "Fail Queries"
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,8 @@
|
||||
"resources": {
|
||||
"total": "Total",
|
||||
"free": "Livre",
|
||||
"used": "Usada"
|
||||
"used": "Usada",
|
||||
"load": "Load"
|
||||
},
|
||||
"docker": {
|
||||
"rx": "Rx",
|
||||
@ -125,5 +126,12 @@
|
||||
"apps": "Aplicações",
|
||||
"clients": "Clientes",
|
||||
"messages": "Mensagens"
|
||||
},
|
||||
"prowlarr": {
|
||||
"enableIndexers": "Indexers",
|
||||
"numberOfGrabs": "Grabs",
|
||||
"numberOfQueries": "Queries",
|
||||
"numberOfFailGrabs": "Fail Grabs",
|
||||
"numberOfFailQueries": "Fail Queries"
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,8 @@
|
||||
"resources": {
|
||||
"total": "Общий",
|
||||
"free": "Свободно",
|
||||
"used": "Использовано"
|
||||
"used": "Использовано",
|
||||
"load": "Load"
|
||||
},
|
||||
"docker": {
|
||||
"rx": "Rx",
|
||||
@ -114,5 +115,12 @@
|
||||
"apps": "Applications",
|
||||
"clients": "Clients",
|
||||
"messages": "Messages"
|
||||
},
|
||||
"prowlarr": {
|
||||
"enableIndexers": "Indexers",
|
||||
"numberOfGrabs": "Grabs",
|
||||
"numberOfQueries": "Queries",
|
||||
"numberOfFailGrabs": "Fail Grabs",
|
||||
"numberOfFailQueries": "Fail Queries"
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,8 @@
|
||||
"resources": {
|
||||
"total": "Tổng",
|
||||
"free": "Dư",
|
||||
"used": "Đã dùng"
|
||||
"used": "Đã dùng",
|
||||
"load": "Load"
|
||||
},
|
||||
"docker": {
|
||||
"rx": "RX",
|
||||
@ -114,5 +115,12 @@
|
||||
"apps": "Applications",
|
||||
"clients": "Clients",
|
||||
"messages": "Messages"
|
||||
},
|
||||
"prowlarr": {
|
||||
"numberOfFailGrabs": "Fail Grabs",
|
||||
"enableIndexers": "Indexers",
|
||||
"numberOfGrabs": "Grabs",
|
||||
"numberOfQueries": "Queries",
|
||||
"numberOfFailQueries": "Fail Queries"
|
||||
}
|
||||
}
|
||||
|
@ -8,31 +8,32 @@
|
||||
"placeholder": "搜索…"
|
||||
},
|
||||
"resources": {
|
||||
"total": "全部的",
|
||||
"free": "自由的",
|
||||
"used": "用过的"
|
||||
"total": "共",
|
||||
"free": "空闲",
|
||||
"used": "已用",
|
||||
"load": "Load"
|
||||
},
|
||||
"docker": {
|
||||
"rx": "rx",
|
||||
"tx": "TX",
|
||||
"mem": "mem",
|
||||
"cpu": "中央处理器",
|
||||
"rx": "接收",
|
||||
"tx": "发送",
|
||||
"mem": "内存",
|
||||
"cpu": "处理器",
|
||||
"offline": "离线"
|
||||
},
|
||||
"emby": {
|
||||
"playing": "玩",
|
||||
"playing": "正在播放",
|
||||
"transcoding": "转码",
|
||||
"bitrate": "比特率",
|
||||
"no_active": "No Active Streams"
|
||||
"no_active": "暂无播放"
|
||||
},
|
||||
"tautulli": {
|
||||
"playing": "玩",
|
||||
"playing": "正在播放",
|
||||
"transcoding": "转码",
|
||||
"bitrate": "比特率",
|
||||
"no_active": "No Active Streams"
|
||||
"no_active": "暂无播放"
|
||||
},
|
||||
"rutorrent": {
|
||||
"active": "积极的",
|
||||
"active": "活动中",
|
||||
"upload": "上传",
|
||||
"download": "下载"
|
||||
},
|
||||
@ -42,18 +43,18 @@
|
||||
"series": "系列"
|
||||
},
|
||||
"radarr": {
|
||||
"wanted": "通缉",
|
||||
"queued": "排队",
|
||||
"wanted": "订阅",
|
||||
"queued": "队列",
|
||||
"movies": "电影"
|
||||
},
|
||||
"readarr": {
|
||||
"wanted": "Wanted",
|
||||
"queued": "Queued",
|
||||
"books": "Books"
|
||||
"wanted": "订阅",
|
||||
"queued": "队列",
|
||||
"books": "书籍"
|
||||
},
|
||||
"ombi": {
|
||||
"pending": "待办的",
|
||||
"approved": "得到正式认可的",
|
||||
"approved": "已批准",
|
||||
"available": "可用的"
|
||||
},
|
||||
"jellyseerr": {
|
||||
@ -72,9 +73,9 @@
|
||||
"ping": "ping"
|
||||
},
|
||||
"portainer": {
|
||||
"running": "跑步",
|
||||
"stopped": "停了下来",
|
||||
"total": "全部的"
|
||||
"running": "运行中",
|
||||
"stopped": "已停止",
|
||||
"total": "总计"
|
||||
},
|
||||
"traefik": {
|
||||
"routers": "路由器",
|
||||
@ -87,32 +88,39 @@
|
||||
"total": "全部的"
|
||||
},
|
||||
"weather": {
|
||||
"current": "Current Location",
|
||||
"allow": "Click to allow",
|
||||
"updating": "Updating",
|
||||
"wait": "Please wait"
|
||||
"current": "当前位置",
|
||||
"allow": "点击并允许",
|
||||
"updating": "更新中",
|
||||
"wait": "请等待"
|
||||
},
|
||||
"overseerr": {
|
||||
"pending": "Pending",
|
||||
"approved": "Approved",
|
||||
"available": "Available"
|
||||
"pending": "待办",
|
||||
"approved": "已批准",
|
||||
"available": "可用"
|
||||
},
|
||||
"sabnzbd": {
|
||||
"rate": "Rate",
|
||||
"queue": "Queue",
|
||||
"timeleft": "Time Left"
|
||||
"rate": "速率",
|
||||
"queue": "队列",
|
||||
"timeleft": "剩余时间"
|
||||
},
|
||||
"nzbget": {
|
||||
"rate": "Rate",
|
||||
"remaining": "Remaining",
|
||||
"downloaded": "Downloaded"
|
||||
"rate": "速率",
|
||||
"remaining": "剩余",
|
||||
"downloaded": "下载"
|
||||
},
|
||||
"coinmarketcap": {
|
||||
"configure": "Configure one or more crypto currencies to track"
|
||||
"configure": "配置一个或多个需要追踪的加密"
|
||||
},
|
||||
"gotify": {
|
||||
"apps": "Applications",
|
||||
"clients": "Clients",
|
||||
"messages": "Messages"
|
||||
"apps": "应用",
|
||||
"clients": "客户端",
|
||||
"messages": "信息"
|
||||
},
|
||||
"prowlarr": {
|
||||
"enableIndexers": "Indexers",
|
||||
"numberOfGrabs": "Grabs",
|
||||
"numberOfQueries": "Queries",
|
||||
"numberOfFailGrabs": "Fail Grabs",
|
||||
"numberOfFailQueries": "Fail Queries"
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ export default function Item({ bookmark }) {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => window.open(bookmark.href, "_blank").focus()}
|
||||
className="w-full text-left mb-3 cursor-pointer rounded-md font-medium text-theme-700 hover:text-theme-700 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-black/10 dark:shadow-black/20 bg-white/50 hover:bg-theme-300/10 dark:bg-white/10 dark:hover:bg-white/20 backdrop-blur-md"
|
||||
className="w-full text-left mb-3 cursor-pointer rounded-md font-medium text-theme-700 hover:text-theme-700 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-black/10 dark:shadow-black/20 bg-white/50 hover:bg-theme-300/10 dark:bg-white/10 dark:hover:bg-white/20"
|
||||
>
|
||||
<div className="flex">
|
||||
<div className="flex-shrink-0 flex items-center justify-center w-11 bg-theme-500/10 dark:bg-theme-900/50 text-theme-700 hover:text-theme-700 dark:text-theme-200 text-sm font-medium rounded-l-md">
|
||||
|
@ -36,7 +36,7 @@ export default function Item({ service }) {
|
||||
<div
|
||||
className={`${
|
||||
hasLink ? "cursor-pointer " : " "
|
||||
}transition-all h-15 mb-3 p-1 rounded-md font-medium text-theme-700 hover:text-theme-700/70 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-black/10 dark:shadow-black/20 bg-white/50 hover:bg-theme-300/20 dark:bg-white/10 dark:hover:bg-white/20 backdrop-blur-md`}
|
||||
}transition-all h-15 mb-3 p-1 rounded-md font-medium text-theme-700 hover:text-theme-700/70 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-black/10 dark:shadow-black/20 bg-white/50 hover:bg-theme-300/20 dark:bg-white/10 dark:hover:bg-white/20`}
|
||||
>
|
||||
<div className="flex select-none">
|
||||
{service.icon &&
|
||||
|
@ -21,6 +21,7 @@ import Npm from "./widgets/service/npm";
|
||||
import Tautulli from "./widgets/service/tautulli";
|
||||
import CoinMarketCap from "./widgets/service/coinmarketcap";
|
||||
import Gotify from "./widgets/service/gotify";
|
||||
import Prowlarr from "./widgets/service/prowlarr";
|
||||
|
||||
const widgetMappings = {
|
||||
docker: Docker,
|
||||
@ -44,6 +45,7 @@ const widgetMappings = {
|
||||
npm: Npm,
|
||||
tautulli: Tautulli,
|
||||
gotify: Gotify,
|
||||
prowlarr: Prowlarr
|
||||
};
|
||||
|
||||
export default function Widget({ service }) {
|
||||
|
55
src/components/services/widgets/service/prowlarr.jsx
Normal file
55
src/components/services/widgets/service/prowlarr.jsx
Normal file
@ -0,0 +1,55 @@
|
||||
import useSWR from "swr";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import Widget from "../widget";
|
||||
import Block from "../block";
|
||||
|
||||
import { formatApiUrl } from "utils/api-helpers";
|
||||
|
||||
export default function Prowlarr({ service }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const config = service.widget;
|
||||
|
||||
const { data: indexersData, error: indexersError } = useSWR(formatApiUrl(config, "indexer"));
|
||||
const { data: grabsData, error: grabsError } = useSWR(formatApiUrl(config, "indexerstats"));
|
||||
|
||||
if (indexersError || grabsError) {
|
||||
return <Widget error={t("widget.api_error")} />;
|
||||
}
|
||||
|
||||
if (!indexersData || !grabsData) {
|
||||
return (
|
||||
<Widget>
|
||||
<Block label={t("prowlarr.enableIndexers")} />
|
||||
<Block label={t("prowlarr.numberOfGrabs")} />
|
||||
<Block label={t("prowlarr.numberOfQueries")} />
|
||||
<Block label={t("prowlarr.numberOfFailGrabs")} />
|
||||
<Block label={t("prowlarr.numberOfFailQueries")} />
|
||||
</Widget>
|
||||
);
|
||||
}
|
||||
|
||||
const indexers = indexersData?.filter((indexer) => indexer.enable === true);
|
||||
|
||||
let numberOfGrabs = 0
|
||||
let numberOfQueries = 0
|
||||
let numberOfFailedGrabs = 0
|
||||
let numberOfFailedQueries = 0
|
||||
grabsData?.indexers?.forEach(element => {
|
||||
numberOfGrabs += element.numberOfGrabs;
|
||||
numberOfQueries += element.numberOfQueries;
|
||||
numberOfFailedGrabs += numberOfFailedGrabs + element.numberOfFailedGrabs;
|
||||
numberOfFailedQueries += numberOfFailedQueries + element.numberOfFailedQueries;
|
||||
});
|
||||
|
||||
return (
|
||||
<Widget>
|
||||
<Block label={t("prowlarr.enableIndexers")} value={indexers.length} />
|
||||
<Block label={t("prowlarr.numberOfGrabs")} value={numberOfGrabs} />
|
||||
<Block label={t("prowlarr.numberOfQueries")} value={numberOfQueries} />
|
||||
<Block label={t("prowlarr.numberOfFailGrabs")} value={numberOfFailedGrabs} />
|
||||
<Block label={t("prowlarr.numberOfFailQueries")} value={numberOfFailedQueries} />
|
||||
</Widget>
|
||||
);
|
||||
}
|
@ -5,7 +5,7 @@ import { useTranslation } from "react-i18next";
|
||||
|
||||
import UsageBar from "./usage-bar";
|
||||
|
||||
export default function Cpu() {
|
||||
export default function Cpu({ expanded }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { data, error } = useSWR(`/api/widgets/resources?type=cpu`, {
|
||||
@ -39,11 +39,29 @@ export default function Cpu() {
|
||||
return (
|
||||
<div className="flex-none flex flex-row items-center mr-3 py-1.5">
|
||||
<FiCpu className="text-theme-800 dark:text-theme-200 w-5 h-5" />
|
||||
<div className="flex flex-col ml-3 text-left font-mono min-w-[80px]">
|
||||
<div className="text-theme-800 dark:text-theme-200 text-xs">
|
||||
{t("common.number", { value: data.cpu.usage, style: "unit", unit: "percent", maximumFractionDigits: 0 })}{" "}
|
||||
{t("docker.cpu")}
|
||||
<div className="flex flex-col ml-3 text-left min-w-[85px]">
|
||||
<div className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between">
|
||||
<div className="pl-0.5">
|
||||
{t("common.number", {
|
||||
value: data.cpu.usage,
|
||||
style: "unit",
|
||||
unit: "percent",
|
||||
maximumFractionDigits: 0,
|
||||
})}
|
||||
</div>
|
||||
<div className="pr-1">{t("docker.cpu")}</div>
|
||||
</div>
|
||||
{expanded && (
|
||||
<div className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between">
|
||||
<div className="pl-0.5">
|
||||
{t("common.number", {
|
||||
value: data.cpu.load,
|
||||
maximumFractionDigits: 2,
|
||||
})}
|
||||
</div>
|
||||
<div className="pr-1">{t("resources.load")}</div>
|
||||
</div>
|
||||
)}
|
||||
<UsageBar percent={percent} />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -5,7 +5,7 @@ import { useTranslation } from "react-i18next";
|
||||
|
||||
import UsageBar from "./usage-bar";
|
||||
|
||||
export default function Disk({ options }) {
|
||||
export default function Disk({ options, expanded }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { data, error } = useSWR(`/api/widgets/resources?type=disk&target=${options.disk}`, {
|
||||
@ -37,15 +37,19 @@ export default function Disk({ options }) {
|
||||
const percent = Math.round((data.drive.usedGb / data.drive.totalGb) * 100);
|
||||
|
||||
return (
|
||||
<div className="flex-none flex flex-row items-center mr-3 py-1.5 group">
|
||||
<div className="flex-none flex flex-row items-center mr-3 py-1.5">
|
||||
<FiHardDrive className="text-theme-800 dark:text-theme-200 w-5 h-5" />
|
||||
<div className="flex flex-col ml-3 text-left min-w-[80px]">
|
||||
<span className="text-theme-800 dark:text-theme-200 text-xs group-hover:hidden">
|
||||
{t("common.bytes", { value: data.drive.freeGb * 1024 * 1024 * 1024 })} {t("resources.free")}
|
||||
</span>
|
||||
<span className="text-theme-800 dark:text-theme-200 text-xs hidden group-hover:block">
|
||||
{t("common.bytes", { value: data.drive.totalGb * 1024 * 1024 * 1024 })} {t("resources.total")}
|
||||
<div className="flex flex-col ml-3 text-left min-w-[85px]">
|
||||
<span className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between">
|
||||
<div className="pl-0.5">{t("common.bytes", { value: data.drive.freeGb * 1024 * 1024 * 1024 })}</div>
|
||||
<div className="pr-1">{t("resources.free")}</div>
|
||||
</span>
|
||||
{expanded && (
|
||||
<span className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between">
|
||||
<div className="pl-0.5">{t("common.bytes", { value: data.drive.totalGb * 1024 * 1024 * 1024 })}</div>
|
||||
<div className="pr-1">{t("resources.total")}</div>
|
||||
</span>
|
||||
)}
|
||||
<UsageBar percent={percent} />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -5,7 +5,7 @@ import { useTranslation } from "react-i18next";
|
||||
|
||||
import UsageBar from "./usage-bar";
|
||||
|
||||
export default function Memory() {
|
||||
export default function Memory({ expanded }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { data, error } = useSWR(`/api/widgets/resources?type=memory`, {
|
||||
@ -37,15 +37,27 @@ export default function Memory() {
|
||||
const percent = Math.round((data.memory.usedMemMb / data.memory.totalMemMb) * 100);
|
||||
|
||||
return (
|
||||
<div className="flex-none flex flex-row items-center mr-3 py-1.5 group">
|
||||
<div className="flex-none flex flex-row items-center mr-3 py-1.5">
|
||||
<FaMemory className="text-theme-800 dark:text-theme-200 w-5 h-5" />
|
||||
<div className="flex flex-col ml-3 text-left min-w-[80px]">
|
||||
<span className="text-theme-800 dark:text-theme-200 text-xs group-hover:hidden">
|
||||
{t("common.bytes", { value: data.memory.freeMemMb * 1024 * 1024 })} {t("resources.free")}
|
||||
</span>
|
||||
<span className="text-theme-800 dark:text-theme-200 text-xs hidden group-hover:block">
|
||||
{t("common.bytes", { value: data.memory.usedMemMb * 1024 * 1024 })} {t("resources.used")}
|
||||
<div className="flex flex-col ml-3 text-left min-w-[85px]">
|
||||
<span className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between">
|
||||
<div className="pl-0.5">
|
||||
{t("common.bytes", { value: data.memory.freeMemMb * 1024 * 1024, maximumFractionDigits: 0, binary: true })}
|
||||
</div>
|
||||
<div className="pr-1">{t("resources.free")}</div>
|
||||
</span>
|
||||
{expanded && (
|
||||
<span className="text-theme-800 dark:text-theme-200 text-xs flex flex-row justify-between">
|
||||
<div className="pl-0.5">
|
||||
{t("common.bytes", {
|
||||
value: data.memory.totalMemMb * 1024 * 1024,
|
||||
maximumFractionDigits: 0,
|
||||
binary: true,
|
||||
})}
|
||||
</div>
|
||||
<div className="pr-1">{t("resources.total")}</div>
|
||||
</span>
|
||||
)}
|
||||
<UsageBar percent={percent} />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -3,14 +3,16 @@ import Cpu from "./cpu";
|
||||
import Memory from "./memory";
|
||||
|
||||
export default function Resources({ options }) {
|
||||
console.log(options);
|
||||
const { expanded } = options;
|
||||
return (
|
||||
<div className="flex flex-col max-w:full sm:basis-auto self-center m-auto flex-wrap">
|
||||
<div className="flex flex-row self-center flex-wrap justify-between">
|
||||
{options.cpu && <Cpu />}
|
||||
{options.memory && <Memory />}
|
||||
{options.cpu && <Cpu expanded={expanded} />}
|
||||
{options.memory && <Memory expanded={expanded} />}
|
||||
{Array.isArray(options.disk)
|
||||
? options.disk.map((disk) => <Disk key={disk} options={{ disk }} />)
|
||||
: options.disk && <Disk options={options} />}
|
||||
? options.disk.map((disk) => <Disk key={disk} options={{ disk }} expanded={expanded} />)
|
||||
: options.disk && <Disk options={options} expanded={expanded} />}
|
||||
</div>
|
||||
{options.label && (
|
||||
<div className="ml-6 pt-1 text-center text-theme-800 dark:text-theme-200 text-xs">{options.label}</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
export default function UsageBar({ percent }) {
|
||||
return (
|
||||
<div className="mt-0.5 w-full bg-theme-800/30 rounded-full h-1 dark:bg-white/20 backdrop-blur-md">
|
||||
<div className="mt-0.5 w-full bg-theme-800/30 rounded-full h-1 dark:bg-white/20">
|
||||
<div
|
||||
className="bg-theme-800/70 h-1 rounded-full dark:bg-white/50"
|
||||
style={{
|
||||
|
@ -62,8 +62,7 @@ export default function Search({ options }) {
|
||||
bg-white/50 dark:bg-white/10
|
||||
focus:ring-theme-500 dark:focus:ring-white/50
|
||||
focus:border-theme-500 dark:focus:border-white/50
|
||||
border border-theme-300 dark:border-theme-200/50
|
||||
backdrop-blur-md"
|
||||
border border-theme-300 dark:border-theme-200/50"
|
||||
placeholder={t("search.placeholder")}
|
||||
onChange={(s) => setQuery(s.currentTarget.value)}
|
||||
required
|
||||
|
@ -24,6 +24,7 @@ const serviceProxyHandlers = {
|
||||
overseerr: credentialedProxyHandler,
|
||||
ombi: credentialedProxyHandler,
|
||||
coinmarketcap: credentialedProxyHandler,
|
||||
prowlarr: credentialedProxyHandler,
|
||||
// super specific handlers
|
||||
rutorrent: rutorrentProxyHandler,
|
||||
nzbget: nzbgetProxyHandler,
|
||||
|
@ -18,6 +18,7 @@ const formats = {
|
||||
sabnzbd: `{url}/api/?apikey={key}&output=json&mode={endpoint}`,
|
||||
coinmarketcap: `https://pro-api.coinmarketcap.com/{endpoint}`,
|
||||
gotify: `{url}/{endpoint}`,
|
||||
prowlarr: `{url}/api/v1/{endpoint}`,
|
||||
};
|
||||
|
||||
export function formatApiCall(api, args) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user