Public/Get-SpotifyPlaylists.ps1
<# .SYNOPSIS Export your Spotify playlists .DESCRIPTION Retrieves your Spotify playlists. By default, returns them as a nested data object, but can be instructed to instead return a combined JSON file or set of CSV files, where each CSV contains a song list for a specific playlist. .PARAMETER ClientId Optional. The ClientId of the app you registered in the Spotify developer portal. See the 'Authentication' section at https://github.com/niwamo/SpotifyUtils .PARAMETER RedirectURI Optional. The redirect URI used for OAuth authentication. Must match what is configured in the Spotify developer protal. See the 'Authentication' section at https://github.com/niwamo/SpotifyUtils .PARAMETER ConfigFile Optional. The path to a JSON configuration file containing 'ClientId' and 'RedirectURI' properties. See the 'Authentication' section at https://github.com/niwamo/SpotifyUtils .PARAMETER OutputFormat The format in which to return playlist data. Can be either 'json' or 'csv'. If 'JSON', combined with OutputFile or OutputFolder, writes directly to a file. If 'JSON' and not combined with one of the above parameters, returns a string. If 'CSV', must be combined with OutputFolder, and will write one file per playlist. .PARAMETER OutputFile The filepath where this function should save retreived data. Requires OutputFormat to be specified. .PARAMETER OutputFolder The directory where this function should save retrieved data. Requires OutputFormat to be specified. .EXAMPLE Get-SpotifyPlaylists -OutputFormat csv -OutputFolder ./playlists #> function Get-SpotifyPlaylists { [CmdletBinding()] param ( [Parameter(Mandatory=$false)] [string] $ClientId, [Parameter(Mandatory=$false)] [string] $RedirectURI, [ValidateScript({Test-Path $_})] [Parameter(Mandatory=$false)] [string] $ConfigFile, [ValidateSet('json', 'csv')] [Parameter(Mandatory=$false)] [string] $OutputFormat, [ValidateScript({ !(Test-Path $_) -and (Test-Path ([IO.Path]::GetDirectoryName($_))) })] [Parameter(Mandatory=$false)] [string] $OutputFile, [ValidateScript({Test-Path $_})] [Parameter(Mandatory=$false)] [string] $OutputFolder ) if ($OutputFormat -eq 'csv' -and ! $OutputFolder) { throw 'OutputFolder must be specified when using OutputFormat=csv' } if ($OutputFile -and $OutputFolder) { throw 'OutputFile and OutputFolder are mutually exclusive' } Set-StrictMode -Version 1.0 $ErrorActionPreference = 'Stop' # authorization $PSBoundParameters.Add( 'Scopes', @('playlist-read-private', 'playlist-read-collaborative') ) | Out-Null $token = Get-SpotifyToken @PSBoundParameters $headers = @{ Authorization = "Bearer $token" } ########################## # Region: Playlists # ########################## $uri = $script:MYPLAYLISTS_URI $playlists = [System.Collections.ArrayList]::New() while ($true) { $response = ( Invoke-WebRequest -Uri $uri -Headers $headers ).Content | ConvertFrom-Json # add to array $playlists.AddRange(@($response.items)) | Out-Null if (! $response.next) { break } $uri = $response.next # avoid rate limiting [System.Threading.Thread]::Sleep($script:API_DELAY) } Write-Information "Found $($playlists.Count) playlists. Fetching playlist tracks..." $playlistData = foreach ($playlist in $playlists) { Write-Information "`tFetching tracks in '$($playlist.Name)'..." $trackURI = $playlist.tracks.href $urlParams = @{ fields = "next,offset,items(track(name,artists(name),album(name),show(name)))" } $tracks = [System.Collections.ArrayList]::New() while ($true) { $uParams = foreach ($param in $urlParams.Keys) { [string]::Format( "{0}={1}", $param, $urlParams.$param ) } $uri = [string]::Format("{0}?{1}", $trackURI, [string]::Join("&", $uParams)) $response = ( Invoke-WebRequest -Uri $uri -Headers $headers ).Content | ConvertFrom-Json # add to array $newTracks = ConvertTo-SpotifyTrack -Tracks $response.items.track $tracks.AddRange($newTracks) | Out-Null if (! $response.next) { break } $urlParams.offset = $tracks.Count # avoid rate limiting [System.Threading.Thread]::Sleep($script:API_DELAY) } [PSCustomObject]@{ Name = $playlist.name Owner = $playlist.owner.display_name Tracks = [array]$tracks } Write-Information "Done ($($tracks.Count))" } ########################## # Region: Export # ########################## if ($OutputFormat -eq 'json') { $out = $playlistData | ConvertTo-Json if ($OutputFile) { Set-Content -Path $OutputFile -Encoding 'UTF8' -Value $out Write-Information "Wrote playlist data to $OutputFile" return } if ($OutputFolder) { $tstamp = Get-Date -Format "yyyy-MM-dd-HH-mm-ss" $fpath = "$OutputFolder/$tstamp-playlist-export.json" Set-Content -Path $fpath -Encoding 'UTF8' -Value $out Write-Information "Wrote playlist data to $fpath" return } return $out } if ($OutputFormat -eq 'csv') { # case where OutputFolder is NOT provided is handled at top of function foreach ($plist in $playlistData) { $tstamp = Get-Date -Format "yyyy-MM-dd-HH-mm-ss" $outdir = New-Item -ItemType Directory -Path "$OutputFolder/$tstamp-playlist-export" $fpath = "$outdir/$($plist.Name).csv" Export-Csv -InputObject $plist.Tracks -Encoding utf8 -Path $fpath } } return $playlistData } |