From 8ae16f5277c594eb70aacaf769a4a8ad49007584 Mon Sep 17 00:00:00 2001 From: Crony Akatsuki Date: Sun, 5 Oct 2025 21:17:04 +0200 Subject: [PATCH] feat(glance): add more widgets. --- modules/servers/tyr/glance.nix | 216 ++++++++++++++++++++++++++++++++- secrets/glance.age | Bin 1484 -> 2087 bytes 2 files changed, 215 insertions(+), 1 deletion(-) diff --git a/modules/servers/tyr/glance.nix b/modules/servers/tyr/glance.nix index 9f1ac73..aa6b26d 100644 --- a/modules/servers/tyr/glance.nix +++ b/modules/servers/tyr/glance.nix @@ -295,12 +295,47 @@ "syncthing/syncthing" ]; } + { + type = "custom-api"; + title = "GitHub Notifications"; + url = "https://api.github.com/notifications?all=true&per_page=20"; + headers = { + Authorization = "Bearer \${GITHUB_TOKEN}"; + Accept = "application/vnd.github+json"; + }; + template = '' + + ''; + } ]; } ]; } { - name = "gaming"; + name = "Gaming"; columns = [ { size = "small"; @@ -362,6 +397,185 @@ } ]; } + { + name = "SelfHosted Services"; + columns = [ + { + size = "small"; + widgets = [ + { + type = "custom-api"; + title = "Audiobookshelf"; + title-url = "\${AUDIOBOOKSHELF_URL}"; + options = { + base-url = "\${AUDIOBOOKSHELF_URL}"; + api-key = "\${AUDIOBOOKSHELF_KEY}"; + }; + cache = "5m"; + template = '' + {{ $baseURL := .Options.StringOr "base-url" "" }} + {{ $apiKey := .Options.StringOr "api-key" "" }} + + {{ define "errorMsg" }} +
+
ERROR
+ + + +
+

{{ . }}

+ {{ end }} + + {{ $bearer := printf "Bearer %s" $apiKey }} + {{ $librariesRequestURL := concat $baseURL "/api/libraries" }} + {{ $librariesResponse := newRequest $librariesRequestURL + | withHeader "Content-Type" "application/json" + | withHeader "Authorization" $bearer + | getResponse }} + + {{ if $librariesResponse.JSON.Exists "libraries" }} + {{ $all_libraries := $librariesResponse.JSON.Array "libraries" }} + + {{ $books_count := 0 }} + {{ $books_duration := 0 }} + {{ $podcasts_count := 0 }} + {{ $podcasts_duration := 0 }} + + {{ range $library := $all_libraries }} + {{ $lib_id := $library.String "id" }} + {{ $lib_request_url := concat $baseURL "/api/libraries/" $lib_id "/stats"}} + {{ $lib_stats := newRequest $lib_request_url + | withHeader "Content-Type" "application/json" + | withHeader "Authorization" $bearer + | getResponse }} + {{ $lib_type := $library.String "mediaType" }} + {{ $lib_item_count := $lib_stats.JSON.Int "totalItems" }} + {{ $lib_total_duration := $lib_stats.JSON.Int "totalDuration" }} + {{ if eq $lib_type "book" }} + {{ $books_count = add $books_count $lib_item_count }} + {{ $books_duration = add $books_duration $lib_total_duration }} + {{ else if eq $lib_type "podcast" }} + {{ $podcasts_count = add $podcasts_count $lib_item_count }} + {{ $podcasts_duration = add $podcasts_duration $lib_total_duration }} + {{ end }} + {{ end }} + + {{ $books_duration = duration (concat (printf "%d" $books_duration) "s") }} + {{ $podcasts_duration = duration (concat (printf "%d" $podcasts_duration) "s") }} + +
+
+
+
{{ $books_count }}
+
Books
+
+
+
{{ $books_duration }}
+
Duration
+
+
+
{{ $podcasts_count }}
+
Podcasts
+
+
+
{{ $podcasts_duration }}
+
Duration
+
+
+
+ {{ else }} + {{ template "errorMsg" "Could not fetch data from API!" }} + {{ end }} + ''; + } + { + type = "custom-api"; + title = "Immich Stats"; + cache = "1d"; + url = "https://immich.cronyakatsuki.xyz/api/server/statistics"; + headers = { + x-api-key = "\${IMMICH_API_KEY}"; + Accept = "application/json"; + }; + template = '' +
+
+
{{ .JSON.Int "photos" | formatNumber }}
+
PHOTOS
+
+
+
{{ .JSON.Int "videos" | formatNumber }}
+
VIDEOS
+
+
+
{{ div (.JSON.Int "usage" | toFloat) 1073741824 | toInt | formatNumber }}GB
+
USAGE
+
+
+ ''; + } + { + type = "custom-api"; + title = "Jellyfin Stats"; + base-url = "\${JELLYFIN_URL}"; + options = { + url = "\${JELLYFIN_URL}"; + key = "\${JELLYFIN_KEY}"; + }; + template = '' + {{ $url := .Options.StringOr "url" "" }} + {{ $key := .Options.StringOr "key" "" }} + + {{- if or (eq $url "") (eq $key "") -}} + +

Error: The URL or API Key was not configured in the widget options.

+ + {{- else -}} + + {{- $requestUrl := printf "%s/emby/Items/Counts?api_key=%s" $url $key -}} + {{- $jellyfinData := newRequest $requestUrl | getResponse -}} + + {{- if eq $jellyfinData.Response.StatusCode 200 -}} +
+
+ +
+
{{ $jellyfinData.JSON.Int "MovieCount" | formatNumber }}
+
Movies
+
+ +
+
{{ $jellyfinData.JSON.Int "SeriesCount" | formatNumber }}
+
TV Shows
+
+ +
+
{{ $jellyfinData.JSON.Int "EpisodeCount" | formatNumber }}
+
Episodes
+
+ +
+
{{ $jellyfinData.JSON.Int "SongCount" | formatNumber }}
+
Songs
+
+ +
+
+ {{- else -}} +

Failed: {{ $jellyfinData.Response.Status }}

+ {{- end -}} + {{- end -}} + ''; + } + ]; + } + { + size = "full"; + widgets = [ + ]; + } + ]; + } ]; }; }; diff --git a/secrets/glance.age b/secrets/glance.age index 43efa986fdb1625173654c19fae17d4f6423a792..3b62064f748c9aa7786942e70d2b8a3eeec9bf27 100644 GIT binary patch delta 2008 zcmX@ZyXLz>0U$S+Q}jh*tj0(?!%EJ9L)47|e9OACBL z(kn7^Q_Krey~;!VLNZ)U+#T~Pd=mYWGTq82pJf!UPt0-h$qfiA%J*_I3d<`GcGY$@ z@hD5R@X08z$S>D+t}rZ0^z?KuD9i}tGS)6JD+^A}OGykY@yv}#HOtEnb=OWR53#Jw z39JYzcF77dGEU1X4KlDmkAcD@U+400W-$`$;)3JtQ$+#I7^ixU$IQ%X}RQw=MEeao^E&3&q}y~|u2 z>z)0z16{qt!n3(5jY2X@Ln9J%OMMIsOwBU&z0$S)GYZlJ3evLjioNwiEQ|g0i^7UL ze3Q|wbN7pi3`$oBH#R9QuQU$|2-o&6FwJo+h;np~vh*oQ$;og@%GEcHEDJL#E!NHo z%*p3U^tVWJF|Dc(C~&T@^bXF+2{X&_jdJu#b1?}B*RLwiP0g#yO3zGnObN(Gw=OM3 zKguUiAvIaQuprypIITR-xY8upy`m~7r^qnO&9BPXz$mw@sysBv!o)o!Bs0R7%gw}7 z->WjoInp)CwEy7J1~Q=F%FuPb4w+GX@@e{Er>*rJ*n6WXW!{1YRk&+~jXbBov>6^0qug>^rv*>+6j$ezpn-`o$>m#*h5Sf#`loO(Kn zNBVi3tmxMmUeiev)EPgQ+c{>u`4eg5m(8%pU-|m-DB%df6Smh{vrnntJZoI*-Jjt6 zTzFq+vtphmZ{x49Pp1W*3$3u5Us=BUU$R*1vqBz2m+Yf1+IAw50XsDpaddaZzkDXS zw#srz>!EoYwo5im+_K-tx_-;icUpHc9!)>LojZ-~SPI`|F;T7gYA@dC*1g?O4&EJzYF}R8Ev@h!@G&~hT1g(EnQouoL%Gd~r8+_kqp%cQv&qwl=fZ!~qeu;>MeoFn?Pra3?VaF6lNe(?j&tD5#Xty0g~Q(rE| z#CrNxO-r{=Ty}~%1p1qCI za_-_*%g{N&hFqk9?l?#|WRjprYq zRG#%J>+$K^pVd2hXQ#LB zPwB=Y*X;V;Yqpdqo(ww8SgiKJHb2ruX3>|)`~Tcm)mXMXFR<=dYI0eejc#Y;Tdhag zUN6=^;cl5AWOS}IsOQ_M|cCjI7K{ z_cb>3DGhOp^6*cpDhiGYsWdbwH+9J z@2uidAK%idpfHnc54Vg0_khG4gL1AwZ^yh66T{T7(uh=Zch3q>$0FBq=d42gj12AI zVEv>h$3Xoc!<0O8({gm%{L2kO+{+bmGLkJVy#tH%Q=!YhIzoJ)&x%QL(TElMN(9jn}3i%negBTOwyjl2t8O)|9& zoWm;pLp{-LOLq12^L126uSoJuHZ3smuF!T5jmRy}$?*&E%QOuLH802u2?)-q%rwa{ zadOEH2?^y&%}NXQF;CB|Oe@VP@v{gHu?UK&h;mFVcP}r?bPi9Aa?dkx4{&jHkBCIK ztuV>gyC_h>*|$6}IjkzV(lgbl$~B_OD z%-72`C9yD9-!;J3Co0&i+{M$(r#vgqAT7+?EyJSB$Iz)H(=yxKqbM8QwkU&K$EtFL zV85iW@?gWld^byTL(f2qC=Y*=beDAh$f(S+s>)nCF{M-u9%8;@Y%WxBP+uZ%4B7@QuJSz$UQ_8|~ z%}i1=GYvgVOuYgf&B8(q1A_uf1N6fT%hEEOa|8WLJOVAaQVhLAL$v*T%-nKv!m~28 zD-*rUEG*JIElk3*v?GnoP09;Bs?sA0ozgIDOH0v@@(EN3anHy}(N7OGO!7)LN{fo9 zOieX$DGtdl%QDI`PEILx3(U!Jb_sMh%gW};2=fezFtoJvtFmy*EJ%*B2n;MQi}VOL zuSoJv@^gwXb&AN&v2ZL24ZuhxRe?^KQRNE7m5zmlrbQuTX6`0lkzvV|E*%B*^ylSk#5D2fsvIZd0yuEIl)DS;Z52MP{*}&t zxhDSE*-7rDCFxwcy1EJx*%{7}g(1OZMM)L87LLU^5xJ4x!A@xr=IOtb0;e>Kz;V@+pH$q|vX= zj^ndk|N2xP^C>)fn5SEZD`MZaJF|}_DK(v6ug{XjrEXwua5>ku$@l&~-qxhLjgK#U z-@#I{`h%S8vcq@HCtsNq`M~*Mw`@g8+ACQe#~Wu~cF1u*Z?)RF+i>%Qmua)ApZLsI z>#1CO|Nhxtd7&Ei9~x|2g$wo>U9_?NqkO{4wrrM`>c`D|g*zvh>u8xN)AJrY|zS zzRw|F{qmEP2Vu__g=|UOrgTdxH}j&9y`z#=Pbq_XX7ln>tpU(mmY~ eW3_GTnU}&-_g(mXq4V49@Y6{P4(NS)vKau>nGW&*