Public/Get-ShellPhishSongsNeverSeen.ps1

function Get-ShellPhishSongsNeverSeen {
    <#
    .SYNOPSIS
        Lists songs a user has never seen performed live.
    .PARAMETER Username
        Phish.net username.
    .PARAMETER ExportPath
        Optional file path (.csv or .json) to export results.
    .PARAMETER DelayMs
        Delay in milliseconds between API calls. Default 500.
    .EXAMPLE
        PS C:\> Get-ShellPhishSongsNeverSeen -Username wilson
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [string]$Username,

        [Parameter()]
        [string]$ExportPath,

        [Parameter()]
        [int]$DelayMs = 500
    )

    Write-Verbose "Fetching full song catalog..."
    $allSongs = (Get-ShellPhishSongs).data

    Write-Verbose "Fetching attendance for $Username..."
    $attendance = (Get-ShellPhishAttendance -Username $Username).data

    if (-not $attendance) {
        Write-Warning "No attendance records found for $Username"
        return
    }

    Write-Verbose "Found $($attendance.Count) show(s). Fetching setlists..."
    $seenSlugs = @{}
    foreach ($record in $attendance) {
        Start-Sleep -Milliseconds $DelayMs
        $setlist = (Get-ShellPhishSetlists -ShowId $record.showid).data
        if ($setlist) {
            foreach ($entry in $setlist) {
                $seenSlugs[$entry.slug] = $true
            }
        }
    }

    $neverSeen = $allSongs | Where-Object { -not $seenSlugs.ContainsKey($_.slug) } | ForEach-Object {
        [PSCustomObject]@{
            Song = $_.song
            Slug = $_.slug
        }
    } | Sort-Object Song

    Write-Verbose "Seen $($seenSlugs.Count) unique songs. Never seen $($neverSeen.Count) songs."
    Export-ShellPhishData -Data $neverSeen -ExportPath $ExportPath
}