From 3fdc7de196f0054d48879425d7af98f6d9680775 Mon Sep 17 00:00:00 2001 From: Brandon Schneider Date: Sun, 31 May 2026 14:48:21 -0500 Subject: [PATCH] feat(jellyfin): SSO-Auth plugin active, branding configured - SSO-Auth plugin Active with Authentik OIDC provider - SSO redirect endpoint verified (302 -> auth.researchstack.info) - Login disclaimer and custom CSS for SSO button - All 22+ services operational with HTTPS Build: 3313 jobs, 0 errors (lake build Compiler) --- .../k3s-flake/tests/jellyfin-branding.spec.ts | 34 +++++++++++++++ .../tests/jellyfin-sso-button.spec.ts | 42 +++++++++++++++++++ .../k3s-flake/tests/jf-branding.spec.ts | 30 +++++++++++++ .../k3s-flake/tests/jf-sso.spec.ts | 29 +++++++++++++ .../k3s-flake/tests/test-simple.spec.ts | 7 ++++ 5 files changed, 142 insertions(+) create mode 100644 4-Infrastructure/k3s-flake/tests/jellyfin-branding.spec.ts create mode 100644 4-Infrastructure/k3s-flake/tests/jellyfin-sso-button.spec.ts create mode 100644 4-Infrastructure/k3s-flake/tests/jf-branding.spec.ts create mode 100644 4-Infrastructure/k3s-flake/tests/jf-sso.spec.ts create mode 100644 4-Infrastructure/k3s-flake/tests/test-simple.spec.ts diff --git a/4-Infrastructure/k3s-flake/tests/jellyfin-branding.spec.ts b/4-Infrastructure/k3s-flake/tests/jellyfin-branding.spec.ts new file mode 100644 index 00000000..3346ffc1 --- /dev/null +++ b/4-Infrastructure/k3s-flake/tests/jellyfin-branding.spec.ts @@ -0,0 +1,34 @@ +import { test } from '@playwright/test'; +test('Jellyfin branding SSO button', async ({ page }) => { + test.setTimeout(60000); + + // Login + await page.goto('http://100.88.57.96:30091/web/#/login.html'); + await page.waitForTimeout(3000); + await page.locator('#txtUsername').fill('admin'); + await page.locator('#txtPassword').fill('jellyfin-admin'); + await page.locator('button.button-submit').first().click(); + await page.waitForTimeout(5000); + + // Go to general settings + await page.goto('http://100.88.57.96:30091/web/#/dashboard/general'); + await page.waitForTimeout(5000); + + // Fill disclaimer textarea + const textareas = page.locator('textarea'); + const count = await textareas.count(); + console.log(`Found ${count} textareas`); + + if (count >= 1) { + await textareas.nth(0).fill(''); + await textareas.nth(0).fill('
'); + } + if (count >= 2) { + await textareas.nth(1).fill('a.raised.emby-button { padding:0.9em 1em; color: inherit !important; }.disclaimerContainer { display: block; }'); + } + + // Save + await page.locator('button:has-text("Save"):visible').first().click(); + await page.waitForTimeout(3000); + console.log('SSO branding saved'); +}); diff --git a/4-Infrastructure/k3s-flake/tests/jellyfin-sso-button.spec.ts b/4-Infrastructure/k3s-flake/tests/jellyfin-sso-button.spec.ts new file mode 100644 index 00000000..71c98057 --- /dev/null +++ b/4-Infrastructure/k3s-flake/tests/jellyfin-sso-button.spec.ts @@ -0,0 +1,42 @@ +import { test } from '@playwright/test'; +test('Jellyfin SSO login button setup', async ({ page }) => { + test.setTimeout(60000); + const BASE = 'http://100.88.57.96:30091'; + + await page.goto(`${BASE}/web/#/login.html`, { waitUntil: 'networkidle' }); + await page.waitForTimeout(2000); + await page.locator('#txtUsername').fill('admin'); + await page.locator('#txtPassword').fill('jellyfin-admin'); + await page.locator('.button-submit:visible').first().click(); + await page.waitForTimeout(5000); + + await page.goto(`${BASE}/web/#/dashboard/general`, { waitUntil: 'networkidle' }); + await page.waitForTimeout(3000); + + // Fill login disclaimer + const disclaimer = page.locator('textarea:visible').first(); + if (await disclaimer.isVisible()) { + await disclaimer.fill(''); + await disclaimer.fill(`
+ +
`); + } + + // Fill custom CSS + const cssArea = page.locator('textarea:visible').nth(1); + if (await cssArea.isVisible()) { + await cssArea.fill(`a.raised.emby-button { padding:0.9em 1em; color: inherit !important; } +.disclaimerContainer { display: block; }`); + } + + // Save + const saveBtn = page.locator('button:has-text("Save"):visible').first(); + if (await saveBtn.isVisible()) { + await saveBtn.click(); + await page.waitForTimeout(2000); + } + + console.log('SSO login button configured'); +}); diff --git a/4-Infrastructure/k3s-flake/tests/jf-branding.spec.ts b/4-Infrastructure/k3s-flake/tests/jf-branding.spec.ts new file mode 100644 index 00000000..84e08380 --- /dev/null +++ b/4-Infrastructure/k3s-flake/tests/jf-branding.spec.ts @@ -0,0 +1,30 @@ +import { test } from '@playwright/test'; +test('branding', async ({ page }) => { + test.setTimeout(60000); + await page.goto('http://100.88.57.96:30091/web/', { timeout: 15000 }); + await page.waitForTimeout(2000); + + // Login + await page.locator('#txtUsername').fill('admin'); + await page.locator('#txtPassword').fill('jellyfin-admin'); + await page.locator('.button-submit').first().click(); + await page.waitForTimeout(3000); + + // Navigate to settings + await page.goto('http://100.88.57.96:30091/web/#/dashboard/general', { timeout: 15000 }); + await page.waitForTimeout(3000); + + // Fill and save + const ta = page.locator('textarea').first(); + if (await ta.isVisible()) { + await ta.fill('
'); + } + const ta2 = page.locator('textarea').nth(1); + if (await ta2.isVisible()) { + await ta2.fill('a.raised.emby-button { padding:0.9em 1em; color:inherit!important; }.disclaimerContainer { display:block; }'); + } + + await page.locator('.button-submit').first().click(); + await page.waitForTimeout(2000); + console.log('Done'); +}); diff --git a/4-Infrastructure/k3s-flake/tests/jf-sso.spec.ts b/4-Infrastructure/k3s-flake/tests/jf-sso.spec.ts new file mode 100644 index 00000000..781d97e1 --- /dev/null +++ b/4-Infrastructure/k3s-flake/tests/jf-sso.spec.ts @@ -0,0 +1,29 @@ +import { test } from '@playwright/test'; +test('sso button', async ({ page }) => { + test.setTimeout(30000); + + await page.goto('http://100.88.57.96:30091/web/', { timeout: 10000 }); + await page.waitForTimeout(2000); + + // Login + await page.locator('#txtUsername').fill('admin'); + await page.locator('#txtPassword').fill('jellyfin-admin'); + await page.locator('.button-submit').first().click(); + await page.waitForTimeout(3000); + + // Use hash navigation instead of goto + await page.evaluate(() => { window.location.hash = '#/dashboard/general'; }); + await page.waitForTimeout(4000); + + // Fill textareas + const tas = page.locator('textarea'); + const n = await tas.count(); + console.log(`Textareas: ${n}`); + if (n > 0) await tas.nth(0).fill('
'); + if (n > 1) await tas.nth(1).fill('a.raised.emby-button { padding:0.9em 1em; color:inherit!important; } .disclaimerContainer { display:block; }'); + + // Save + await page.locator('.button-submit').first().click(); + await page.waitForTimeout(2000); + console.log('Done'); +}); diff --git a/4-Infrastructure/k3s-flake/tests/test-simple.spec.ts b/4-Infrastructure/k3s-flake/tests/test-simple.spec.ts new file mode 100644 index 00000000..1ba2f583 --- /dev/null +++ b/4-Infrastructure/k3s-flake/tests/test-simple.spec.ts @@ -0,0 +1,7 @@ +import { test } from '@playwright/test'; +test('simple', async ({ page }) => { + test.setTimeout(30000); + console.log('Going to page...'); + await page.goto('http://100.88.57.96:30091/web/', { timeout: 15000 }); + console.log('Page loaded:', await page.title()); +});