Public/Wait-PatLibraryScan.ps1

function Wait-PatLibraryScan {
    <#
    .SYNOPSIS
        Waits for a Plex library scan to complete.
 
    .DESCRIPTION
        Blocks execution until a library scan completes for the specified section.
        Polls the Plex server's activities endpoint and displays progress.
        Useful after calling Update-PatLibrary to ensure the scan finishes
        before proceeding.
 
    .PARAMETER SectionId
        The ID of the library section to monitor.
 
    .PARAMETER SectionName
        The friendly name of the library section to monitor (e.g., "Movies").
 
    .PARAMETER Timeout
        Maximum time to wait in seconds. Throws an error if exceeded.
        Default: 300 seconds (5 minutes).
 
    .PARAMETER PollingInterval
        Time between status checks in seconds. Default: 2 seconds.
 
    .PARAMETER PassThru
        If specified, returns the final activity status when complete.
 
    .PARAMETER ServerUri
        The base URI of the Plex server (e.g., http://plex.example.com:32400)
        If not specified, uses the default stored server.
 
    .EXAMPLE
        Update-PatLibrary -SectionName 'Movies' -Path '/mnt/media/Movies/NewMovie'
        Wait-PatLibraryScan -SectionName 'Movies'
 
        Triggers a library scan and waits for it to complete.
 
    .EXAMPLE
        Wait-PatLibraryScan -SectionId 2 -Timeout 60
 
        Waits up to 60 seconds for section 2 to finish scanning.
 
    .EXAMPLE
        $status = Wait-PatLibraryScan -SectionName 'Movies' -PassThru
 
        Waits for scan completion and returns the final activity status.
 
    .EXAMPLE
        Update-PatLibrary -SectionId 2
        Wait-PatLibraryScan -SectionId 2 -PollingInterval 5
 
        Waits for scan, checking every 5 seconds instead of the default 2.
 
    .OUTPUTS
        None by default. With -PassThru, returns PlexAutomationToolkit.Activity object
        or $null if no scan was in progress.
    #>

    [CmdletBinding(DefaultParameterSetName = 'ByName')]
    param (
        [Parameter(Mandatory = $true, ParameterSetName = 'ById')]
        [ValidateRange(1, [int]::MaxValue)]
        [int]
        $SectionId,

        [Parameter(Mandatory = $true, ParameterSetName = 'ByName')]
        [ValidateNotNullOrEmpty()]
        [string]
        $SectionName,

        [Parameter(Mandatory = $false)]
        [ValidateRange(1, 3600)]
        [int]
        $Timeout = 300,

        [Parameter(Mandatory = $false)]
        [ValidateRange(1, 60)]
        [int]
        $PollingInterval = 2,

        [Parameter(Mandatory = $false)]
        [switch]
        $PassThru,

        [Parameter(Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [ValidateScript({ Test-PatServerUri -Uri $_ })]
        [string]
        $ServerUri
    )

    # Build parameters for internal calls
    $serverParams = @{}
    if ($ServerUri) {
        $serverParams['ServerUri'] = $ServerUri
    }

    # Resolve section name to ID if needed
    $resolvedSectionId = $SectionId
    $sectionDisplayName = $SectionId.ToString()

    if ($PSCmdlet.ParameterSetName -eq 'ByName') {
        try {
            $libraryPaths = Get-PatLibraryPath @serverParams -SectionName $SectionName -ErrorAction 'Stop'
            if ($libraryPaths) {
                $resolvedSectionId = [int]$libraryPaths[0].sectionId
                $sectionDisplayName = $SectionName
            }
            else {
                throw "Library section '$SectionName' not found"
            }
        }
        catch {
            throw "Failed to resolve section name '$SectionName': $($_.Exception.Message)"
        }
    }

    $startTime = Get-Date
    $lastActivity = $null

    Write-Verbose "Waiting for library scan on section $sectionDisplayName (timeout: ${Timeout}s)"

    while ($true) {
        # Check for timeout
        $elapsed = (Get-Date) - $startTime
        if ($elapsed.TotalSeconds -ge $Timeout) {
            throw "Timeout waiting for library scan to complete after $Timeout seconds"
        }

        # Check for scan activity
        try {
            $activityParams = $serverParams.Clone()
            $activityParams['Type'] = 'library.update.section'
            $activityParams['SectionId'] = $resolvedSectionId

            $activity = Get-PatActivity @activityParams -ErrorAction 'Stop'
        }
        catch {
            Write-Warning "Failed to check activity status: $($_.Exception.Message)"
            $activity = $null
        }

        if ($activity) {
            $lastActivity = $activity

            # Show progress
            $progressParams = @{
                Activity        = "Library scan: $sectionDisplayName"
                Status          = $activity.Subtitle
                PercentComplete = $activity.Progress
            }
            Write-Progress @progressParams

            Write-Verbose "Scan in progress: $($activity.Progress)% - $($activity.Subtitle)"
        }
        else {
            # No scan activity found - either completed or never started
            Write-Progress -Activity "Library scan: $sectionDisplayName" -Completed
            Write-Verbose "No active scan found for section $sectionDisplayName"

            if ($PassThru) {
                return $lastActivity
            }
            return
        }

        # Wait before next poll
        Start-Sleep -Seconds $PollingInterval
    }
}