diff --git a/config/pages/home.yml b/config/pages/home.yml
index e2c1e1b..5c8e46f 100644
--- a/config/pages/home.yml
+++ b/config/pages/home.yml
@@ -20,13 +20,19 @@
- $include: ../widgets/feeds/hacker-news.yml
- $include: ../widgets/feeds/lobsters.yml
- $include: ../widgets/reddit/selfhosted.yml
+ - $include: ../widgets/custom/wikipedia-on-this-day.yml
- $include: ../widgets/videos/youtube-subscriptions.yml
- size: small
widgets:
- $include: ../widgets/clock.yml
+ - $include: ../widgets/custom/sunrise-sunset.yml
- $include: ../widgets/calendar.yml
+ - $include: ../widgets/custom/random-fact.yml
- $include: ../widgets/weather/quito.yml
- $include: ../widgets/weather/seoul.yml
- - $include: ../widgets/markets.yml
+ - $include: ../widgets/custom/lastfm-latest.yml
+ - $include: ../widgets/custom/steam-recent-games.yml
+ - $include: ../widgets/custom/steam-friends.yml
- $include: ../widgets/releases/followed.yml
- $include: ../widgets/releases/own.yml
+ - $include: ../widgets/custom/xkcd.yml
diff --git a/config/widgets/custom/lastfm-latest.yml b/config/widgets/custom/lastfm-latest.yml
new file mode 100644
index 0000000..b588e91
--- /dev/null
+++ b/config/widgets/custom/lastfm-latest.yml
@@ -0,0 +1,33 @@
+- type: custom-api
+ title: 🎵 Lastest Scrobbles
+ cache: 60s
+ url: http://ws.audioscrobbler.com/2.0/
+ parameters:
+ method: user.getRecentTracks
+ user: ${LASTFM_USERNAME}
+ api_key: ${LASTFM_API_KEY}
+ format: json
+ limit: 10
+ template: |
+
+ {{ range .JSON.Array "recenttracks.track" }}
+ -
+
+
+
+
+
{{ .String "artist.#text" }}
+
{{ .String "name" }}
+
+ {{ if .String "@attr.nowplaying" }}
+ Now playing
+ {{ else }}
+
+ {{ end }}
+
+
+
+ {{ end }}
+
diff --git a/config/widgets/custom/random-fact.yml b/config/widgets/custom/random-fact.yml
new file mode 100644
index 0000000..2eb08bd
--- /dev/null
+++ b/config/widgets/custom/random-fact.yml
@@ -0,0 +1,6 @@
+- type: custom-api
+ title: 💡 Random Fact
+ cache: 1h
+ url: https://uselessfacts.jsph.pl/api/v2/facts/random
+ template: |
+ {{ .JSON.String "text" }}
diff --git a/config/widgets/custom/steam-friends.yml b/config/widgets/custom/steam-friends.yml
new file mode 100644
index 0000000..807d044
--- /dev/null
+++ b/config/widgets/custom/steam-friends.yml
@@ -0,0 +1,56 @@
+- type: custom-api
+ title: 🎮 Steam Friends
+ cache: 1m
+ url: https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=${STEAM_API_KEY}&steamids=${STEAM_FRIENDS}
+ template: |
+
+ {{ $players := .JSON.Array "response.players" }}
+ {{ if gt (len $players) 0 }}
+ {{ range $players }}
+ {{ $status := .Int "personastate" }}
+ {{ $colorClass := "color-subdue" }}
+ {{ $statusText := "Offline" }}
+ {{ if eq $status 1 }}
+ {{ $colorClass = "color-positive" }}
+ {{ $statusText = "Online" }}
+ {{ else if eq $status 2 }}
+ {{ $colorClass = "color-highlight" }}
+ {{ $statusText = "Busy" }}
+ {{ else if eq $status 3 }}
+ {{ $colorClass = "color-primary" }}
+ {{ $statusText = "Away" }}
+ {{ else if eq $status 4 }}
+ {{ $colorClass = "color-primary" }}
+ {{ $statusText = "Snooze" }}
+ {{ else if eq $status 5 }}
+ {{ $colorClass = "color-primary" }}
+ {{ $statusText = "Looking to Trade" }}
+ {{ else if eq $status 6 }}
+ {{ $colorClass = "color-primary" }}
+ {{ $statusText = "Looking to Play" }}
+ {{ end }}
+ -
+
+
+
+
+
{{ .String "personaname" }}
+
+ {{ if .Exists "gameextrainfo" }}
+ {{ .String "gameextrainfo" }}
+ {{ else }}
+ {{ $statusText }}
+ {{ if eq $status 0 }}
+ {{ if .Exists "lastlogoff" }}
+ for
+ {{ end }}
+ {{ end }}
+ {{ end }}
+
+
+
+ {{ end }}
+ {{ else }}
+ No player data found.
+ {{ end }}
+
\ No newline at end of file
diff --git a/config/widgets/custom/steam-recent-games.yml b/config/widgets/custom/steam-recent-games.yml
new file mode 100644
index 0000000..67e4089
--- /dev/null
+++ b/config/widgets/custom/steam-recent-games.yml
@@ -0,0 +1,46 @@
+- type: custom-api
+ title: 🎮 Recently Played Games
+ cache: 1h
+ url: http://api.steampowered.com/IPlayerService/GetRecentlyPlayedGames/v0001/?key=${STEAM_API_KEY}&steamid=${STEAM_USERID}&format=json
+ template: |
+
+ {{ if eq .Response.StatusCode 200 }}
+ {{ $games := .JSON.Array "response.games" }}
+ {{ if gt (len $games) 0 }}
+
+ {{ range $games }}
+ -
+
+
+
+
+
+ {{ .String "name" }}
+
+
+
+ Last 2 weeks:
+ {{ if gt (toFloat (.Int "playtime_2weeks")) 60.0 }}
+ {{ printf "%.2f hrs" (div (toFloat (.Int "playtime_2weeks")) 60.0) }}
+ {{ else }}
+ {{ .Int "playtime_2weeks" }} mins
+ {{ end }}
+
+
+
+ {{ end }}
+
+ {{ else }}
+
No recently played games found.
+ {{ end }}
+ {{ else }}
+
An unexpected error occurred. Please try again later.
+ {{ end }}
+
\ No newline at end of file
diff --git a/config/widgets/custom/sunrise-sunset.yml b/config/widgets/custom/sunrise-sunset.yml
new file mode 100644
index 0000000..21fbfaa
--- /dev/null
+++ b/config/widgets/custom/sunrise-sunset.yml
@@ -0,0 +1,60 @@
+- type: custom-api
+ title: ☀️ Sunrise & Sunset
+ body-type: string
+ cache: 12h
+ options:
+ location: Quito, Ecuador
+ template: |
+ {{ $timeLayout := "3:04 PM" }}
+
+ {{/* Step 1: geocode the location */}}
+ {{ $loc := replaceAll " " "%20" (.Options.StringOr "location" "") }}
+ {{ $geoUrl := printf "https://geocoding-api.open-meteo.com/v1/search?name=%s&count=1&language=en&format=json" $loc }}
+ {{ $geo := newRequest $geoUrl | getResponse }}
+ {{ $results := $geo.JSON.Array "results" }}
+
+
+
+ {{ if eq (len $results) 0 }}
+ Location "{{ .Options.StringOr "location" "" }}" not found.
+ {{ else }}
+ {{ $lat := $geo.JSON.String "results.0.latitude" }}
+ {{ $lon := $geo.JSON.String "results.0.longitude" }}
+
+ {{/* Step 2: today's sunrise/sunset/daylight from Open-Meteo */}}
+ {{ $fcUrl := printf "https://api.open-meteo.com/v1/forecast?latitude=%s&longitude=%s&daily=sunrise,sunset,daylight_duration&forecast_days=1&timezone=auto" $lat $lon }}
+ {{ $fc := newRequest $fcUrl | getResponse }}
+
+ {{ $sunriseRaw := $fc.JSON.String "daily.sunrise.0" }}
+ {{ $sunsetRaw := $fc.JSON.String "daily.sunset.0" }}
+ {{ $daylight := $fc.JSON.Int "daily.daylight_duration.0" }}
+
+ {{ if or (eq $sunriseRaw "") (eq $sunsetRaw "") }}
+ No sunrise/sunset today (polar region).
+ {{ else }}
+ {{ $sunrise := $sunriseRaw | parseTime "2006-01-02T15:04" }}
+ {{ $sunset := $sunsetRaw | parseTime "2006-01-02T15:04" }}
+ {{ $hours := div $daylight 3600 }}
+ {{ $mins := div (mod $daylight 3600) 60 }}
+
+
+
+
+
+
{{ $sunrise.Format $timeLayout }}
+
Sunrise
+
+
+
+
{{ $hours }}h {{ $mins }}m
+
Daylight
+
+
+
+
+
{{ $sunset.Format $timeLayout }}
+
Sunset
+
+
+ {{ end }}
+ {{ end }}
diff --git a/config/widgets/custom/wikipedia-on-this-day.yml b/config/widgets/custom/wikipedia-on-this-day.yml
new file mode 100644
index 0000000..4181872
--- /dev/null
+++ b/config/widgets/custom/wikipedia-on-this-day.yml
@@ -0,0 +1,49 @@
+- type: custom-api
+ title: 💡 On This Day
+ cache: 6h
+ url: https://api.github.com/rate_limit
+ template: |
+ {{/* Top-level URL is a cheap dummy JSON; the real work is done inside the template via newRequest so we can compute today's date. Wikipedia's REST API requires a descriptive User-Agent per their policy (https://meta.wikimedia.org/wiki/User-Agent_policy) — an unset UA returns 403. */}}
+ {{ $month := now | formatTime "01" }}
+ {{ $day := now | formatTime "02" }}
+ {{ $url := concat "https://en.wikipedia.org/api/rest_v1/feed/onthisday/events/" $month "/" $day }}
+ {{
+ $resp := newRequest $url
+ | withHeader "Accept" "application/json"
+ | withHeader "User-Agent" "glance-dashboard/1.0 (+https://github.com/glanceapp/glance)"
+ | getResponse
+ }}
+
+ {{ if ne $resp.Response.StatusCode 200 }}
+ Failed to load Wikipedia events ({{ $resp.Response.Status }})
+ {{ else }}
+ {{ $events := $resp.JSON.Array "events" }}
+ {{ if eq (len $events) 0 }}
+ No events found for today.
+ {{ else }}
+
+ {{ range $events }}
+ {{ $year := .Int "year" }}
+ {{ $text := .String "text" }}
+ {{ $pages := .Array "pages" }}
+ {{ $link := "" }}
+ {{ if gt (len $pages) 0 }}
+ {{ $firstPage := index $pages 0 }}
+ {{ $link = $firstPage.String "content_urls.desktop.page" }}
+ {{ end }}
+ -
+
+
{{ $year }}
+
+ {{ if ne $link "" }}
+ {{ $text }}
+ {{ else }}
+ {{ $text }}
+ {{ end }}
+
+
+
+ {{ end }}
+
+ {{ end }}
+ {{ end }}
diff --git a/config/widgets/custom/xkcd.yml b/config/widgets/custom/xkcd.yml
new file mode 100644
index 0000000..58ebf67
--- /dev/null
+++ b/config/widgets/custom/xkcd.yml
@@ -0,0 +1,7 @@
+- type: custom-api
+ title: 💥 xkcd
+ cache: 2m
+ url: https://xkcd.com/info.0.json
+ template: |
+ {{ .JSON.String "title" }}
+
diff --git a/config/widgets/videos/youtube-subscriptions.yml b/config/widgets/videos/youtube-subscriptions.yml
index ac38a8c..75256d2 100644
--- a/config/widgets/videos/youtube-subscriptions.yml
+++ b/config/widgets/videos/youtube-subscriptions.yml
@@ -1,7 +1,7 @@
- type: videos
title: 📺 Subscriptions
limit: 100
- collapse-after-rows: 5
+ collapse-after-rows: 6
include-shorts: false
style: grid-cards
channels:
diff --git a/docker-compose.yml b/docker-compose.yml
index 591dd5f..6b9d05f 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -10,3 +10,8 @@ services:
environment:
TZ: ${TIMEZONE}
GITHUB_TOKEN: ${GITHUB_TOKEN}
+ LASTFM_USERNAME: ${LASTFM_USERNAME}
+ LASTFM_API_KEY: ${LASTFM_API_KEY}
+ STEAM_USERID: ${STEAM_USERID}
+ STEAM_API_KEY: ${STEAM_API_KEY}
+ STEAM_FRIENDS: ${STEAM_FRIENDS}