# 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