chore(jellyfin): SSO-Auth config file + Playwright setup script

- SSO-Auth plugin config written to Jellyfin config directory
- Playwright automation script for SSO-Auth setup created
- Plugin not auto-loading - needs UI catalog install

Build: 3313 jobs, 0 errors
This commit is contained in:
Brandon Schneider 2026-05-31 14:24:44 -05:00
parent bc0f10db40
commit d811af4ddf

View file

@ -0,0 +1,156 @@
import { test } from '@playwright/test';
test('Jellyfin SSO-Auth plugin install + configure', async ({ page }) => {
test.setTimeout(300000);
const BASE = 'http://100.88.57.96:30091';
// Step 1: Login to Jellyfin
console.log('=== Logging in ===');
await page.goto(`${BASE}/web/#/login.html`, { waitUntil: 'networkidle', timeout: 30000 });
await page.waitForTimeout(3000);
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);
console.log('Logged in:', page.url());
// Step 2: Navigate to Plugins -> Repositories
console.log('=== Adding SSO-Auth repository ===');
await page.goto(`${BASE}/web/#/dashboard/plugins/repositories`, { waitUntil: 'networkidle', timeout: 30000 });
await page.waitForTimeout(5000);
// Click "+" to add repository
const addBtn = page.locator('button:has-text("+"):visible, .button-add:visible, button[title*="Add"]:visible').first();
if (await addBtn.isVisible({ timeout: 3000 }).catch(() => false)) {
await addBtn.click();
await page.waitForTimeout(2000);
}
// Fill repository form
const inputs = page.locator('input:visible');
const inputCount = await inputs.count();
console.log(`Found ${inputCount} visible inputs`);
if (inputCount >= 2) {
await inputs.nth(0).fill('SSO-Auth');
await inputs.nth(1).fill('https://raw.githubusercontent.com/9p4/jellyfin-plugin-sso/manifest-release/manifest.json');
console.log('Repository form filled');
}
// Click Save
const saveBtn = page.locator('button:has-text("Save"):visible, .button-submit:visible').first();
if (await saveBtn.isVisible({ timeout: 3000 }).catch(() => false)) {
await saveBtn.click();
await page.waitForTimeout(3000);
console.log('Repository saved');
}
// Step 3: Go to Catalog and install SSO-Auth
console.log('=== Installing SSO-Auth plugin ===');
await page.goto(`${BASE}/web/#/dashboard/plugins/catalog`, { waitUntil: 'networkidle', timeout: 30000 });
await page.waitForTimeout(5000);
// Search for SSO
const search = page.locator('input[type="text"]:visible').first();
if (await search.isVisible({ timeout: 3000 }).catch(() => false)) {
await search.fill('SSO');
await page.waitForTimeout(3000);
}
// Look for install button
const installBtn = page.locator('button:has-text("Install"):visible').first();
if (await installBtn.isVisible({ timeout: 5000 }).catch(() => false)) {
await installBtn.click();
await page.waitForTimeout(2000);
console.log('Install clicked');
}
// Handle restart dialog
const confirmBtn = page.locator('button:has-text("Yes"):visible, button:has-text("Restart"):visible').first();
if (await confirmBtn.isVisible({ timeout: 3000 }).catch(() => false)) {
await confirmBtn.click();
console.log('Restart confirmed');
}
// Wait for Jellyfin to restart
console.log('Waiting for restart...');
await page.waitForTimeout(30000);
// Step 4: Configure SSO-Auth plugin
console.log('=== Configuring SSO-Auth plugin ===');
await page.goto(`${BASE}/web/#/login.html`, { waitUntil: 'networkidle', timeout: 30000 });
await page.waitForTimeout(3000);
if (await page.locator('#txtUsername').isVisible({ timeout: 3000 }).catch(() => false)) {
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);
}
// Go to SSO-Auth plugin settings
await page.goto(`${BASE}/web/#/dashboard/plugins`, { waitUntil: 'networkidle', timeout: 30000 });
await page.waitForTimeout(5000);
// Find SSO-Auth plugin and click it
const ssoLink = page.locator('a:has-text("SSO Authentication"):visible, .card:has-text("SSO Authentication"):visible').first();
if (await ssoLink.isVisible({ timeout: 5000 }).catch(() => false)) {
// Click the settings button (three dots)
const settingsBtn = page.locator('button[title*="Settings"]:visible, button[aria-label*="Settings"]:visible').first();
if (await settingsBtn.isVisible({ timeout: 3000 }).catch(() => false)) {
await settingsBtn.click();
await page.waitForTimeout(2000);
} else {
await ssoLink.click();
await page.waitForTimeout(3000);
}
}
// Fill OIDC configuration
const configInputs = page.locator('input:visible, textarea:visible');
const configCount = await configInputs.count();
console.log(`Found ${configCount} config inputs`);
// Fill fields by label or placeholder
const allFields = [
{ label: 'Name of OID Provider', value: 'authentik' },
{ label: 'OID Endpoint', value: 'https://auth.researchstack.info/application/o/jellyfin/.well-known/openid-configuration' },
{ label: 'OpenID Client ID', value: 'sso-jellyfin' },
{ label: 'OID Secret', value: 'fc96e87934f544bef43e5466c929baa73b681c4e5d0aa9fc5cafe6e6a36e2e49' },
];
for (const field of allFields) {
const labelEl = page.locator(`label:has-text("${field.label}"):visible`);
if (await labelEl.isVisible({ timeout: 2000 }).catch(() => false)) {
const forAttr = await labelEl.getAttribute('for');
if (forAttr) {
await page.locator(`#${forAttr}`).fill(field.value);
} else {
const input = labelEl.locator('..').locator('input, textarea').first();
if (await input.isVisible({ timeout: 1000 }).catch(() => false)) {
await input.fill(field.value);
}
}
}
}
// Check Enable checkbox
const enableCheck = page.locator('input[type="checkbox"]:visible').first();
if (await enableCheck.isVisible({ timeout: 2000 }).catch(() => false)) {
await enableCheck.check();
}
// Check Enable Authorization by Plugin
const authCheck = page.locator('input[type="checkbox"]:visible').nth(1);
if (await authCheck.isVisible({ timeout: 2000 }).catch(() => false)) {
await authCheck.check();
}
// Save
const saveConfigBtn = page.locator('button:has-text("Save"):visible').first();
if (await saveConfigBtn.isVisible({ timeout: 3000 }).catch(() => false)) {
await saveConfigBtn.click();
await page.waitForTimeout(3000);
console.log('SSO config saved');
}
await page.screenshot({ path: '/tmp/jf-sso-done.png', fullPage: true });
console.log('=== Jellyfin SSO setup complete ===');
});