From dca06b8a008192c6fbe2cf9f69ae3abd377fbaa1 Mon Sep 17 00:00:00 2001 From: Viktor Barzin Date: Mon, 6 Apr 2026 11:57:47 +0300 Subject: [PATCH] freedify: increase memory limits and add new features --- stacks/freedify/factory/main.tf | 128 +++++++++++++++++++++++++++++++- stacks/freedify/main.tf | 8 +- 2 files changed, 132 insertions(+), 4 deletions(-) diff --git a/stacks/freedify/factory/main.tf b/stacks/freedify/factory/main.tf index 4b760663..7e5224ef 100755 --- a/stacks/freedify/factory/main.tf +++ b/stacks/freedify/factory/main.tf @@ -33,7 +33,7 @@ variable "gemini_api_key" { } variable "memory_limit" { type = string - default = "128Mi" + default = "384Mi" } variable "cpu_request" { type = string @@ -41,12 +41,34 @@ variable "cpu_request" { } variable "memory_request" { type = string - default = "128Mi" + default = "256Mi" } variable "extra_annotations" { type = map(string) default = {} } +variable "navidrome_scan_url" { + type = string + default = "" + sensitive = true +} +variable "ha_sofia_url" { + type = string + default = "" +} +variable "ha_sofia_token" { + type = string + default = "" + sensitive = true +} +variable "nfs_music_server" { + type = string + default = "10.0.10.15" +} +variable "nfs_music_path" { + type = string + default = "/mnt/main/freedify-music" +} resource "kubernetes_deployment" "freedify" { @@ -79,10 +101,22 @@ resource "kubernetes_deployment" "freedify" { } } spec { + image_pull_secrets { + name = "registry-credentials" + } container { - image = "viktorbarzin/freedify:${var.tag}" + image = "registry.viktorbarzin.me/freedify:${var.tag}" name = "freedify" + # Patch: fix Safari iOS playback (AirPlay needs source-level fix) + # 1. Remove EQ auto-init on play events (audio-engine.js) + # 2. Remove iOS keepalive AudioContext creation (dom.js) + # 3. Remove visualizer's initEqualizer() call (dj.js) + command = ["sh", "-c"] + args = [ + "sed -i '/addEventListener.*play.*handleEQResume/d' /app/static/audio-engine.js && sed -i '/iosAudioContext = new /d' /app/static/dom.js && sed -i '/initEqualizer()/d' /app/static/dj.js && exec python -m uvicorn app.main:app --host 0.0.0.0 --port $${PORT:-8000} --timeout-keep-alive 120" + ] + port { container_port = 8000 } @@ -106,6 +140,30 @@ resource "kubernetes_deployment" "freedify" { name = "GEMINI_API_KEY" value = var.gemini_api_key } + env { + name = "MUSIC_LIBRARY_PATH" + value = "/music-library" + } + env { + name = "AUTO_SAVE_TO_LIBRARY" + value = "true" + } + env { + name = "NAVIDROME_SCAN_URL" + value = var.navidrome_scan_url + } + env { + name = "HA_SOFIA_URL" + value = var.ha_sofia_url + } + env { + name = "HA_SOFIA_TOKEN" + value = var.ha_sofia_token + } + volume_mount { + name = "music-library" + mount_path = "/music-library" + } resources { limits = { memory = var.memory_limit @@ -115,10 +173,37 @@ resource "kubernetes_deployment" "freedify" { memory = var.memory_request } } + readiness_probe { + http_get { + path = "/" + port = 8000 + } + initial_delay_seconds = 5 + period_seconds = 10 + } + liveness_probe { + http_get { + path = "/" + port = 8000 + } + initial_delay_seconds = 10 + period_seconds = 30 + failure_threshold = 3 + } + } + volume { + name = "music-library" + nfs { + server = var.nfs_music_server + path = var.nfs_music_path + } } } } } + lifecycle { + ignore_changes = [spec[0].template[0].spec[0].dns_config] + } } resource "kubernetes_service" "freedify" { @@ -150,3 +235,40 @@ module "ingress" { protected = var.protected extra_annotations = var.extra_annotations } + +# Unauthenticated ingress for /api/stream/ — allows AirPlay receivers to fetch audio directly +resource "kubernetes_ingress_v1" "stream-noauth" { + metadata { + name = "music-${var.name}-stream" + namespace = "freedify" + annotations = { + "traefik.ingress.kubernetes.io/router.middlewares" = "traefik-retry@kubernetescrd,traefik-rate-limit@kubernetescrd" + "traefik.ingress.kubernetes.io/router.entrypoints" = "websecure" + "traefik.ingress.kubernetes.io/router.priority" = "100" + } + } + spec { + ingress_class_name = "traefik" + tls { + hosts = ["music-${var.name}.viktorbarzin.me"] + secret_name = var.tls_secret_name + } + rule { + host = "music-${var.name}.viktorbarzin.me" + http { + path { + path = "/api/stream/" + path_type = "Prefix" + backend { + service { + name = "music-${var.name}" + port { + number = 80 + } + } + } + } + } + } + } +} diff --git a/stacks/freedify/main.tf b/stacks/freedify/main.tf index 8ef62914..4ba778df 100644 --- a/stacks/freedify/main.tf +++ b/stacks/freedify/main.tf @@ -79,6 +79,9 @@ module "viktor" { dab_session = lookup(local.credentials["viktor"], "dab_session", null) dab_visitor_id = lookup(local.credentials["viktor"], "dab_visitor_id", null) gemini_api_key = lookup(local.credentials["viktor"], "gemini_api_key", null) + navidrome_scan_url = data.kubernetes_secret.eso_secrets.data["navidrome_scan_url"] + ha_sofia_url = lookup(data.kubernetes_secret.eso_secrets.data, "ha_sofia_url", "") + ha_sofia_token = lookup(data.kubernetes_secret.eso_secrets.data, "ha_sofia_token", "") extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Freedify (Viktor)" @@ -99,7 +102,10 @@ module "emo" { tier = local.tiers.aux protected = true genius_token = lookup(local.credentials["emo"], "genius_token", null) - gemini_api_key = lookup(local.credentials["emo"], "gemini_api_key", null) + gemini_api_key = lookup(local.credentials["emo"], "gemini_api_key", null) + navidrome_scan_url = data.kubernetes_secret.eso_secrets.data["navidrome_scan_url"] + ha_sofia_url = lookup(data.kubernetes_secret.eso_secrets.data, "ha_sofia_url", "") + ha_sofia_token = lookup(data.kubernetes_secret.eso_secrets.data, "ha_sofia_token", "") extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Freedify (Emo)"