77e30685bb
- Implements Phases 3–6: session isolation, cache coordination, primary election, and file system monitor coordination for Jellyfin with PostgreSQL. - Adds new database entities (Instance, DistributedLock, FileSystemChange) and EF model configurations. - Includes SQL migration scripts and EF migration for all required tables, columns, and helper functions. - Updates Device entity and JellyfinDbContext for multi-instance tracking. - Integrates new DI services for instance registry, distributed locks, cache coordinator, and primary election. - Adds publishing profiles (Win/Linux/FrameworkDependent) and automation script for deployment. - Extensive documentation for architecture, setup, and publishing. - All changes are backward compatible and build successfully.
270 lines
8.9 KiB
PowerShell
270 lines
8.9 KiB
PowerShell
# PublishAndDeploy.ps1
|
|
# Automated publish and deployment script for Jellyfin multi-instance builds
|
|
|
|
param(
|
|
[ValidateSet("MultiInstance-Win-x64", "MultiInstance-Linux-x64", "MultiInstance-FrameworkDependent")]
|
|
[string]$Profile = "MultiInstance-Win-x64",
|
|
|
|
[string]$DeployPath = "D:\Program Files\Jellyfin-multiinstance",
|
|
|
|
[switch]$SkipDeploy,
|
|
|
|
[switch]$CreatePackage,
|
|
|
|
[string]$PackageOutput = ".",
|
|
|
|
[switch]$Verbose
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
# Colors
|
|
function Write-Step {
|
|
param([string]$Message)
|
|
Write-Host "[>] $Message" -ForegroundColor Cyan
|
|
}
|
|
|
|
function Write-Success {
|
|
param([string]$Message)
|
|
Write-Host "[+] $Message" -ForegroundColor Green
|
|
}
|
|
|
|
function Write-Warning {
|
|
param([string]$Message)
|
|
Write-Host "[!] $Message" -ForegroundColor Yellow
|
|
}
|
|
|
|
function Write-Failure {
|
|
param([string]$Message)
|
|
Write-Host "[X] $Message" -ForegroundColor Red
|
|
}
|
|
|
|
# Header
|
|
Write-Host ""
|
|
Write-Host "================================================================" -ForegroundColor Cyan
|
|
Write-Host " Jellyfin Multi-Instance Publisher & Deployer" -ForegroundColor Cyan
|
|
Write-Host "================================================================" -ForegroundColor Cyan
|
|
Write-Host ""
|
|
|
|
Write-Host "Profile: $Profile" -ForegroundColor White
|
|
Write-Host "Deploy Path: $DeployPath" -ForegroundColor White
|
|
Write-Host "Skip Deploy: $SkipDeploy" -ForegroundColor White
|
|
Write-Host "Create Pkg: $CreatePackage`n" -ForegroundColor White
|
|
|
|
# Validate project exists
|
|
$projectPath = "Jellyfin.Server\Jellyfin.Server.csproj"
|
|
if (-not (Test-Path $projectPath)) {
|
|
Write-Failure "Project not found: $projectPath"
|
|
Write-Host "Please run this script from the solution root directory.`n" -ForegroundColor Yellow
|
|
exit 1
|
|
}
|
|
|
|
Write-Success "Found project: $projectPath"
|
|
|
|
# Step 1: Clean
|
|
Write-Step "Cleaning previous builds..."
|
|
dotnet clean $projectPath --configuration Release --verbosity minimal
|
|
if ($LASTEXITCODE -ne 0) {
|
|
Write-Failure "Clean failed!"
|
|
exit 1
|
|
}
|
|
Write-Success "Clean completed"
|
|
|
|
# Step 2: Restore
|
|
Write-Step "Restoring NuGet packages..."
|
|
dotnet restore $projectPath --verbosity minimal
|
|
if ($LASTEXITCODE -ne 0) {
|
|
Write-Failure "Restore failed!"
|
|
exit 1
|
|
}
|
|
Write-Success "Restore completed"
|
|
|
|
# Step 3: Publish
|
|
Write-Step "Publishing with profile: $Profile..."
|
|
$verbosityArg = if ($Verbose) { "normal" } else { "minimal" }
|
|
|
|
dotnet publish $projectPath `
|
|
-p:PublishProfile=$Profile `
|
|
--configuration Release `
|
|
--verbosity $verbosityArg `
|
|
--nologo
|
|
|
|
if ($LASTEXITCODE -ne 0) {
|
|
Write-Failure "Publish failed!"
|
|
exit 1
|
|
}
|
|
Write-Success "Publish completed"
|
|
|
|
# Step 4: Verify output
|
|
$publishDir = "Jellyfin.Server\bin\Publish\$Profile"
|
|
Write-Step "Verifying publish output at: $publishDir"
|
|
|
|
if (-not (Test-Path $publishDir)) {
|
|
Write-Failure "Publish directory not found: $publishDir"
|
|
exit 1
|
|
}
|
|
|
|
$exeName = if ($Profile -like "*Win*") { "jellyfin.exe" } else { "jellyfin" }
|
|
$exePath = Join-Path $publishDir $exeName
|
|
|
|
if (-not (Test-Path $exePath)) {
|
|
Write-Failure "Executable not found: $exePath"
|
|
exit 1
|
|
}
|
|
|
|
# Verify SQL scripts
|
|
$sqlPath = Join-Path $publishDir "sql\add_multi_instance_support.sql"
|
|
if (-not (Test-Path $sqlPath)) {
|
|
Write-Warning "SQL script not found (expected at: $sqlPath)"
|
|
} else {
|
|
Write-Success "SQL scripts included"
|
|
}
|
|
|
|
# Verify documentation
|
|
$docsPath = Join-Path $publishDir "docs"
|
|
if (Test-Path $docsPath) {
|
|
$docCount = (Get-ChildItem $docsPath -Filter "*.md").Count
|
|
Write-Success "Documentation included ($docCount files)"
|
|
} else {
|
|
Write-Warning "Documentation directory not found"
|
|
}
|
|
|
|
# Get publish size
|
|
$publishSize = (Get-ChildItem $publishDir -Recurse | Measure-Object -Property Length -Sum).Sum / 1MB
|
|
Write-Success "Publish output verified (Size: $($publishSize.ToString('N2')) MB)"
|
|
|
|
# Step 5: Create package (optional)
|
|
if ($CreatePackage) {
|
|
Write-Step "Creating deployment package..."
|
|
|
|
$version = Get-Date -Format "yyyyMMdd-HHmmss"
|
|
$packageName = "Jellyfin-MultiInstance-$version.zip"
|
|
$packagePath = Join-Path $PackageOutput $packageName
|
|
|
|
Compress-Archive -Path "$publishDir\*" `
|
|
-DestinationPath $packagePath `
|
|
-CompressionLevel Optimal `
|
|
-Force
|
|
|
|
if (Test-Path $packagePath) {
|
|
$packageSize = (Get-Item $packagePath).Length / 1MB
|
|
Write-Success "Package created: $packagePath ($($packageSize.ToString('N2')) MB)"
|
|
} else {
|
|
Write-Failure "Failed to create package"
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
# Step 6: Deploy (optional)
|
|
if (-not $SkipDeploy) {
|
|
Write-Step "Deploying to: $DeployPath"
|
|
|
|
# Check if jellyfin is running
|
|
$jellyfinProcess = Get-Process -Name "jellyfin" -ErrorAction SilentlyContinue
|
|
if ($jellyfinProcess) {
|
|
Write-Warning "Jellyfin is currently running (PID: $($jellyfinProcess.Id))"
|
|
$response = Read-Host "Stop Jellyfin and continue? (y/N)"
|
|
if ($response -eq 'y' -or $response -eq 'Y') {
|
|
Write-Step "Stopping Jellyfin..."
|
|
$jellyfinProcess | Stop-Process -Force
|
|
Start-Sleep -Seconds 2
|
|
Write-Success "Jellyfin stopped"
|
|
} else {
|
|
Write-Warning "Deployment cancelled by user"
|
|
exit 0
|
|
}
|
|
}
|
|
|
|
# Backup existing installation
|
|
if (Test-Path $DeployPath) {
|
|
$backupPath = "$DeployPath.backup-$(Get-Date -Format 'yyyyMMdd-HHmmss')"
|
|
Write-Step "Backing up existing installation to: $backupPath"
|
|
|
|
try {
|
|
Copy-Item -Path $DeployPath -Destination $backupPath -Recurse -Force
|
|
Write-Success "Backup created"
|
|
} catch {
|
|
Write-Warning "Backup failed: $_"
|
|
$response = Read-Host "Continue without backup? (y/N)"
|
|
if ($response -ne 'y' -and $response -ne 'Y') {
|
|
exit 1
|
|
}
|
|
}
|
|
}
|
|
|
|
# Create deploy directory
|
|
if (-not (Test-Path $DeployPath)) {
|
|
New-Item -ItemType Directory -Path $DeployPath -Force | Out-Null
|
|
}
|
|
|
|
# Copy files
|
|
Write-Step "Copying files to deployment directory..."
|
|
try {
|
|
Copy-Item -Path "$publishDir\*" -Destination $DeployPath -Recurse -Force
|
|
Write-Success "Files copied successfully"
|
|
} catch {
|
|
Write-Failure "Deployment failed: $_"
|
|
exit 1
|
|
}
|
|
|
|
# Verify deployment
|
|
$deployedExe = Join-Path $DeployPath $exeName
|
|
if (Test-Path $deployedExe) {
|
|
Write-Success "Deployment verified"
|
|
} else {
|
|
Write-Failure "Deployment verification failed"
|
|
exit 1
|
|
}
|
|
|
|
Write-Success "Deployment complete!"
|
|
|
|
# Post-deployment instructions
|
|
Write-Host ""
|
|
Write-Host "================================================================" -ForegroundColor Green
|
|
Write-Host " Deployment Successful!" -ForegroundColor Green
|
|
Write-Host "================================================================" -ForegroundColor Green
|
|
Write-Host ""
|
|
|
|
Write-Host "Next Steps:" -ForegroundColor Yellow
|
|
Write-Host "1. Create database.xml in config directory" -ForegroundColor White
|
|
Write-Host " Location: " -NoNewline -ForegroundColor White
|
|
Write-Host "$DeployPath\config\database.xml" -ForegroundColor Cyan
|
|
Write-Host "`n2. Run multi-instance SQL setup (first deployment only):" -ForegroundColor White
|
|
Write-Host " psql -h YOUR_SERVER -U jellyfin -d jellyfin -f $DeployPath\sql\add_multi_instance_support.sql" -ForegroundColor Cyan
|
|
Write-Host "`n3. Start Jellyfin:" -ForegroundColor White
|
|
Write-Host " cd `"$DeployPath`"" -ForegroundColor Cyan
|
|
Write-Host " .\$exeName" -ForegroundColor Cyan
|
|
Write-Host ""
|
|
|
|
} else {
|
|
Write-Step "Skipping deployment (use -SkipDeploy:`$false to deploy)"
|
|
|
|
Write-Host ""
|
|
Write-Host "================================================================" -ForegroundColor Green
|
|
Write-Host " Publish Successful!" -ForegroundColor Green
|
|
Write-Host "================================================================" -ForegroundColor Green
|
|
Write-Host ""
|
|
|
|
Write-Host "Publish Directory:" -ForegroundColor Yellow
|
|
Write-Host " $publishDir" -ForegroundColor Cyan
|
|
Write-Host "`nTo deploy manually:" -ForegroundColor Yellow
|
|
Write-Host " Copy-Item -Path `"$publishDir\*`" -Destination `"YOUR_PATH`" -Recurse -Force" -ForegroundColor Cyan
|
|
Write-Host ""
|
|
}
|
|
|
|
# Summary
|
|
Write-Host "================================================================" -ForegroundColor Gray
|
|
Write-Host "Profile: $Profile" -ForegroundColor White
|
|
Write-Host "Published: $publishDir" -ForegroundColor White
|
|
Write-Host "Size: $($publishSize.ToString('N2')) MB" -ForegroundColor White
|
|
if ($CreatePackage) {
|
|
Write-Host "Package: $packagePath" -ForegroundColor White
|
|
}
|
|
if (-not $SkipDeploy) {
|
|
Write-Host "Deployed to: $DeployPath" -ForegroundColor White
|
|
}
|
|
Write-Host "================================================================" -ForegroundColor Gray
|
|
Write-Host ""
|
|
|
|
exit 0
|