diff --git a/servers/eisen/configuration.nix b/servers/eisen/configuration.nix index 08c5db1..4110f68 100644 --- a/servers/eisen/configuration.nix +++ b/servers/eisen/configuration.nix @@ -211,6 +211,7 @@ in }; pages = import ./glance-pages.nix; }; + environmentFile = "/etc/secrets/glance.env"; }; caddy = { diff --git a/servers/eisen/glance-pages.nix b/servers/eisen/glance-pages.nix index 6eb3006..91c2899 100644 --- a/servers/eisen/glance-pages.nix +++ b/servers/eisen/glance-pages.nix @@ -1,3 +1,29 @@ +let + jellyfinConfig = + { + title, + library-name ? null, + mode, + }: + { + inherit title; + type = "custom-api"; + # url = "http://jellyfin.eisen.danbulant.cloud"; + frameless = true; + cache = "5m"; + options = { + inherit library-name mode; + base-url = "http://jellyfin.eisen.danbulant.cloud"; + api-key = "\${JELLYFIN_KEY}"; + user-name = "dan"; + item-count = "10"; + small-column = false; + show-thumbnail = true; + thumbnail-aspect-ratio = "default"; + }; + template = builtins.readFile ./glance/jellyfin-latest; + }; +in [ { name = "Home"; @@ -17,6 +43,24 @@ } ]; } + { + + # - type: custom-api + # title: "Jellyfin/Emby Stats" + # base-url: ${JELLYFIN_URL} + # options: + # url: ${JELLYFIN_URL} + # key: ${JELLYFIN_API_KEY} + # + type = "custom-api"; + title = "Jellyfin Stats"; + # url = "http://jellyfin.eisen.danbulant.cloud"; + options = { + url = "http://jellyfin.eisen.danbulant.cloud"; + key = "\${JELLYFIN_KEY}"; + }; + template = builtins.readFile ./glance/jellyfin-stats; + } { type = "custom-api"; title = "Uptime Kuma"; @@ -28,61 +72,24 @@ }; }; cache = "10m"; - template = '' - {{ $hb := .Subrequest "heartbeats" }} - - {{ if not (.JSON.Exists "publicGroupList") }} -

Error reading response

- {{ else if eq (len (.JSON.Array "publicGroupList")) 0 }} -

No monitors found

- {{ else }} - - - {{ end }} - ''; + template = builtins.readFile ./glance/uptime-kuma; + } + { + type = "custom-api"; + title = "Tailscale"; + title-url = "https://login.tailscale.com/admin/machines"; + url = "https://api.tailscale.com/api/v2/tailnet/-/devices"; + headers = { + Authorization = "Bearer \${TAILSCALE_API_KEY}"; + }; + cache = "10m"; + options = { + # collapseAfter: 4 + # disableOfflineIndicator: true + # disableUpdateIndicator: true + # prioritiseTags: true + }; + template = builtins.readFile ./glance/tailscale; } ]; } @@ -149,6 +156,25 @@ } ]; } + (jellyfinConfig { + title = "Movies"; + mode = "nextup"; + }) + { + type = "group"; + widgets = [ + (jellyfinConfig { + title = "Shows"; + library-name = "Shows"; + mode = "latest"; + }) + (jellyfinConfig { + title = "Movies"; + library-name = "Movies"; + mode = "latest"; + }) + ]; + } # { # type = "docker-containers"; # } @@ -163,17 +189,27 @@ units = "metric"; "hour-format" = "24h"; } + # { + # type = "releases"; + # cache = "1d"; + # repositories = [ + # "glanceapp/glance" + # "go-gitea/gitea" + # "immich-app/immich" + # "syncthing/syncthing" + # "9001/copyparty" + # "caddyserver/caddy" + # ]; + # } { - type = "releases"; - cache = "1d"; - repositories = [ - "glanceapp/glance" - "go-gitea/gitea" - "immich-app/immich" - "syncthing/syncthing" - "9001/copyparty" - "caddyserver/caddy" - ]; + type = "custom-api"; + title = "xkcd"; + cache = "10m"; + url = "https://xkcd.com/info.0.json"; + template = '' + {{ .JSON.String "title" }} + + ''; } { type = "custom-api"; diff --git a/servers/eisen/glance/jellyfin-latest b/servers/eisen/glance/jellyfin-latest new file mode 100644 index 0000000..055e661 --- /dev/null +++ b/servers/eisen/glance/jellyfin-latest @@ -0,0 +1,231 @@ + +{{/* Required config options */}} +{{ $baseURL := .Options.StringOr "base-url" "" }} +{{ $apiKey := .Options.StringOr "api-key" "" }} +{{ $userName := .Options.StringOr "user-name" "" }} + +{{/* Required config options for "latest" mode */}} +{{ $libraryName := .Options.StringOr "library-name" "" }} + +{{/* Optional config options */}} +{{ $mode := .Options.StringOr "mode" "latest" }} +{{ $itemCount := .Options.StringOr "item-count" "10" }} +{{ $mediaTypes := .Options.StringOr "media-types" "Movie,Episode,MusicAlbum" }} +{{ $thumbAspectRatio := .Options.StringOr "thumbnail-aspect-ratio" "" }} +{{ $isSmallColumn:= .Options.BoolOr "small-column" false }} +{{ $showThumbnail := .Options.BoolOr "show-thumbnail" false }} +{{ $showProgressBar := .Options.BoolOr "progress-bar" true }} + +{{/* Error message template */}} +{{ define "errorMsg" }} +
+
ERROR
+ + + +
+

{{ . }}

+{{ end }} + +{{/* Check required fields */}} +{{ if or (eq $baseURL "") (eq $apiKey "") (eq $userName "") (eq $mode "") (and (eq $mode "latest") (eq $libraryName "")) }} + {{ template "errorMsg" "Some required options are not set." }} +{{ else }} + + {{/* Fetch user ID */}} + {{ $userID := "" }} + {{ $usersCall := newRequest (print $baseURL "/Users") + | withParameter "api_key" $apiKey + | withHeader "Accept" "application/json" + | getResponse }} + + {{ range $i, $user := $usersCall.JSON.Array "" }} + {{ if eq ($user.String "Name") $userName }} + {{ $userID = $user.String "Id" }} + {{ break }} + {{ end }} + {{ end }} + {{ if eq $userID "" }} + {{ template "errorMsg" (printf "User '%s' not found." $userName) }} + {{ else }} + + {{ $items := "" }} + + {{ if eq $mode "latest" }} + + {{/* Fetch library ID */}} + {{ $libraryID := "" }} + {{ $userViewsCall := newRequest (print $baseURL "/UserViews") + | withParameter "api_key" $apiKey + | withParameter "userId" $userID + | withHeader "Accept" "application/json" + | getResponse }} + + {{ range $i, $item := $userViewsCall.JSON.Array "Items" }} + {{ if eq ($item.String "Name") $libraryName }} + {{ $libraryID = $item.String "Id" }} + {{ break }} + {{ end }} + {{ end }} + + {{ if eq $libraryID "" }} + {{ template "errorMsg" (printf "Library '%s' not found." $libraryName) }} + {{ else }} + {{/* Fetch latest items */}} + {{ $latestCall := newRequest (print $baseURL "/Users/" $userID "/Items/Latest") + | withParameter "api_key" $apiKey + | withParameter "Limit" $itemCount + | withParameter "ParentId" $libraryID + | withParameter "IncludeItemTypes" $mediaTypes + | withParameter "GroupItems" "true" + | withHeader "Accept" "application/json" + | getResponse }} + {{ $items = $latestCall.JSON.Array "" }} + {{ end }} + + {{ else if eq $mode "nextup" }} + + {{/* Fetch next up items */}} + {{ $nextUpCall := newRequest (print $baseURL "/Shows/NextUp") + | withParameter "api_key" $apiKey + | withParameter "UserId" $userID + | withParameter "Limit" $itemCount + | withParameter "EnableResumable" "true" + | withHeader "Accept" "application/json" + | getResponse }} + {{ $items = $nextUpCall.JSON.Array "Items" }} + + {{ else }} + {{ template "errorMsg" "Unknown mode, expected 'latest' or 'nextup'" }} + {{ end }} + + {{ if eq (len $items) 0 }} +

No items found, start streaming something!

+ {{ else }} + + {{/* Display the item carousel */}} + + {{ end }} + + {{ end }} + +{{ end }} diff --git a/servers/eisen/glance/jellyfin-stats b/servers/eisen/glance/jellyfin-stats new file mode 100644 index 0000000..8254779 --- /dev/null +++ b/servers/eisen/glance/jellyfin-stats @@ -0,0 +1,43 @@ + +{{ $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 -}} diff --git a/servers/eisen/glance/tailscale b/servers/eisen/glance/tailscale new file mode 100644 index 0000000..177f261 --- /dev/null +++ b/servers/eisen/glance/tailscale @@ -0,0 +1,106 @@ + + diff --git a/servers/eisen/glance/uptime-kuma b/servers/eisen/glance/uptime-kuma new file mode 100644 index 0000000..8ffc278 --- /dev/null +++ b/servers/eisen/glance/uptime-kuma @@ -0,0 +1,54 @@ + +{{ $hb := .Subrequest "heartbeats" }} + +{{ if not (.JSON.Exists "publicGroupList") }} +

Error reading response

+{{ else if eq (len (.JSON.Array "publicGroupList")) 0 }} +

No monitors found

+{{ else }} + + +{{ end }} diff --git a/servers/fern/configuration.nix b/servers/fern/configuration.nix index d6f85a8..05323f0 100644 --- a/servers/fern/configuration.nix +++ b/servers/fern/configuration.nix @@ -71,6 +71,7 @@ nvitop basalt-monado cudaPackages.cuda_nvcc + # llama-cpp (llama-cpp.overrideAttrs (prevAttrs: { cmakeFlags = with lib; [ # -march=native is non-deterministic; override with platform-specific flags if needed @@ -80,18 +81,18 @@ (cmakeBool "LLAMA_BUILD_TESTS" false) (cmakeBool "LLAMA_OPENSSL" true) (cmakeBool "BUILD_SHARED_LIBS" true) - (cmakeBool "GGML_BLAS" false) + # (cmakeBool "GGML_BLAS" false) (cmakeBool "GGML_LTO" true) (cmakeBool "GGML_CLBLAST" true) (cmakeBool "GGML_CUDA" true) (cmakeBool "GGML_CUDA_GRAPHS" true) (cmakeBool "GGML_CUDA_F16" true) (cmakeBool "GGML_CUDA_FA_ALL_QUANTS" true) - (cmakeBool "GGML_HIP" false) - (cmakeBool "GGML_METAL" false) - (cmakeBool "GGML_RPC" false) - (cmakeBool "GGML_VULKAN" false) - (cmakeFeature "LLAMA_BUILD_NUMBER" "8770") + # (cmakeBool "GGML_HIP" false) + # (cmakeBool "GGML_METAL" false) + # (cmakeBool "GGML_RPC" false) + # (cmakeBool "GGML_VULKAN" false) + (cmakeFeature "LLAMA_BUILD_NUMBER" "8667") (cmakeFeature "CMAKE_CUDA_ARCHITECTURES" "120") ]; }))