Compare commits

..

7 Commits

Author SHA1 Message Date
shamoon
fb9d7f6f3d Enhancement: improve dual-stack support 2025-12-07 09:06:22 -08:00
shamoon
cd34796b9d Merge branch 'main' into dev
Some checks are pending
Docker CI / Linting Checks (push) Waiting to run
Docker CI / Docker Build & Push (push) Blocked by required conditions
2025-12-07 08:53:57 -08:00
shamoon
0d788e3d06 Documentation: note instructions for enabling IPv6 in Docker
Some checks failed
Docker CI / Linting Checks (push) Waiting to run
Docker CI / Docker Build & Push (push) Blocked by required conditions
Docs / Linting Checks (push) Waiting to run
Docs / Test Build Docs (push) Blocked by required conditions
Docs / Build & Deploy Docs (push) Blocked by required conditions
Crowdin Action / Crowdin Sync (push) Has been cancelled
2025-12-07 08:49:27 -08:00
shamoon
ed1dafadde Improvement: include longer auto-select timeout in http agent options (#6059)
Some checks failed
Docker CI / Linting Checks (push) Has been cancelled
Docker CI / Docker Build & Push (push) Has been cancelled
2025-12-06 21:29:18 -08:00
shamoon
96ac9046b3 Fix: handle widget version parsing for array labels (#6053)
Some checks failed
Docker CI / Linting Checks (push) Has been cancelled
Docker CI / Docker Build & Push (push) Has been cancelled
2025-12-04 08:53:28 -08:00
shamoon
6d5f35f07e Enhancement: add valueOnly option to block highlighting feature (#6051) 2025-12-04 08:42:24 -08:00
shamoon
8887281246 Documentation: make docker.sock mount read-only in docs
Some checks failed
Crowdin Action / Crowdin Sync (push) Has been cancelled
Docs / Linting Checks (push) Has been cancelled
Docker CI / Linting Checks (push) Has been cancelled
Docs / Test Build Docs (push) Has been cancelled
Docs / Build & Deploy Docs (push) Has been cancelled
Docker CI / Docker Build & Push (push) Has been cancelled
Repository Maintenance / Stale (push) Has been cancelled
Repository Maintenance / Lock Old Threads (push) Has been cancelled
Repository Maintenance / Close Answered Discussions (push) Has been cancelled
Repository Maintenance / Close Outdated Discussions (push) Has been cancelled
Repository Maintenance / Close Unsupported Feature Requests (push) Has been cancelled
2025-11-30 20:04:42 -08:00
52 changed files with 112 additions and 126 deletions

View File

@@ -54,7 +54,7 @@ RUN apk add --no-cache su-exec iputils-ping shadow
USER root
ENV NODE_ENV=production
ENV HOSTNAME=0.0.0.0
ENV HOSTNAME=::
ENV PORT=3000
EXPOSE $PORT

View File

@@ -12,6 +12,15 @@ export PGID=${PGID:-0}
export HOMEPAGE_BUILDTIME=$(date +%s)
# Try IPv6 first (dual stack when available), but fall back to IPv4 if the bind fails
export HOSTNAME=${HOSTNAME:-::}
if [ "$HOSTNAME" = "::" ]; then
if ! node -e "const server = require('http').createServer(() => {}); const host = '::'; const port = process.env.PORT || 3000; server.once('error', (err) => { console.error('IPv6 bind failed:', err.message); process.exit(1); }); server.listen(port, host, () => server.close(() => process.exit(0)));"; then
echo "Falling back to IPv4 bind at 0.0.0.0"
export HOSTNAME=0.0.0.0
fi
fi
# Check ownership before chown
if [ -e /app/config ]; then
CURRENT_UID=$(stat -c %u /app/config)

View File

@@ -159,6 +159,19 @@ Widgets can tint their metric block text automatically based on rules defined al
Supported numeric operators for the `when` property are `gt`, `gte`, `lt`, `lte`, `eq`, `ne`, `between`, and `outside`. String rules support `equals`, `includes`, `startsWith`, `endsWith`, and `regex`. Each rule can be inverted with `negate: true`, and string rules may pass `caseSensitive: true` or custom regex `flags`. The highlight engine does its best to coerce formatted values, but you will get the most reliable results when you pass plain numbers or strings into `<Block>`.
#### Value Only Highlighting
You can optionally apply highlighting only to the value portion of a block (not the label) by setting `valueOnly: true` on the field configuration. This keeps the label visible while highlighting only the metric value itself.
```yaml
- Sonarr:
...
highlight:
queued:
valueOnly: true
...
```
## Descriptions
Services may have descriptions,

View File

@@ -14,7 +14,7 @@ services:
- 3000:3000
volumes:
- /path/to/config:/app/config # Make sure your local config directory exists
- /var/run/docker.sock:/var/run/docker.sock # (optional) For docker integrations
- /var/run/docker.sock:/var/run/docker.sock:ro # (optional) For docker integrations
environment:
HOMEPAGE_ALLOWED_HOSTS: gethomepage.dev # required, may need port. See gethomepage.dev/installation/#homepage_allowed_hosts
```
@@ -36,7 +36,7 @@ services:
- 3000:3000
volumes:
- /path/to/config:/app/config # Make sure your local config directory exists
- /var/run/docker.sock:/var/run/docker.sock # (optional) For docker integrations, see alternative methods
- /var/run/docker.sock:/var/run/docker.sock:ro # (optional) For docker integrations, see alternative methods
environment:
HOMEPAGE_ALLOWED_HOSTS: gethomepage.dev # required, may need port. See gethomepage.dev/installation/#homepage_allowed_hosts
PUID: $PUID

View File

@@ -68,7 +68,7 @@ All service widgets work essentially the same, that is, homepage makes a proxied
If, after correctly adding and mapping your custom icons via the [Icons](../configs/services.md#icons) instructions, you are still unable to see your icons please try recreating your container.
## Disabling IPv6
## Disabling IPv6 for http requests {#disabling-ipv6}
If you are having issues with certain widgets that are unable to reach public APIs (e.g. weather), in certain setups you may need to disable IPv6. You can set the environment variable `HOMEPAGE_PROXY_DISABLE_IPV6` to `true` to disable IPv6 for the homepage proxy.

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Vandag",
"gross_percent_1y": "Een jaar",
"gross_percent_max": "Alle tyd",
"net_worth": "Net Worth"
"gross_percent_max": "Alle tyd"
},
"audiobookshelf": {
"podcasts": "Podsendinge",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "سنة",
"gross_percent_max": "كل الوقت",
"net_worth": "Net Worth"
"gross_percent_max": "كل الوقت"
},
"audiobookshelf": {
"podcasts": "بودكاست",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "Една година",
"gross_percent_max": "All time",
"net_worth": "Net Worth"
"gross_percent_max": "All time"
},
"audiobookshelf": {
"podcasts": "Подкасти",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "Un any",
"gross_percent_max": "Sempre",
"net_worth": "Net Worth"
"gross_percent_max": "Sempre"
},
"audiobookshelf": {
"podcasts": "Pòdcasts",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "Jeden rok",
"gross_percent_max": "Za celou dobu",
"net_worth": "Net Worth"
"gross_percent_max": "Za celou dobu"
},
"audiobookshelf": {
"podcasts": "Podcasty",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "Et År",
"gross_percent_max": "Altid",
"net_worth": "Net Worth"
"gross_percent_max": "Altid"
},
"audiobookshelf": {
"podcasts": "Podcasts",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Heute",
"gross_percent_1y": "Ein Jahr",
"gross_percent_max": "Gesamt",
"net_worth": ""
"gross_percent_max": "Gesamt"
},
"audiobookshelf": {
"podcasts": "Podcasts",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "Ένας χρόνος",
"gross_percent_max": "Διαχρονικά",
"net_worth": "Net Worth"
"gross_percent_max": "Διαχρονικά"
},
"audiobookshelf": {
"podcasts": "Podcasts",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "One year",
"gross_percent_max": "All time",
"net_worth": "Net Worth"
"gross_percent_max": "All time"
},
"audiobookshelf": {
"podcasts": "Podcasts",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Hoy",
"gross_percent_1y": "Un año",
"gross_percent_max": "Todo el tiempo",
"net_worth": "Net Worth"
"gross_percent_max": "Todo el tiempo"
},
"audiobookshelf": {
"podcasts": "Podcasts",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "One year",
"gross_percent_max": "All time",
"net_worth": "Net Worth"
"gross_percent_max": "All time"
},
"audiobookshelf": {
"podcasts": "Podcasts",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "One year",
"gross_percent_max": "All time",
"net_worth": "Net Worth"
"gross_percent_max": "All time"
},
"audiobookshelf": {
"podcasts": "Podcasts",

View File

@@ -142,8 +142,8 @@
"connectionStatusDisconnected": "Déconnecté",
"connectionStatusConnected": "Connecté",
"uptime": "Démarré depuis",
"maxDown": "Réception max",
"maxUp": "Envoi max",
"maxDown": "Réception max.",
"maxUp": "Envoi max.",
"down": "Réception",
"up": "Envoi",
"received": "Reçu",
@@ -229,7 +229,7 @@
"seed": "En partage"
},
"develancacheui": {
"cachehitbytes": "Octets acquis du cache",
"cachehitbytes": "Cache Hit (B)",
"cachemissbytes": "Cache Miss (B)"
},
"downloadstation": {
@@ -294,7 +294,7 @@
"queries": "Requêtes",
"blocked": "Bloqué",
"blocked_percent": "% bloqué",
"gravity": "Listes dom. Bloqués"
"gravity": "Listes dom. bloqués"
},
"adguard": {
"queries": "Requêtes",
@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Aujourd'hui",
"gross_percent_1y": "Un an",
"gross_percent_max": "Depuis le début",
"net_worth": "Patrimoine net"
"gross_percent_max": "Depuis le début"
},
"audiobookshelf": {
"podcasts": "Podcasts",
@@ -1092,7 +1091,7 @@
"NEW_ARRAY": "Nouveau tableau",
"RECON_DISK": "Reconstruction du disque",
"DISABLE_DISK": "Disque désactivé",
"SWAP_DSBL": "Désactiver le swap",
"SWAP_DSBL": "Swap Disable",
"INVALID_EXPANSION": "Extension invalide",
"PARITY_NOT_BIGGEST": "La parité n'est pas la plus grande",
"TOO_MANY_MISSING_DISKS": "Trop de disques manquants",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "היום",
"gross_percent_1y": "שנה",
"gross_percent_max": "כל הזמן",
"net_worth": "Net Worth"
"gross_percent_max": "כל הזמן"
},
"audiobookshelf": {
"podcasts": "פודקאסטים",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "One year",
"gross_percent_max": "All time",
"net_worth": "Net Worth"
"gross_percent_max": "All time"
},
"audiobookshelf": {
"podcasts": "Podcasts",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Danas",
"gross_percent_1y": "Jedna godina",
"gross_percent_max": "Svo vrijeme",
"net_worth": "Neto vrijednost"
"gross_percent_max": "Svo vrijeme"
},
"audiobookshelf": {
"podcasts": "Podcasti",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "Egy év",
"gross_percent_max": "Mindig",
"net_worth": "Net Worth"
"gross_percent_max": "Mindig"
},
"audiobookshelf": {
"podcasts": "Podcast",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "Satu Tahun",
"gross_percent_max": "Sepanjang Masa",
"net_worth": "Net Worth"
"gross_percent_max": "Sepanjang Masa"
},
"audiobookshelf": {
"podcasts": "Podcast",

View File

@@ -168,7 +168,7 @@
"passes": "Tessere"
},
"tautulli": {
"playing": "In riproduzione",
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
@@ -313,7 +313,7 @@
"total": "Total"
},
"suwayomi": {
"download": "Scaricati",
"download": "Downloaded",
"nondownload": "Non Scaricato",
"read": "Read",
"unread": "Unread",
@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "Un anno",
"gross_percent_max": "Sempre",
"net_worth": "Net Worth"
"gross_percent_max": "Sempre"
},
"audiobookshelf": {
"podcasts": "Podcast",

View File

@@ -69,7 +69,7 @@
"docker": {
"rx": "受信済み",
"tx": "送信済み",
"mem": "メモリ",
"mem": "MEM",
"cpu": "CPU",
"running": "起動中",
"offline": "オフライン",
@@ -83,7 +83,7 @@
"partial": "部分的"
},
"ping": {
"error": "エラー",
"error": "Error",
"ping": "Ping",
"down": "下へ",
"up": "稼働",
@@ -112,7 +112,7 @@
"offline_alt": "オフライン",
"online": "オンライン",
"total": "Total",
"unknown": "不明"
"unknown": "Unknown"
},
"evcc": {
"pv_power": "発電量",
@@ -223,8 +223,8 @@
"invalid": "無効"
},
"deluge": {
"download": "ダウンロード",
"upload": "アップロード",
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
@@ -233,8 +233,8 @@
"cachemissbytes": "キャッシュミスバイト"
},
"downloadstation": {
"download": "ダウンロード",
"upload": "アップロード",
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
@@ -251,7 +251,7 @@
"queued": "Queued",
"movies": "Movies",
"queue": "Queue",
"unknown": "不明"
"unknown": "Unknown"
},
"lidarr": {
"wanted": "Wanted",
@@ -692,8 +692,8 @@
},
"diskstation": {
"days": "Days",
"uptime": "稼働時間",
"volumeAvailable": "利用可能"
"uptime": "Uptime",
"volumeAvailable": "Available"
},
"mylar": {
"series": "Series",
@@ -754,13 +754,12 @@
"gatus": {
"up": "Sites Up",
"down": "Sites Down",
"uptime": "稼働時間"
"uptime": "Uptime"
},
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "1年",
"gross_percent_max": "全期間",
"net_worth": "Net Worth"
"gross_percent_max": "全期間"
},
"audiobookshelf": {
"podcasts": "ポッドキャスト",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "오늘",
"gross_percent_1y": "1년",
"gross_percent_max": "전체 기간",
"net_worth": "Net Worth"
"gross_percent_max": "전체 기간"
},
"audiobookshelf": {
"podcasts": "팟캐스트",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "One year",
"gross_percent_max": "All time",
"net_worth": "Net Worth"
"gross_percent_max": "All time"
},
"audiobookshelf": {
"podcasts": "Podcasts",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "Satu tahun",
"gross_percent_max": "Sepanjang masa",
"net_worth": "Net Worth"
"gross_percent_max": "Sepanjang masa"
},
"audiobookshelf": {
"podcasts": "Podkas",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Vandaag",
"gross_percent_1y": "Een jaar",
"gross_percent_max": "Altijd",
"net_worth": "Net Worth"
"gross_percent_max": "Altijd"
},
"audiobookshelf": {
"podcasts": "Podcasts",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "Ett år",
"gross_percent_max": "Gjennom tidene",
"net_worth": "Net Worth"
"gross_percent_max": "Gjennom tidene"
},
"audiobookshelf": {
"podcasts": "Podkaster",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Dzisiaj",
"gross_percent_1y": "Rok",
"gross_percent_max": "Od początku",
"net_worth": "Net Worth"
"gross_percent_max": "Od początku"
},
"audiobookshelf": {
"podcasts": "Podcasty",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "Um ano",
"gross_percent_max": "Desde Sempre",
"net_worth": "Net Worth"
"gross_percent_max": "Desde Sempre"
},
"audiobookshelf": {
"podcasts": "Podcasts",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Hoje",
"gross_percent_1y": "Um ano",
"gross_percent_max": "Todo o tempo",
"net_worth": "Patrimônio Líquido"
"gross_percent_max": "Todo o tempo"
},
"audiobookshelf": {
"podcasts": "Podcasts",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "Un an",
"gross_percent_max": "Tot timpul",
"net_worth": "Net Worth"
"gross_percent_max": "Tot timpul"
},
"audiobookshelf": {
"podcasts": "Podcasturi",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Сегодня",
"gross_percent_1y": "Один год",
"gross_percent_max": "Все время",
"net_worth": "Net Worth"
"gross_percent_max": "Все время"
},
"audiobookshelf": {
"podcasts": "Подкасты",

View File

@@ -362,8 +362,8 @@
},
"trilium": {
"version": "Verzia",
"notesCount": "Poznámky",
"dbSize": "Veľkosť databázy",
"notesCount": "Notes",
"dbSize": "Database Size",
"unknown": "Neznáme"
},
"navidrome": {
@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Dnes",
"gross_percent_1y": "Jeden rok",
"gross_percent_max": "Za celý čas",
"net_worth": "Net Worth"
"gross_percent_max": "Za celý čas"
},
"audiobookshelf": {
"podcasts": "Podcasty",
@@ -787,7 +786,7 @@
"downloadCount": "Poradie",
"downloadBytesRemaining": "Zostávajúce",
"downloadTotalBytes": "Veľkosť",
"downloadSpeed": "Rýchlosť"
"downloadSpeed": "Speed"
},
"kavita": {
"seriesCount": "Series",
@@ -953,7 +952,7 @@
"loading": "Načítava sa",
"open": "Open - US Market",
"closed": "Closed - US Market",
"invalidConfiguration": "Neplatná konfigurácia"
"invalidConfiguration": "Invalid Configuration"
},
"frigate": {
"cameras": "Kamery",
@@ -1023,10 +1022,10 @@
"loading": "Načítava sa"
},
"gitlab": {
"groups": "Skupiny",
"issues": "Problémy",
"groups": "Groups",
"issues": "Issues",
"merges": "Merge Requests",
"projects": "Projekty"
"projects": "Projects"
},
"apcups": {
"status": "Stav",
@@ -1036,7 +1035,7 @@
},
"karakeep": {
"bookmarks": "Bookmarks",
"favorites": "Obľúbené",
"favorites": "Favorites",
"archived": "Archived",
"highlights": "Highlights",
"lists": "Zoznamy",
@@ -1066,13 +1065,13 @@
"komodo": {
"total": "Celkom",
"running": "Beží",
"stopped": "Zastavené",
"stopped": "Stopped",
"down": "Down",
"unhealthy": "Nezdravý",
"unknown": "Neznáme",
"servers": "Servery",
"servers": "Servers",
"stacks": "Stacks",
"containers": "Kontajnery"
"containers": "Containers"
},
"filebrowser": {
"available": "Dostupné",
@@ -1081,8 +1080,8 @@
},
"wallos": {
"activeSubscriptions": "Subscriptions",
"thisMonthlyCost": "Tento mesiac",
"nextMonthlyCost": "Ďalší mesiac",
"thisMonthlyCost": "This Month",
"nextMonthlyCost": "Next Month",
"previousMonthlyCost": "Prev. Month",
"nextRenewingSubscription": "Next Payment"
},

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "Eno leto",
"gross_percent_max": "Celoten čas",
"net_worth": "Net Worth"
"gross_percent_max": "Celoten čas"
},
"audiobookshelf": {
"podcasts": "Podcasti",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Данас",
"gross_percent_1y": "Једна година",
"gross_percent_max": "Све време",
"net_worth": "Нето вредност"
"gross_percent_max": "Све време"
},
"audiobookshelf": {
"podcasts": "Подкасти",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "One year",
"gross_percent_max": "All time",
"net_worth": "Net Worth"
"gross_percent_max": "All time"
},
"audiobookshelf": {
"podcasts": "Podcasts",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "One year",
"gross_percent_max": "All time",
"net_worth": "Net Worth"
"gross_percent_max": "All time"
},
"audiobookshelf": {
"podcasts": "Podcasts",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "One year",
"gross_percent_max": "All time",
"net_worth": "Net Worth"
"gross_percent_max": "All time"
},
"audiobookshelf": {
"podcasts": "Podcasts",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Bugün",
"gross_percent_1y": "Bir yıl",
"gross_percent_max": "Tüm zaman",
"net_worth": "Net Worth"
"gross_percent_max": "Tüm zaman"
},
"audiobookshelf": {
"podcasts": "Podcast",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "Один рік",
"gross_percent_max": "Весь час",
"net_worth": "Net Worth"
"gross_percent_max": "Весь час"
},
"audiobookshelf": {
"podcasts": "Подкасти",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "One year",
"gross_percent_max": "All time",
"net_worth": "Net Worth"
"gross_percent_max": "All time"
},
"audiobookshelf": {
"podcasts": "Podcasts",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "一年",
"gross_percent_max": "所有時間",
"net_worth": "Net Worth"
"gross_percent_max": "所有時間"
},
"audiobookshelf": {
"podcasts": "播客",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "一年",
"gross_percent_max": "所有时间",
"net_worth": "Net Worth"
"gross_percent_max": "所有时间"
},
"audiobookshelf": {
"podcasts": "播客",

View File

@@ -759,8 +759,7 @@
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_1y": "一年",
"gross_percent_max": "所有時間",
"net_worth": "Net Worth"
"gross_percent_max": "所有時間"
},
"audiobookshelf": {
"podcasts": "Podcasts",

View File

@@ -32,6 +32,8 @@ export default function Block({ value, label, field }) {
return getHighlightClass(highlight.level, highlightConfig);
}, [highlight, highlightConfig]);
const applyToValueOnly = highlight?.valueOnly === true;
return (
<div
className={classNames(
@@ -44,7 +46,11 @@ export default function Block({ value, label, field }) {
data-highlight-source={highlight?.source}
>
<div className="font-thin text-sm">{value === undefined || value === null ? "-" : value}</div>
<div className="font-bold text-xs uppercase">{t(label)}</div>
<div
className={classNames("font-bold text-xs uppercase", applyToValueOnly && "text-theme-700 dark:text-theme-200")}
>
{t(label)}
</div>
</div>
);
}

View File

@@ -4,7 +4,7 @@ export function middleware(req) {
// Check the Host header, if HOMEPAGE_ALLOWED_HOSTS is set
const host = req.headers.get("host");
const port = process.env.PORT || 3000;
let allowedHosts = [`localhost:${port}`, `127.0.0.1:${port}`];
let allowedHosts = [`localhost:${port}`, `127.0.0.1:${port}`, `[::1]:${port}`];
const allowAll = process.env.HOMEPAGE_ALLOWED_HOSTS === "*";
if (process.env.HOMEPAGE_ALLOWED_HOSTS) {
allowedHosts = allowedHosts.concat(process.env.HOMEPAGE_ALLOWED_HOSTS.split(","));

View File

@@ -111,7 +111,7 @@ export async function servicesFromDocker() {
};
}
let substitutedVal = substituteEnvironmentVars(containerLabels[label]);
if (value === "widget.version") {
if (value === "widget.version" || /^widgets\[\d+\]\.version$/.test(value)) {
substitutedVal = parseInt(substitutedVal, 10);
}
shvl.set(constructedService, value, substitutedVal);

View File

@@ -200,7 +200,7 @@ const ensureArray = (value) => {
};
const findHighlightLevel = (ruleSet, numericValue, stringValue) => {
const { numeric, string } = ruleSet;
const { numeric, string, valueOnly } = ruleSet;
if (numeric && numericValue !== undefined) {
const numericRules = ensureArray(numeric);
@@ -208,7 +208,7 @@ const findHighlightLevel = (ruleSet, numericValue, stringValue) => {
for (const candidate of numericCandidates) {
for (const rule of numericRules) {
if (rule?.level && evaluateNumericRule(candidate, rule)) {
return { level: rule.level, source: "numeric", rule };
return { level: rule.level, source: "numeric", rule, valueOnly };
}
}
}
@@ -218,7 +218,7 @@ const findHighlightLevel = (ruleSet, numericValue, stringValue) => {
const stringRules = ensureArray(string);
for (const rule of stringRules) {
if (rule?.level && evaluateStringRule(stringValue, rule)) {
return { level: rule.level, source: "string", rule };
return { level: rule.level, source: "string", rule, valueOnly };
}
}
}

View File

@@ -111,7 +111,7 @@ export async function cachedRequest(url, duration = 5, ua = "homepage") {
export async function httpProxy(url, params = {}) {
const constructedUrl = new URL(url);
const disableIpv6 = process.env.HOMEPAGE_PROXY_DISABLE_IPV6 === "true";
const agentOptions = disableIpv6 ? { family: 4, autoSelectFamily: false } : {};
const agentOptions = disableIpv6 ? { family: 4, autoSelectFamily: false } : { autoSelectFamilyAttemptTimeout: 500 };
let request = null;
if (constructedUrl.protocol === "https:") {