├── .gitattributes ├── .gitignore ├── Assets └── spotify.netstandard.png ├── CHANGELOG.md ├── LICENSE ├── NUGET.md ├── README.md └── Spotify.NetStandard ├── Spotify.NetStandard.Test ├── Spotify.NetStandard.Test.csproj ├── SpotifyClientApiTest.cs ├── SpotifyClientAuthTest.cs ├── SpotifyClientTest.cs ├── Usings.cs └── appsettings.example.json ├── Spotify.NetStandard.sln └── Spotify.NetStandard ├── Client ├── Authentication │ ├── AccessToken.cs │ ├── Enums │ │ └── TokenType.cs │ └── Internal │ │ ├── AccessCode.cs │ │ ├── AuthenticationCache.cs │ │ ├── AuthenticationClient.cs │ │ ├── AuthenticationResponse.cs │ │ ├── ImplicitGrant.cs │ │ └── VerifierChallenge.cs ├── Exceptions │ ├── AuthCodeStateException.cs │ ├── AuthCodeValueException.cs │ ├── AuthCodeVerifierRequiredException.cs │ ├── AuthException.cs │ ├── AuthTokenRequiredException.cs │ ├── AuthTokenStateException.cs │ └── AuthTokenValueException.cs ├── Interfaces │ ├── ISpotifyApi.cs │ └── ISpotifyClient.cs ├── Internal │ ├── Extensions.cs │ ├── Helpers.cs │ ├── SimpleServiceClient.cs │ ├── SimpleServiceResult.cs │ ├── SpotifyApi.cs │ └── SpotifyClient.cs └── SpotifyClientFactory.cs ├── Enums ├── FollowType.cs ├── LookupType.cs ├── NavigateType.cs ├── RepeatState.cs └── TimeRange.cs ├── Requests ├── Cursor.cs ├── DevicesRequest.cs ├── IncludeGroup.cs ├── Page.cs ├── PlaybackRequest.cs ├── PlaylistReorderRequest.cs ├── PlaylistRequest.cs ├── PlaylistTracksRequest.cs ├── PositionRequest.cs ├── PositionUriRequest.cs ├── PublicRequest.cs ├── Scope.cs ├── ScopeExtensions.cs ├── SearchType.cs ├── TuneableTrack.cs ├── UriListRequest.cs └── UriRequest.cs ├── Responses ├── Actions.cs ├── Album.cs ├── Artist.cs ├── AudioAnalysis.cs ├── AudioFeatures.cs ├── Audiobook.cs ├── Author.cs ├── AvailableGenreSeeds.cs ├── AvailableMarkets.cs ├── BaseResponse.cs ├── Bools.cs ├── Category.cs ├── Chapter.cs ├── Content.cs ├── ContentResponse.cs ├── Context.cs ├── Copyright.cs ├── CurrentlyPlaying.cs ├── CursorPaging.cs ├── Device.cs ├── Devices.cs ├── Disallows.cs ├── Episode.cs ├── ErrorResponse.cs ├── ExternalId.cs ├── ExternalUrl.cs ├── Followers.cs ├── Image.cs ├── Internal │ ├── ContentCursorResponse.cs │ └── InternalResponse.cs ├── LinkedTrack.cs ├── LookupResponse.cs ├── Narrator.cs ├── Paging.cs ├── PlayHistory.cs ├── Playlist.cs ├── PlaylistTrack.cs ├── PrivateUser.cs ├── PublicUser.cs ├── Queue.cs ├── RecommendationSeed.cs ├── RecommendationsResponse.cs ├── ResumePoint.cs ├── SavedAlbum.cs ├── SavedEpisode.cs ├── SavedShow.cs ├── SavedTrack.cs ├── Section.cs ├── Segment.cs ├── Show.cs ├── SimplifiedAlbum.cs ├── SimplifiedArtist.cs ├── SimplifiedAudiobook.cs ├── SimplifiedChapter.cs ├── SimplifiedCurrentlyPlaying.cs ├── SimplifiedEpisode.cs ├── SimplifiedPlaylist.cs ├── SimplifiedShow.cs ├── SimplifiedTrack.cs ├── Snapshot.cs ├── Status.cs ├── TimeInterval.cs ├── Track.cs └── TrackRestriction.cs ├── Spotify.NetStandard.csproj ├── Spotify.NetStandard.xml └── Usings.cs /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015/2017 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # Visual Studio 2017 auto generated files 33 | Generated\ Files/ 34 | 35 | # MSTest test Results 36 | [Tt]est[Rr]esult*/ 37 | [Bb]uild[Ll]og.* 38 | 39 | # NUNIT 40 | *.VisualState.xml 41 | TestResult.xml 42 | 43 | # Build Results of an ATL Project 44 | [Dd]ebugPS/ 45 | [Rr]eleasePS/ 46 | dlldata.c 47 | 48 | # Benchmark Results 49 | BenchmarkDotNet.Artifacts/ 50 | 51 | # .NET Core 52 | project.lock.json 53 | project.fragment.lock.json 54 | artifacts/ 55 | **/Properties/launchSettings.json 56 | 57 | # StyleCop 58 | StyleCopReport.xml 59 | 60 | # Files built by Visual Studio 61 | *_i.c 62 | *_p.c 63 | *_i.h 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.iobj 68 | *.pch 69 | *.pdb 70 | *.ipdb 71 | *.pgc 72 | *.pgd 73 | *.rsp 74 | *.sbr 75 | *.tlb 76 | *.tli 77 | *.tlh 78 | *.tmp 79 | *.tmp_proj 80 | *.log 81 | *.vspscc 82 | *.vssscc 83 | .builds 84 | *.pidb 85 | *.svclog 86 | *.scc 87 | 88 | # Chutzpah Test files 89 | _Chutzpah* 90 | 91 | # Visual C++ cache files 92 | ipch/ 93 | *.aps 94 | *.ncb 95 | *.opendb 96 | *.opensdf 97 | *.sdf 98 | *.cachefile 99 | *.VC.db 100 | *.VC.VC.opendb 101 | 102 | # Visual Studio profiler 103 | *.psess 104 | *.vsp 105 | *.vspx 106 | *.sap 107 | 108 | # Visual Studio Trace Files 109 | *.e2e 110 | 111 | # TFS 2012 Local Workspace 112 | $tf/ 113 | 114 | # Guidance Automation Toolkit 115 | *.gpState 116 | 117 | # ReSharper is a .NET coding add-in 118 | _ReSharper*/ 119 | *.[Rr]e[Ss]harper 120 | *.DotSettings.user 121 | 122 | # JustCode is a .NET coding add-in 123 | .JustCode 124 | 125 | # TeamCity is a build add-in 126 | _TeamCity* 127 | 128 | # DotCover is a Code Coverage Tool 129 | *.dotCover 130 | 131 | # AxoCover is a Code Coverage Tool 132 | .axoCover/* 133 | !.axoCover/settings.json 134 | 135 | # Visual Studio code coverage results 136 | *.coverage 137 | *.coveragexml 138 | 139 | # NCrunch 140 | _NCrunch_* 141 | .*crunch*.local.xml 142 | nCrunchTemp_* 143 | 144 | # MightyMoose 145 | *.mm.* 146 | AutoTest.Net/ 147 | 148 | # Web workbench (sass) 149 | .sass-cache/ 150 | 151 | # Installshield output folder 152 | [Ee]xpress/ 153 | 154 | # DocProject is a documentation generator add-in 155 | DocProject/buildhelp/ 156 | DocProject/Help/*.HxT 157 | DocProject/Help/*.HxC 158 | DocProject/Help/*.hhc 159 | DocProject/Help/*.hhk 160 | DocProject/Help/*.hhp 161 | DocProject/Help/Html2 162 | DocProject/Help/html 163 | 164 | # Click-Once directory 165 | publish/ 166 | 167 | # Publish Web Output 168 | *.[Pp]ublish.xml 169 | *.azurePubxml 170 | # Note: Comment the next line if you want to checkin your web deploy settings, 171 | # but database connection strings (with potential passwords) will be unencrypted 172 | *.pubxml 173 | *.publishproj 174 | 175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 176 | # checkin your Azure Web App publish settings, but sensitive information contained 177 | # in these scripts will be unencrypted 178 | PublishScripts/ 179 | 180 | # NuGet Packages 181 | *.nupkg 182 | # The packages folder can be ignored because of Package Restore 183 | **/[Pp]ackages/* 184 | # except build/, which is used as an MSBuild target. 185 | !**/[Pp]ackages/build/ 186 | # Uncomment if necessary however generally it will be regenerated when needed 187 | #!**/[Pp]ackages/repositories.config 188 | # NuGet v3's project.json files produces more ignorable files 189 | *.nuget.props 190 | *.nuget.targets 191 | 192 | # Microsoft Azure Build Output 193 | csx/ 194 | *.build.csdef 195 | 196 | # Microsoft Azure Emulator 197 | ecf/ 198 | rcf/ 199 | 200 | # Windows Store app package directories and files 201 | AppPackages/ 202 | BundleArtifacts/ 203 | Package.StoreAssociation.xml 204 | _pkginfo.txt 205 | *.appx 206 | 207 | # Visual Studio cache files 208 | # files ending in .cache can be ignored 209 | *.[Cc]ache 210 | # but keep track of directories ending in .cache 211 | !*.[Cc]ache/ 212 | 213 | # Others 214 | ClientBin/ 215 | ~$* 216 | *~ 217 | *.dbmdl 218 | *.dbproj.schemaview 219 | *.jfm 220 | *.pfx 221 | *.publishsettings 222 | orleans.codegen.cs 223 | 224 | # Including strong name files can present a security risk 225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 226 | #*.snk 227 | 228 | # Since there are multiple workflows, uncomment next line to ignore bower_components 229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 230 | #bower_components/ 231 | 232 | # RIA/Silverlight projects 233 | Generated_Code/ 234 | 235 | # Backup & report files from converting an old project file 236 | # to a newer Visual Studio version. Backup files are not needed, 237 | # because we have git ;-) 238 | _UpgradeReport_Files/ 239 | Backup*/ 240 | UpgradeLog*.XML 241 | UpgradeLog*.htm 242 | ServiceFabricBackup/ 243 | *.rptproj.bak 244 | 245 | # SQL Server files 246 | *.mdf 247 | *.ldf 248 | *.ndf 249 | 250 | # Business Intelligence projects 251 | *.rdl.data 252 | *.bim.layout 253 | *.bim_*.settings 254 | *.rptproj.rsuser 255 | 256 | # Microsoft Fakes 257 | FakesAssemblies/ 258 | 259 | # GhostDoc plugin setting file 260 | *.GhostDoc.xml 261 | 262 | # Node.js Tools for Visual Studio 263 | .ntvs_analysis.dat 264 | node_modules/ 265 | 266 | # Visual Studio 6 build log 267 | *.plg 268 | 269 | # Visual Studio 6 workspace options file 270 | *.opt 271 | 272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 273 | *.vbw 274 | 275 | # Visual Studio LightSwitch build output 276 | **/*.HTMLClient/GeneratedArtifacts 277 | **/*.DesktopClient/GeneratedArtifacts 278 | **/*.DesktopClient/ModelManifest.xml 279 | **/*.Server/GeneratedArtifacts 280 | **/*.Server/ModelManifest.xml 281 | _Pvt_Extensions 282 | 283 | # Paket dependency manager 284 | .paket/paket.exe 285 | paket-files/ 286 | 287 | # FAKE - F# Make 288 | .fake/ 289 | 290 | # JetBrains Rider 291 | .idea/ 292 | *.sln.iml 293 | 294 | # CodeRush 295 | .cr/ 296 | 297 | # Python Tools for Visual Studio (PTVS) 298 | __pycache__/ 299 | *.pyc 300 | 301 | # Cake - Uncomment if you are using it 302 | # tools/** 303 | # !tools/packages.config 304 | 305 | # Tabs Studio 306 | *.tss 307 | 308 | # Telerik's JustMock configuration file 309 | *.jmconfig 310 | 311 | # BizTalk build output 312 | *.btp.cs 313 | *.btm.cs 314 | *.odx.cs 315 | *.xsd.cs 316 | 317 | # OpenCover UI analysis results 318 | OpenCover/ 319 | 320 | # Azure Stream Analytics local run output 321 | ASALocalRun/ 322 | 323 | # MSBuild Binary and Structured Log 324 | *.binlog 325 | 326 | # NVidia Nsight GPU debugger configuration file 327 | *.nvuser 328 | 329 | # MFractors (Xamarin productivity tool) working folder 330 | .mfractor/ 331 | /Spotify.NetStandard/Spotify.NetStandard.Test/appsettings.json 332 | -------------------------------------------------------------------------------- /Assets/spotify.netstandard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RoguePlanetoid/Spotify-NetStandard/78b5eeea1aba7904459ca4b72e7504d1acf1c3d0/Assets/spotify.netstandard.png -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Spotify.NetStandard 2 | 3 | ## Change Log 4 | 5 | #### Version 2.1.0 6 | 7 | - Restored Authorisation Code Flow 8 | 9 | ### Version 2.0.0 10 | 11 | - Refactored Code, Added User Episodes, Audiobook, Chapter and Queue, Updated Authorisation Code Flow with Code Verifier using Proof Key for Code Exchange (PKCE), Removed Authorisation Code Flow without Code Verifier and Original Proof Key for Code Exchange (PKCE) Flow 12 | 13 | ### Version 1.9.0 14 | 15 | - Added External HttpClient Support and Uno Platform Compatibility 16 | 17 | ### Version 1.8.0 18 | 19 | - Updated Authentication Flow with PKCE for Refresh Token 20 | 21 | ### Version 1.7.7 22 | 23 | - Fixed issue with Authentication Cache Response Uri 24 | 25 | ### Version 1.7.6 26 | 27 | - Fixed issue with Resume Point not returning Resume Position Correctly 28 | 29 | ### Version 1.7.5 30 | 31 | - Added Authorization Code Flow with Proof Key for Code Exchange (PKCE) for API 32 | 33 | ### Version 1.7.0 34 | 35 | - Added Authorization Code Flow with Proof Key for Code Exchange (PKCE), Updated Track Restrictions and Newtonsoft.Json 36 | 37 | ### Version 1.6.6 38 | 39 | - Fixed Track or Episode identification issue with Playlist Track and Currently Playing Objects 40 | 41 | ### Version 1.6.5 42 | 43 | - Updated Get a Playlist and Get a Playlist's Items to support Additional Types 44 | 45 | ### Version 1.6.0 46 | 47 | - Updated Remove Tracks from Playlist to support Positions and Added Paging Method 48 | 49 | ### Version 1.5.5 50 | 51 | - Fixed issue with Market and Country being used correctly 52 | 53 | ### Version 1.5.0 54 | 55 | - Added Save Shows for Current User, Get User's Saved Shows, Remove User's Saved Shows, Get an Episode, Get Multiple Episodes, Get a Show, Get Multiple Shows and Get a Show's Episodes plus PlaybackPositionRead Scope. Updated Get the User's Currently Playing Track, Get Information About The User's Current Playback and Search for an Item 56 | 57 | ### Version 1.2.0 58 | 59 | - Added Add an Item to the User's Playback Queue, Updated Get a Playlist and Get Playlist's Tracks to support Fields Parameter and Fixed Check/Lookup Methods Return Error Status Correctly 60 | 61 | ### Version 1.1.5 62 | 63 | - Added Actions Object, Disallows Object, Simplified Playlist Object and updated related methods 64 | 65 | ### Version 1.1.4 66 | 67 | - Fixed Token Storage and Get Playlist Tracks 68 | 69 | ### Version 1.1.3 70 | 71 | - Removed User Birthdate Value and Scope 72 | 73 | ### Version 1.1.2 74 | 75 | - Fixed and Improved Authentication Exceptions including minor Client Changes 76 | 77 | ### Version 1.1.1 78 | 79 | - Fixed Cursor and Paging Navigation 80 | 81 | ### Version 1.1.0 82 | 83 | - Added Authenticated Get Methods 84 | - Fixed Issue with Cursor Responses 85 | 86 | ### Version 1.0.2 87 | 88 | - Fixed Extension Methods 89 | 90 | ### Version 1.0.1 91 | 92 | - Added Multi Scope Helpers by [parkeradam](https://github.com/parkeradam) 93 | 94 | ### Version 1.0.0 95 | 96 | - Initial Release -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Peter Bull 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /NUGET.md: -------------------------------------------------------------------------------- 1 | # Spotify.NetStandard 2 | 3 | Spotify API .NET Standard Library 4 | 5 | ## Documentation and Source Code 6 | 7 | Project Documentation and Source Code can be found at [https://github.com/RoguePlanetoid/Spotify-NetStandard](https://github.com/RoguePlanetoid/Spotify-NetStandard) 8 | 9 | ## NuGet 10 | 11 | To add to your project from [nuget.org](https://www.nuget.org/packages/Spotify.NetStandard/) use: 12 | ``` 13 | Install-Package Spotify.NetStandard 14 | ``` 15 | 16 | ## Example 17 | 18 | ```c# 19 | using Spotify.NetStandard.Client; 20 | using Spotify.NetStandard.Requests; 21 | 22 | var client = SpotifyClientFactory 23 | .CreateSpotifyClient( 24 | "client-id","client-secret"); 25 | var page = new Page() { Limit = 10 }; 26 | var browse = await client.LookupNewReleasesAsync(page: page); 27 | foreach (var album in browse.Albums.Items) 28 | { 29 | ... 30 | } 31 | ``` 32 | 33 | ## Client Id and Client Secret 34 | 35 | You can get a "client-id" and "client-secret" from [developer.spotify.com/dashboard](https://developer.spotify.com/dashboard/) by signing in with your Spotify Id then creating an Application. 36 | 37 | ## Change Log 38 | 39 | ### Version 2.1.0 40 | 41 | - Restored Authorisation Code Flow 42 | 43 | ### Version 2.0.0 44 | 45 | - Refactored Code, Added User Episodes, Audiobook, Chapter and Queue, Updated Authorisation Code Flow with Code Verifier using Proof Key for Code Exchange (PKCE), Removed Authorisation Code Flow without Code Verifier and Original Proof Key for Code Exchange (PKCE) Flow 46 | 47 | ### Version 1.9.0 48 | 49 | - Added External HttpClient Support and Uno Platform Compatibility 50 | 51 | ### Version 1.8.0 52 | 53 | - Updated Authentication Flow with PKCE for Refresh Token 54 | 55 | ### Version 1.7.7 56 | 57 | - Fixed issue with Authentication Cache Response Uri 58 | 59 | ### Version 1.7.6 60 | 61 | - Fixed issue with Resume Point not returning Resume Position Correctly 62 | 63 | ### Version 1.7.5 64 | 65 | - Added Authorization Code Flow with Proof Key for Code Exchange (PKCE) for API 66 | 67 | ### Version 1.7.0 68 | 69 | - Added Authorization Code Flow with Proof Key for Code Exchange (PKCE), Updated Track Restrictions and Newtonsoft.Json 70 | 71 | ### Version 1.6.6 72 | 73 | - Fixed Track or Episode identification issue with Playlist Track and Currently Playing Objects 74 | 75 | ### Version 1.6.5 76 | 77 | - Updated Get a Playlist and Get a Playlist's Items to support Additional Types 78 | 79 | ### Version 1.6.0 80 | 81 | - Updated Remove Tracks from Playlist to support Positions and Added Paging Method 82 | 83 | ### Version 1.5.5 84 | 85 | - Fixed issue with Market and Country being used correctly 86 | 87 | ### Version 1.5.0 88 | 89 | - Added Save Shows for Current User, Get User's Saved Shows, Remove User's Saved Shows, Get an Episode, Get Multiple Episodes, Get a Show, Get Multiple Shows and Get a Show's Episodes plus PlaybackPositionRead Scope. Updated Get the User's Currently Playing Track, Get Information About The User's Current Playback and Search for an Item 90 | 91 | ### Version 1.2.0 92 | 93 | - Added Add an Item to the User's Playback Queue, Updated Get a Playlist and Get Playlist's Tracks to support Fields Parameter and Fixed Check/Lookup Methods Return Error Status Correctly 94 | 95 | ### Version 1.1.5 96 | 97 | - Added Actions Object, Disallows Object, Simplified Playlist Object and updated related methods 98 | 99 | ### Version 1.1.4 100 | 101 | - Fixed Token Storage and Get Playlist Tracks 102 | 103 | ### Version 1.1.3 104 | 105 | - Removed User Birthdate Value and Scope 106 | 107 | ### Version 1.1.2 108 | 109 | - Fixed and Improved Authentication Exceptions including minor Client Changes 110 | 111 | ### Version 1.1.1 112 | 113 | - Fixed Cursor and Paging Navigation 114 | 115 | ### Version 1.1.0 116 | 117 | - Added Authenticated Get Methods 118 | - Fixed Issue with Cursor Responses 119 | 120 | ### Version 1.0.2 121 | 122 | - Fixed Extension Methods 123 | 124 | ### Version 1.0.1 125 | 126 | - Added Multi Scope Helpers by [parkeradam](https://github.com/parkeradam) 127 | 128 | ### Version 1.0.0 129 | 130 | - Initial Release 131 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard.Test/Spotify.NetStandard.Test.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Always 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard.Test/SpotifyClientTest.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Test; 2 | 3 | /// 4 | /// Spotify Client Test 5 | /// 6 | [TestClass] 7 | public class SpotifyClientTest 8 | { 9 | private ISpotifyClient _client = null; 10 | private ContentResponse _content = null; 11 | private LookupResponse _list = null; 12 | 13 | /// 14 | /// Initialise Unit Test and Configuration 15 | /// 16 | [TestInitialize] 17 | public void Init() 18 | { 19 | // Configuration 20 | var configBuilder = new ConfigurationBuilder() 21 | .SetBasePath(Directory.GetCurrentDirectory()) 22 | .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); 23 | IConfiguration config = configBuilder.Build(); 24 | // Spotify Client Factory 25 | _client = SpotifyClientFactory.CreateSpotifyClient( 26 | config["client_id"], config["client_secret"]); 27 | Assert.IsNotNull(_client); 28 | } 29 | 30 | #region Albums 31 | /// 32 | /// Get an Album 33 | /// 34 | /// 35 | [TestMethod] 36 | public async Task Test_Lookup_Album() 37 | { 38 | Album item = await _client.LookupAsync( 39 | "1ZGxGu4fMROqmZsFSoepeE", LookupType.Albums); 40 | Assert.IsNotNull(item); 41 | } 42 | 43 | /// 44 | /// Get an Album's Tracks 45 | /// 46 | /// 47 | [TestMethod] 48 | public async Task Test_Lookup_AlbumTracks() 49 | { 50 | Paging list = await _client.LookupAsync>( 51 | "1ZGxGu4fMROqmZsFSoepeE", LookupType.AlbumTracks); 52 | Assert.IsNotNull(list); 53 | Assert.IsTrue(list.Items.Count > 0); 54 | } 55 | 56 | /// 57 | /// Get Several Albums 58 | /// 59 | /// 60 | [TestMethod] 61 | public async Task Test_Lookup_Albums() 62 | { 63 | List ids = new List 64 | { 65 | "41MnTivkwTO3UUJ8DrqEJJ", 66 | "6JWc4iAiJ9FjyK0B59ABb4" 67 | }; 68 | _list = await _client.LookupAsync(ids, LookupType.Albums); 69 | Assert.IsNotNull(_list.Albums); 70 | Assert.IsTrue(_list.Albums.Count == ids.Count); 71 | } 72 | 73 | /// 74 | /// Search for an album 75 | /// 76 | /// 77 | [TestMethod] 78 | public async Task Test_Search_Album() 79 | { 80 | _content = await _client.SearchAsync( 81 | "Tubular Bells", new SearchType { Album = true }); 82 | Assert.IsNotNull(_content.Albums); 83 | Assert.IsTrue(_content.Albums.Count > 0); 84 | } 85 | #endregion Albums 86 | 87 | #region Artists 88 | /// 89 | /// Get an Artist 90 | /// 91 | /// 92 | [TestMethod] 93 | public async Task Test_Lookup_Artist() 94 | { 95 | Artist item = await _client.LookupAsync( 96 | "0OdUWJ0sBjDrqHygGUXeCF", LookupType.Artists); 97 | Assert.IsNotNull(item); 98 | } 99 | 100 | /// 101 | /// Get an Artist's Albums 102 | /// 103 | /// 104 | [TestMethod] 105 | public async Task Test_Lookup_ArtistAlbums() 106 | { 107 | Paging list = await _client.LookupAsync>( 108 | "1vCWHaC5f2uS3yhpwWbIA6", LookupType.ArtistAlbums); 109 | Assert.IsNotNull(list); 110 | Assert.IsTrue(list.Items.Count > 0); 111 | } 112 | 113 | /// 114 | /// Get an Artist's Top Tracks 115 | /// 116 | /// 117 | [TestMethod] 118 | public async Task Test_Lookup_ArtistTopTracks() 119 | { 120 | _list = await _client.LookupArtistTopTracksAsync( 121 | "43ZHCT0cAZBISjO8DG9PnE", "GB"); 122 | Assert.IsNotNull(_list.Tracks); 123 | Assert.IsTrue(_list.Tracks.Count > 0); 124 | } 125 | 126 | /// 127 | /// Get an Artist's Related Artists 128 | /// 129 | /// 130 | [TestMethod] 131 | public async Task Test_Lookup_ArtistRelatedArtists() 132 | { 133 | _list = await _client.LookupArtistRelatedArtistsAsync( 134 | "43ZHCT0cAZBISjO8DG9PnE"); 135 | Assert.IsNotNull(_list.Artists); 136 | Assert.IsTrue(_list.Artists.Count > 0); 137 | } 138 | 139 | /// 140 | /// Get Several Artists 141 | /// 142 | /// 143 | [TestMethod] 144 | public async Task Test_Lookup_Artists() 145 | { 146 | List ids = new List 147 | { 148 | "0oSGxfWSnnOXhD2fKuz2Gy", 149 | "3dBVyJ7JuOMt4GE9607Qin" 150 | }; 151 | _list = await _client.LookupAsync(ids, LookupType.Artists); 152 | Assert.IsNotNull(_list.Artists); 153 | Assert.IsTrue(_list.Artists.Count == ids.Count); 154 | } 155 | 156 | /// 157 | /// Search for an artist 158 | /// 159 | /// 160 | [TestMethod] 161 | public async Task Test_Search_Artist() 162 | { 163 | _content = await _client.SearchAsync( 164 | "Mike Oldfield", new SearchType { Artist = true }); 165 | Assert.IsNotNull(_content.Artists); 166 | Assert.IsTrue(_content.Artists.Count > 0); 167 | } 168 | #endregion Artists 169 | 170 | #region Browse 171 | /// 172 | /// Get a Category 173 | /// 174 | /// 175 | [TestMethod] 176 | public async Task Test_Lookup_Category() 177 | { 178 | Category item = await _client.LookupAsync( 179 | "0JQ5DAqbMKFEC4WFtoNRpw", LookupType.Categories); 180 | Assert.IsNotNull(item); 181 | } 182 | 183 | /// 184 | /// Get a Category's Playlists 185 | /// 186 | /// 187 | [TestMethod] 188 | public async Task Test_Lookup_CategoryPlaylists() 189 | { 190 | _content = await _client.LookupAsync( 191 | "0JQ5DAqbMKFEC4WFtoNRpw", LookupType.CategoriesPlaylists); 192 | Assert.IsNotNull(_content.Playlists); 193 | Assert.IsTrue(_content.Playlists.Count > 0); 194 | } 195 | 196 | /// 197 | /// Get a List of Categories 198 | /// 199 | /// 200 | [TestMethod] 201 | public async Task Test_Lookup_Categories() 202 | { 203 | _content = await _client.LookupAllCategoriesAsync(); 204 | Assert.IsNotNull(_content.Categories); 205 | Assert.IsTrue(_content.Categories.Items.Count > 0); 206 | } 207 | 208 | /// 209 | /// Get a List of Featured Playlists 210 | /// 211 | /// 212 | [TestMethod] 213 | public async Task Test_Lookup_FeaturedPlaylists() 214 | { 215 | _content = await _client.LookupFeaturedPlaylistsAsync(); 216 | Assert.IsNotNull(_content.Playlists); 217 | Assert.IsTrue(_content.Playlists.Items.Count > 0); 218 | } 219 | 220 | /// 221 | /// Get a List of New Releases 222 | /// 223 | /// 224 | [TestMethod] 225 | public async Task Test_Lookup_NewReleases() 226 | { 227 | _content = await _client.LookupNewReleasesAsync(); 228 | Assert.IsNotNull(_content.Albums); 229 | Assert.IsTrue(_content.Albums.Items.Count > 0); 230 | } 231 | 232 | /// 233 | /// Get Recommendations Based on Seeds 234 | /// 235 | /// 236 | [TestMethod] 237 | public async Task Test_Lookup_Recommendation() 238 | { 239 | var recommendation = await _client.LookupRecommendationsAsync( 240 | seedArtists: new List { "562Od3CffWedyz2BbeYWVn" }); 241 | Assert.IsNotNull(recommendation); 242 | Assert.IsTrue(recommendation.Tracks.Count > 0); 243 | } 244 | 245 | /// 246 | /// Get Recommendation Genres 247 | /// 248 | /// 249 | [TestMethod] 250 | public async Task Test_Lookup_RecommendationGenres() 251 | { 252 | AvailableGenreSeeds genre = await _client.LookupRecommendationGenres(); 253 | Assert.IsNotNull(genre); 254 | Assert.IsTrue(genre.Genres.Count > 0); 255 | } 256 | #endregion Browse 257 | 258 | #region Playlists 259 | /// 260 | /// Get a Playlist 261 | /// 262 | /// 263 | [TestMethod] 264 | public async Task Test_Lookup_Playlist() 265 | { 266 | Playlist playlist = await _client.LookupPlaylistAsync("37i9dQZF1DXatMjChPKgBk"); 267 | Assert.IsNotNull(playlist); 268 | } 269 | 270 | /// 271 | /// Get a playlist tracks 272 | /// 273 | /// 274 | [TestMethod] 275 | public async Task Test_Lookup_PlaylistsTracks() 276 | { 277 | Paging list = await _client.LookupPlaylistItemsAsync("37i9dQZF1DXatMjChPKgBk"); 278 | Assert.IsNotNull(list); 279 | Assert.IsTrue(list.Count > 0); 280 | } 281 | 282 | /// 283 | /// Search for a playlist 284 | /// 285 | /// 286 | [TestMethod] 287 | public async Task Test_Search_Playlist() 288 | { 289 | _content = await _client.SearchAsync( 290 | "Mike Oldfield", new SearchType { Playlist = true }); 291 | Assert.IsNotNull(_content.Playlists); 292 | Assert.IsTrue(_content.Playlists.Count > 0); 293 | } 294 | #endregion Playlists 295 | 296 | #region Tracks 297 | /// 298 | /// Get Audio Features for a Track 299 | /// 300 | /// 301 | [TestMethod] 302 | public async Task Test_Lookup_Track_AudioFeatures() 303 | { 304 | AudioFeatures item = await _client.LookupAsync( 305 | "1cTZMwcBJT0Ka3UJPXOeeN", LookupType.AudioFeatures); 306 | Assert.IsNotNull(item); 307 | } 308 | 309 | /// 310 | /// Get a track 311 | /// 312 | /// 313 | [TestMethod] 314 | public async Task Test_Lookup_Track() 315 | { 316 | Track item = await _client.LookupAsync( 317 | "1cTZMwcBJT0Ka3UJPXOeeN", LookupType.Tracks); 318 | Assert.IsNotNull(item); 319 | } 320 | 321 | /// 322 | /// Get Audio Analysis for a Track 323 | /// 324 | /// 325 | [TestMethod] 326 | public async Task Test_Lookup_Track_AudioAnalysis() 327 | { 328 | AudioAnalysis item = await _client.LookupAsync( 329 | "1cTZMwcBJT0Ka3UJPXOeeN", LookupType.AudioAnalysis); 330 | Assert.IsNotNull(item); 331 | } 332 | 333 | /// 334 | /// Get Audio Features for Several Tracks 335 | /// 336 | /// 337 | [TestMethod] 338 | public async Task Test_Lookup_Tracks_AudioFeatures() 339 | { 340 | List ids = new List 341 | { 342 | "3n3Ppam7vgaVa1iaRUc9Lp", 343 | "3twNvmDtFQtAd5gMKedhLD" 344 | }; 345 | _list = await _client.LookupAsync(ids, LookupType.AudioFeatures); 346 | Assert.IsNotNull(_list.AudioFeatures); 347 | Assert.IsTrue(_list.AudioFeatures.Count == ids.Count); 348 | } 349 | 350 | /// 351 | /// Get several tracks 352 | /// 353 | /// 354 | [TestMethod] 355 | public async Task Test_Lookup_Tracks() 356 | { 357 | List ids = new List 358 | { 359 | "3n3Ppam7vgaVa1iaRUc9Lp", 360 | "3twNvmDtFQtAd5gMKedhLD" 361 | }; 362 | _list = await _client.LookupAsync(ids, LookupType.Tracks); 363 | Assert.IsNotNull(_list.Tracks); 364 | Assert.IsTrue(_list.Tracks.Count == ids.Count); 365 | } 366 | 367 | /// 368 | /// Search for a track 369 | /// 370 | /// 371 | [TestMethod] 372 | public async Task Test_Search_Track() 373 | { 374 | _content = await _client.SearchAsync( 375 | "Moonlight Shadow", new SearchType() { Track = true }); 376 | Assert.IsNotNull(_content.Tracks); 377 | Assert.IsTrue(_content.Tracks.Count > 0); 378 | } 379 | #endregion Tracks 380 | 381 | #region Episodes 382 | /// 383 | /// Get an Episode 384 | /// 385 | /// 386 | [TestMethod] 387 | public async Task Test_Lookup_Episode() 388 | { 389 | Episode item = await _client.LookupAsync( 390 | "79hCFrLsRSD7VlDYXcrCVt", LookupType.Episodes); 391 | Assert.IsNotNull(item); 392 | } 393 | 394 | /// 395 | /// Get Multiple Episodes 396 | /// 397 | /// 398 | [TestMethod] 399 | public async Task Test_Lookup_Episodes() 400 | { 401 | List ids = new List 402 | { 403 | "79hCFrLsRSD7VlDYXcrCVt", 404 | "6EbtlqXrvhCBic2TpeaalK" 405 | }; 406 | _list = await _client.LookupAsync(ids, LookupType.Episodes); 407 | Assert.IsNotNull(_list.Episodes); 408 | Assert.IsTrue(_list.Episodes.Count == ids.Count); 409 | } 410 | 411 | /// 412 | /// Search for an Episode 413 | /// 414 | /// 415 | [TestMethod] 416 | public async Task Test_Search_Episode() 417 | { 418 | _content = await _client.SearchAsync( 419 | "Andrew Jackson", new SearchType() { Episode = true }, "GB"); 420 | Assert.IsNotNull(_content.Episodes); 421 | Assert.IsTrue(_content.Episodes.Count > 0); 422 | } 423 | #endregion Episodes 424 | 425 | #region Audiobooks 426 | /// 427 | /// Search for an Audiobook 428 | /// 429 | /// 430 | [TestMethod] 431 | public async Task Test_Search_Audiobook() 432 | { 433 | _content = await _client.SearchAsync( 434 | "Lord of the Rings", new SearchType() { Audiobook = true }, "US"); 435 | Assert.IsNotNull(_content.Audiobooks); 436 | Assert.IsTrue(_content.Audiobooks.Count > 0); 437 | } 438 | 439 | /// 440 | /// Get an Audiobook 441 | /// 442 | /// 443 | [TestMethod] 444 | public async Task Test_Lookup_Audiobook() 445 | { 446 | var item = await _client.LookupAsync( 447 | "31BLWDkAbd2NjnjTMHQuhQ", LookupType.Audiobooks, market: "US"); 448 | Assert.IsNotNull(item); 449 | } 450 | 451 | /// 452 | /// Get Several Audiobooks 453 | /// 454 | /// 455 | [TestMethod] 456 | public async Task Test_Lookup_Several_Audiobook() 457 | { 458 | List ids = new() 459 | { 460 | "31BLWDkAbd2NjnjTMHQuhQ", 461 | "7j3Os33YtAtv6FtRDNxg9n" 462 | }; 463 | var response = await _client.LookupAsync(ids, LookupType.Audiobooks, market: "US"); 464 | Assert.IsNotNull(response.Audiobooks); 465 | } 466 | 467 | /// 468 | /// Get Audiobook Chapters 469 | /// 470 | /// 471 | [TestMethod] 472 | public async Task Test_Lookup_Audiobook_Chapters() 473 | { 474 | var item = await _client.LookupAsync>( 475 | "31BLWDkAbd2NjnjTMHQuhQ", LookupType.AudiobookChapters, market: "US"); 476 | Assert.IsNotNull(item); 477 | } 478 | #endregion Audiobooks 479 | 480 | #region Chapters 481 | /// 482 | /// Get a Chapter 483 | /// 484 | /// 485 | [TestMethod] 486 | public async Task Test_Lookup_Chapter() 487 | { 488 | Chapter item = await _client.LookupAsync( 489 | "4oBDDqvu2Deo9fifYY5ciE", LookupType.Chapters, market: "US"); 490 | Assert.IsNotNull(item); 491 | } 492 | 493 | /// 494 | /// Get Several Chapters 495 | /// 496 | /// 497 | [TestMethod] 498 | public async Task Test_Lookup_Several_Chapter() 499 | { 500 | List ids = new() 501 | { 502 | "4oBDDqvu2Deo9fifYY5ciE", 503 | "3WKtdf6ZL5EMe1pnRza9ap" 504 | }; 505 | var response = await _client.LookupAsync(ids, LookupType.Chapters, market: "US"); 506 | Assert.IsNotNull(response.Chapters); 507 | } 508 | #endregion Chapters 509 | 510 | #region Shows 511 | /// 512 | /// Get a Show 513 | /// 514 | /// 515 | [TestMethod] 516 | public async Task Test_Lookup_Show() 517 | { 518 | Show item = await _client.LookupAsync( 519 | "4r157jjrIV0bzS6UxhN07i", LookupType.Shows, "GB"); 520 | Assert.IsNotNull(item); 521 | } 522 | 523 | /// 524 | /// Get Multiple Shows 525 | /// 526 | /// 527 | [TestMethod] 528 | public async Task Test_Lookup_Shows() 529 | { 530 | List ids = new List 531 | { 532 | "4r157jjrIV0bzS6UxhN07i", 533 | "2GmNzw8t4uG70rn4XG9zcC" 534 | }; 535 | _list = await _client.LookupAsync(ids, LookupType.Shows, "GB"); 536 | Assert.IsNotNull(_list.Shows); 537 | Assert.IsTrue(_list.Shows.Count == ids.Count); 538 | } 539 | 540 | /// 541 | /// Get a Show's Episodes 542 | /// 543 | /// 544 | [TestMethod] 545 | public async Task Test_Lookup_ShowEpisodes() 546 | { 547 | Paging list = await _client.LookupAsync>( 548 | "4r157jjrIV0bzS6UxhN07i", LookupType.ShowEpisodes, "GB"); 549 | Assert.IsNotNull(list); 550 | Assert.IsTrue(list.Items.Count > 0); 551 | } 552 | 553 | /// 554 | /// Search for a Show 555 | /// 556 | /// 557 | [TestMethod] 558 | public async Task Test_Search_Show() 559 | { 560 | _content = await _client.SearchAsync( 561 | "Famous Fates", new SearchType() { Show = true }, "GB"); 562 | Assert.IsNotNull(_content.Shows); 563 | Assert.IsTrue(_content.Shows.Count > 0); 564 | } 565 | #endregion Shows 566 | 567 | #region Markets 568 | /// 569 | /// Get Available Markets 570 | /// 571 | /// 572 | [TestMethod] 573 | public async Task Test_Lookup_Markets() 574 | { 575 | var result = await _client.LookupAvailableMarkets(); 576 | Assert.IsTrue(result.Markets.Count > 0); 577 | } 578 | #endregion Markets 579 | } 580 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard.Test/Usings.cs: -------------------------------------------------------------------------------- 1 | global using Microsoft.Extensions.Configuration; 2 | global using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | global using Spotify.NetStandard.Client; 4 | global using Spotify.NetStandard.Client.Authentication; 5 | global using Spotify.NetStandard.Client.Authentication.Enums; 6 | global using Spotify.NetStandard.Client.Interfaces; 7 | global using Spotify.NetStandard.Enums; 8 | global using Spotify.NetStandard.Requests; 9 | global using Spotify.NetStandard.Responses; -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard.Test/appsettings.example.json: -------------------------------------------------------------------------------- 1 | { 2 | "client_id": "", 3 | "client_secret": "", 4 | "token": "", 5 | "expires": "01/01/1970 00:00:00", 6 | "type": "User" 7 | } -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.329 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spotify.NetStandard", "Spotify.NetStandard\Spotify.NetStandard.csproj", "{439433FD-5B33-4305-A754-DC2A4A4FF984}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spotify.NetStandard.Test", "Spotify.NetStandard.Test\Spotify.NetStandard.Test.csproj", "{DC082645-06DB-44DD-A8F3-75540679A3A0}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {439433FD-5B33-4305-A754-DC2A4A4FF984}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {439433FD-5B33-4305-A754-DC2A4A4FF984}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {439433FD-5B33-4305-A754-DC2A4A4FF984}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {439433FD-5B33-4305-A754-DC2A4A4FF984}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {DC082645-06DB-44DD-A8F3-75540679A3A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {DC082645-06DB-44DD-A8F3-75540679A3A0}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {DC082645-06DB-44DD-A8F3-75540679A3A0}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {DC082645-06DB-44DD-A8F3-75540679A3A0}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {1585FF9D-CB3A-42A8-AF00-7E6D23653BD2} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Client/Authentication/AccessToken.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Client.Authentication; 2 | 3 | /// 4 | /// Access Token Object 5 | /// 6 | [DataContract] 7 | public class AccessToken 8 | { 9 | /// 10 | /// Access Token 11 | /// 12 | [DataMember(Name = "token")] 13 | public string Token { get; set; } 14 | 15 | /// 16 | /// Refresh 17 | /// 18 | [DataMember(Name = "refresh")] 19 | public string Refresh { get; set; } 20 | 21 | /// 22 | /// Token Expiration Date 23 | /// 24 | [DataMember(Name = "expires")] 25 | public DateTime Expiration { get; set; } 26 | 27 | /// 28 | /// Token Type 29 | /// 30 | [DataMember(Name = "type")] 31 | public TokenType TokenType { get; set; } 32 | 33 | /// 34 | /// Scopes 35 | /// 36 | [DataMember(Name = "scopes")] 37 | public string Scopes { get; set; } 38 | 39 | /// 40 | /// Error 41 | /// 42 | [DataMember(Name = "error")] 43 | public string Error { get; set; } 44 | } 45 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Client/Authentication/Enums/TokenType.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Client.Authentication.Enums; 2 | 3 | /// 4 | /// Authentication Token Type 5 | /// 6 | public enum TokenType : byte 7 | { 8 | /// 9 | /// Access Token 10 | /// 11 | Access, 12 | /// 13 | /// User Token 14 | /// 15 | User 16 | } 17 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Client/Authentication/Internal/AccessCode.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Client.Authentication.Internal 2 | { 3 | /// 4 | /// Access Code 5 | /// 6 | internal class AccessCode 7 | { 8 | private const string error = "error"; 9 | private const string state = "state"; 10 | private const string code = "code"; 11 | 12 | /// 13 | /// An authorization code that can be exchanged for an access token. 14 | /// 15 | public string Code { get; set; } 16 | 17 | /// 18 | /// The value of the state parameter supplied in the request. 19 | /// 20 | public string State { get; set; } 21 | 22 | /// 23 | /// The reason authorization failed, for example: “access_denied” 24 | /// 25 | public string Error { get; set; } 26 | 27 | /// 28 | /// An authorization Uri 29 | /// 30 | public Uri ResponseUri { get; set; } 31 | 32 | /// 33 | /// Redirect Uri 34 | /// 35 | public Uri RedirectUri { get; set; } 36 | 37 | /// 38 | /// Constructor 39 | /// 40 | /// An authorization Uri 41 | /// Redirect Uri 42 | /// QueryString Dictionary 43 | public AccessCode( 44 | Uri responseUri, 45 | Uri redirectUri, 46 | Dictionary dictionary) 47 | { 48 | try 49 | { 50 | ResponseUri = responseUri; 51 | RedirectUri = redirectUri; 52 | if (dictionary != null) 53 | { 54 | if (dictionary.ContainsKey(code)) Code = dictionary[code]; 55 | if (dictionary.ContainsKey(state)) State = dictionary[state]; 56 | if (dictionary.ContainsKey(error)) Error = dictionary[error]; 57 | } 58 | } 59 | finally { } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Client/Authentication/Internal/AuthenticationCache.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Client.Authentication.Internal; 2 | 3 | /// 4 | /// Authentication Cache 5 | /// 6 | internal class AuthenticationCache 7 | { 8 | private const char hash = '#'; 9 | 10 | private readonly string _clientId; 11 | private readonly string _clientSecret; 12 | private readonly AuthenticationClient _client; 13 | private AccessCode _accessCode = null; 14 | private ImplicitGrant _implicitGrant = null; 15 | 16 | /// 17 | /// Map 18 | /// 19 | /// TokenType 20 | /// AuthenticationResponse 21 | /// Refresh Token 22 | /// Access Token 23 | private AccessToken Map(TokenType tokenType, 24 | AuthenticationResponse response, 25 | string refreshToken = null) => 26 | new() 27 | { 28 | TokenType = tokenType, 29 | Token = response.AccessToken, 30 | Refresh = refreshToken ?? response.RefreshToken, 31 | Expiration = DateTime.UtcNow.Add(TimeSpan.FromSeconds(Convert.ToDouble(response.ExpiresIn))), 32 | Scopes = response.Scope, 33 | Error = response.Error 34 | }; 35 | 36 | /// 37 | /// Map 38 | /// 39 | /// ImplicitGrant 40 | /// Access Token 41 | private AccessToken Map(ImplicitGrant response) => 42 | new() 43 | { 44 | TokenType = TokenType.User, 45 | Token = response.AccessToken, 46 | Expiration = DateTime.UtcNow.Add(TimeSpan.FromSeconds(Convert.ToDouble(response.ExpiresIn))), 47 | Error = response.Error 48 | }; 49 | 50 | /// 51 | /// Get Uri Dictionary 52 | /// 53 | /// Uri 54 | /// Dictionary of Key Values 55 | private Dictionary GetUriDictionary(Uri uri) => 56 | string.IsNullOrEmpty(uri.Fragment) 57 | ? uri.Query.QueryStringAsDictionary() 58 | : uri.Fragment.TrimStart(hash) 59 | .QueryStringAsDictionary(); 60 | 61 | /// 62 | /// Constructor 63 | /// 64 | /// Authentication Client 65 | /// Client Id 66 | /// Client Secret 67 | public AuthenticationCache( 68 | AuthenticationClient client, 69 | string clientId, 70 | string clientSecret) => 71 | (_client, _clientId, _clientSecret) = 72 | (client, clientId, clientSecret); 73 | 74 | /// 75 | /// Check And Renew Token 76 | /// 77 | /// Token Type 78 | /// Cancellation Token 79 | /// Access Token 80 | /// AuthAccessTokenRequiredException 81 | /// AuthUserTokenRequiredException 82 | public async Task CheckAndRenewTokenAsync( 83 | TokenType tokenType, 84 | CancellationToken cancellationToken) 85 | { 86 | bool requiresUserToken = tokenType == TokenType.User; 87 | if (AccessToken?.Token == null) 88 | { 89 | if(requiresUserToken) 90 | throw new AuthUserTokenRequiredException(); 91 | AccessToken = await GetClientCredentialsTokenAsync(cancellationToken); 92 | } 93 | else if(AccessToken?.Refresh != null && (AccessToken.Expiration < DateTime.UtcNow)) 94 | AccessToken = await GetRefreshTokenAsync( 95 | AccessToken.Refresh, 96 | AccessToken.TokenType, 97 | cancellationToken); 98 | else 99 | { 100 | if(requiresUserToken && !(AccessToken.TokenType == TokenType.User)) 101 | throw new AuthUserTokenRequiredException(); 102 | } 103 | if(AccessToken?.Token == null || (AccessToken.Expiration < DateTime.UtcNow)) 104 | { 105 | if (requiresUserToken) 106 | throw new AuthUserTokenRequiredException(); 107 | else 108 | throw new AuthAccessTokenRequiredException(); 109 | } 110 | return AccessToken; 111 | } 112 | 113 | /// 114 | /// Get Refresh Token 115 | /// 116 | /// Refresh Token 117 | /// Token Type 118 | /// Cancellation Token 119 | /// Access Token 120 | public async Task GetRefreshTokenAsync( 121 | string refreshToken, 122 | TokenType tokenType, 123 | CancellationToken cancellationToken) 124 | { 125 | var authenticationResponse = 126 | string.IsNullOrEmpty(_clientSecret) ? 127 | await _client.RefreshTokenAsync( 128 | _clientId, 129 | refreshToken, 130 | cancellationToken) : 131 | await _client.RefreshTokenAsync( 132 | _clientId, 133 | _clientSecret, 134 | refreshToken, 135 | cancellationToken); 136 | if (authenticationResponse != null) 137 | AccessToken = Map(tokenType, 138 | authenticationResponse, 139 | refreshToken); 140 | return AccessToken; 141 | } 142 | 143 | /// 144 | /// Get Client Credentials Token - Client Credentials Flow 145 | /// 146 | /// Cancellation Token 147 | /// Access Token 148 | public async Task GetClientCredentialsTokenAsync( 149 | CancellationToken cancellationToken) 150 | { 151 | var authenticationResponse = 152 | await _client.ClientCredentialsAsync( 153 | _clientId, 154 | _clientSecret, 155 | cancellationToken); 156 | if (authenticationResponse != null) 157 | AccessToken = Map(TokenType.Access, authenticationResponse); 158 | return AccessToken; 159 | } 160 | 161 | /// 162 | /// Get Implicit Grant Auth - Implicit Grant Flow 163 | /// 164 | /// Redirect Uri 165 | /// State 166 | /// Scope 167 | /// Show Dialog 168 | /// Authentication Uri 169 | public Uri GetImplicitGrantAuth( 170 | Uri redirectUri, 171 | string state, 172 | string scopes, 173 | bool showDialog) => 174 | _client.GetImplicitGrantRequest(_clientId, scopes, 175 | state, redirectUri.ToString(), showDialog); 176 | 177 | /// 178 | /// Get Implicit Grant Auth - Implicit Grant Flow 179 | /// 180 | /// Response Uri 181 | /// Redirect Uri 182 | /// State Value 183 | /// Access Token 184 | /// AuthTokenValueException 185 | /// AuthTokenStateException 186 | public AccessToken GetImplicitGrantAuth( 187 | Uri responseUri, 188 | Uri redirectUri, 189 | string state) 190 | { 191 | if (responseUri != null) 192 | { 193 | if (responseUri.ToString().Contains(redirectUri.ToString())) 194 | { 195 | if (_implicitGrant?.ResponseUri == null || (_implicitGrant.ResponseUri.ToString() != responseUri.ToString())) 196 | { 197 | _implicitGrant = new ImplicitGrant( 198 | responseUri, redirectUri, 199 | GetUriDictionary(responseUri)); 200 | if (state == null || _implicitGrant.State == state) 201 | if (string.IsNullOrEmpty(_implicitGrant.AccessToken)) 202 | throw new AuthTokenValueException(_implicitGrant.Error); 203 | else 204 | { 205 | AccessToken = Map(_implicitGrant); 206 | return AccessToken; 207 | } 208 | else 209 | throw new AuthTokenStateException(_implicitGrant.State); 210 | } 211 | } 212 | } 213 | return null; 214 | } 215 | 216 | /// 217 | /// Get Authorisation Code - Authorization Code Flow with Proof Key for Code Exchange 218 | /// 219 | /// Redirect Uri 220 | /// State 221 | /// Scope 222 | /// Show Dialog 223 | /// Code Verifier 224 | /// Authentication Uri 225 | public Uri GetAuthorisationCodeUri( 226 | Uri redirectUri, 227 | string state, 228 | string scopes, 229 | bool showDialog, 230 | out string codeVerifier) 231 | { 232 | var verifierChallenge = new VerifierChallenge(); 233 | codeVerifier = verifierChallenge.Verifier; 234 | return _client.GetAuthorisationCodeUri( 235 | _clientId, 236 | verifierChallenge.Challenge, 237 | scopes, 238 | state, 239 | redirectUri.ToString(), 240 | showDialog); 241 | } 242 | 243 | /// 244 | /// Get Authorisation Code Token - Authorization Code Flow with Proof Key for Code Exchange 245 | /// 246 | /// Code Verifier 247 | /// Access Code 248 | /// Cancellation Token 249 | /// Access Token 250 | public async Task GetAuthorisationCodeTokenAsync( 251 | string codeVerifier, 252 | AccessCode accessCode, 253 | CancellationToken cancellationToken) 254 | { 255 | var authenticationResponse = 256 | await _client.GetAuthorisationCodeAsync( 257 | _clientId, 258 | codeVerifier, 259 | accessCode, 260 | cancellationToken); 261 | if (authenticationResponse != null) 262 | AccessToken = Map(TokenType.User, authenticationResponse); 263 | return AccessToken; 264 | } 265 | 266 | /// 267 | /// Get Authorisation Code Proof Key for Code Exchange 268 | /// 269 | /// Response Uri 270 | /// Request Uri 271 | /// State 272 | /// Code Verifier 273 | /// Access Token 274 | public async Task GetAuthorisationCodeAuthAsync( 275 | Uri responseUri, 276 | Uri redirectUri, 277 | string state, 278 | string codeVerifier) 279 | { 280 | if(string.IsNullOrEmpty(codeVerifier)) 281 | throw new AuthCodeVerifierRequiredException(); 282 | if (responseUri != null) 283 | { 284 | if (responseUri.ToString().Contains(redirectUri.ToString())) 285 | { 286 | if (_accessCode?.ResponseUri == null || (_accessCode.ResponseUri.ToString() != responseUri.ToString())) 287 | { 288 | _accessCode = new AccessCode( 289 | responseUri, redirectUri, 290 | responseUri.Query.QueryStringAsDictionary()); 291 | if (state == null || _accessCode.State == state) 292 | { 293 | if (string.IsNullOrEmpty(_accessCode.Code)) 294 | throw new AuthCodeValueException(_accessCode.Error); 295 | else 296 | { 297 | AccessToken = await GetAuthorisationCodeTokenAsync( 298 | codeVerifier, 299 | _accessCode, 300 | new CancellationToken(false)); 301 | return AccessToken; 302 | } 303 | } 304 | else 305 | throw new AuthCodeStateException(_accessCode.State); 306 | } 307 | } 308 | } 309 | return null; 310 | } 311 | 312 | /// 313 | /// Get Authorisation Code Token - Authorisation Code Flow 314 | /// 315 | /// Access Code 316 | /// Cancellation Token 317 | /// Access Token 318 | public async Task GetAuthorisationCodeTokenAsync( 319 | AccessCode accessCode, 320 | CancellationToken cancellationToken) 321 | { 322 | var authenticationResponse = 323 | await _client.GetAuthorisationCodeWithSecretAsync( 324 | _clientId, 325 | _clientSecret, 326 | accessCode, 327 | cancellationToken); 328 | if (authenticationResponse != null) 329 | AccessToken = Map(TokenType.User, 330 | authenticationResponse); 331 | return AccessToken; 332 | } 333 | 334 | /// 335 | /// Get Access Code Auth - Authorisation Code Flow 336 | /// 337 | /// Redirect Uri 338 | /// State 339 | /// Scope 340 | /// Show Dialog 341 | /// Authentication Uri 342 | public Uri GetAccessCodeUri( 343 | Uri redirectUri, 344 | string state, 345 | string scopes, 346 | bool showDialog) => 347 | _client.GetAccessCodeRequest(_clientId, scopes, 348 | state, redirectUri.ToString(), showDialog); 349 | 350 | /// 351 | /// Get Access Code Auth - Authorisation Code Flow 352 | /// 353 | /// Response Uri 354 | /// Redirect Uri 355 | /// State Value 356 | /// Access Token 357 | /// AuthCodeValueException 358 | /// AuthCodeStateException 359 | public async Task GetAccessCodeAuthAsync( 360 | Uri responseUri, 361 | Uri redirectUri, 362 | string state) 363 | { 364 | if (responseUri != null) 365 | { 366 | if (responseUri.ToString().Contains(redirectUri.ToString())) 367 | { 368 | if (_accessCode?.ResponseUri == null || (_accessCode.ResponseUri.ToString() != responseUri.ToString())) 369 | { 370 | _accessCode = new AccessCode( 371 | responseUri, redirectUri, 372 | responseUri.Query.QueryStringAsDictionary()); 373 | if (state == null || _accessCode.State == state) 374 | { 375 | if (string.IsNullOrEmpty(_accessCode.Code)) 376 | throw new AuthCodeValueException(_accessCode.Error); 377 | else 378 | { 379 | AccessToken = await GetAuthorisationCodeTokenAsync( 380 | _accessCode, new CancellationToken(false)); 381 | return AccessToken; 382 | } 383 | } 384 | else 385 | throw new AuthCodeStateException(_accessCode.State); 386 | } 387 | } 388 | } 389 | return null; 390 | } 391 | 392 | /// 393 | /// Access Token 394 | /// 395 | public AccessToken AccessToken { get; set; } = null; 396 | } 397 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Client/Authentication/Internal/AuthenticationClient.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Client.Authentication.Internal 2 | { 3 | /// 4 | /// Authentication Client 5 | /// 6 | internal class AuthenticationClient : SimpleServiceClient 7 | { 8 | // Endpoint 9 | private readonly Uri host_name = new("https://accounts.spotify.com"); 10 | // Token Auth 11 | private const string auth_header = "Authorization"; 12 | private const string auth_basic = "Basic"; 13 | private const string grant_type = "grant_type"; 14 | private const string client_credentials = "client_credentials"; 15 | private const string token_uri = "/api/token"; 16 | // Get Auth 17 | private const string response_type = "response_type"; 18 | private const string code_value = "code"; 19 | private const string client_id = "client_id"; 20 | private const string scope_value = "scope"; 21 | private const string state_value = "state"; 22 | private const string token_value = "token"; 23 | private const string redirect_uri = "redirect_uri"; 24 | private const string auth_uri = "/authorize"; 25 | // Url Auth 26 | private const string authorization_code = "authorization_code"; 27 | private const string refresh_token = "refresh_token"; 28 | private const string show_dialog = "show_dialog"; 29 | // PKCE Auth 30 | private const string code_challenge_method_type = "S256"; 31 | private const string code_challenge_method = "code_challenge_method"; 32 | private const string code_challenge = "code_challenge"; 33 | private const string code_verifier = "code_verifier"; 34 | 35 | /// 36 | /// Get Headers 37 | /// 38 | /// Client Id 39 | /// Client Secret 40 | /// Dictionary Of String, String 41 | private Dictionary GetHeaders( 42 | string clientId, 43 | string clientSecret) 44 | { 45 | string auth = Convert.ToBase64String( 46 | Encoding.ASCII.GetBytes($"{clientId}:{clientSecret}")); 47 | Dictionary headers = new() 48 | { 49 | { auth_header, $"{auth_basic} {auth}"} 50 | }; 51 | return headers; 52 | } 53 | 54 | /// 55 | /// Client Credentials - Client Credentials Flow 56 | /// 57 | /// Client Id 58 | /// Client Secret 59 | /// Cancellation Token 60 | /// Authentication Response 61 | public Task ClientCredentialsAsync( 62 | string clientId, 63 | string clientSecret, 64 | CancellationToken cancellationToken) 65 | { 66 | var headers = GetHeaders(clientId, clientSecret); 67 | Dictionary request = new() 68 | { 69 | { grant_type, client_credentials } 70 | }; 71 | return PostRequestAsync, AuthenticationResponse>( 72 | host_name, 73 | token_uri, 74 | null, 75 | cancellationToken, 76 | request, 77 | null, 78 | headers, 79 | true); 80 | } 81 | 82 | /// 83 | /// Refresh Token - Authorisation Code Flow with PKCE 84 | /// 85 | /// Client Id 86 | /// Refresh Token 87 | /// Cancellation Token 88 | /// Authentication Response 89 | public Task RefreshTokenAsync( 90 | string clientId, 91 | string refreshToken, 92 | CancellationToken cancellationToken) 93 | { 94 | var request = new Dictionary() 95 | { 96 | { grant_type, refresh_token }, 97 | { refresh_token, refreshToken }, 98 | { client_id, clientId } 99 | }; 100 | return PostRequestAsync, AuthenticationResponse>( 101 | host_name, 102 | token_uri, 103 | null, 104 | cancellationToken, 105 | request, 106 | null, 107 | null, 108 | true); 109 | } 110 | 111 | /// 112 | /// Implicit Grant Request - Implicit Grant Flow 113 | /// 114 | /// Client Id 115 | /// Comma delimited scopes 116 | /// State 117 | /// Redirect Url 118 | /// Show Dialog 119 | /// Url 120 | public Uri GetImplicitGrantRequest( 121 | string clientId, 122 | string scopes, 123 | string state, 124 | string redirectUrl, 125 | bool showDialog) 126 | { 127 | var request = new Dictionary() 128 | { 129 | { response_type, token_value }, 130 | { client_id, clientId }, 131 | { scope_value, scopes }, 132 | { state_value, HttpUtility.UrlEncode(state) }, 133 | { redirect_uri, HttpUtility.UrlEncode(redirectUrl) }, 134 | { show_dialog, $"{showDialog}".ToLower() } 135 | }; 136 | return GetUri(host_name, auth_uri, request); 137 | } 138 | 139 | /// 140 | /// Get Authoristion Code - Authorisation Code Flow with PKCE 141 | /// 142 | /// Client Id 143 | /// Challenge 144 | /// Scopes 145 | /// State 146 | /// Redirect Uri 147 | /// Show Dialog 148 | /// Uri 149 | public Uri GetAuthorisationCodeUri( 150 | string clientId, 151 | string challenge, 152 | string scopes, 153 | string state, 154 | string redirectUrl, 155 | bool showDialog) 156 | { 157 | var request = new Dictionary() 158 | { 159 | { client_id, clientId }, 160 | { response_type, code_value }, 161 | { redirect_uri, HttpUtility.UrlEncode(redirectUrl) }, 162 | { code_challenge_method, code_challenge_method_type }, 163 | { code_challenge, challenge }, 164 | { scope_value, scopes }, 165 | { state_value, HttpUtility.UrlEncode(state) }, 166 | { show_dialog, $"{showDialog}".ToLower() } 167 | }; 168 | return GetUri(host_name, auth_uri, request); 169 | } 170 | 171 | /// 172 | /// Get Authorisation Code - Authorisation Code Flow with PKCE 173 | /// 174 | /// Client Id 175 | /// Value of this parameter must match the value of the one that your app generated 176 | /// Access Code 177 | /// Cancellation Token 178 | /// Authentication Response 179 | public Task GetAuthorisationCodeAsync( 180 | string clientId, 181 | string verifier, 182 | AccessCode accessCode, 183 | CancellationToken cancellationToken) 184 | { 185 | var request = new Dictionary() 186 | { 187 | { client_id, clientId }, 188 | { grant_type, authorization_code }, 189 | { code_value, accessCode.Code }, 190 | { redirect_uri, $"{accessCode.RedirectUri}" }, 191 | { code_verifier, verifier } 192 | }; 193 | return PostRequestAsync, AuthenticationResponse>( 194 | hostname: host_name, 195 | relativeUri: token_uri, 196 | null, 197 | cancellationToken: cancellationToken, 198 | request, 199 | null, 200 | null, 201 | true); 202 | } 203 | 204 | /// 205 | /// Authorisation Code - Authorisation Code Flow 206 | /// 207 | /// Client Id 208 | /// Client Secret 209 | /// Access Code 210 | /// Cancellation Token 211 | /// Authentication Response 212 | public Task GetAuthorisationCodeWithSecretAsync( 213 | string clientId, 214 | string clientSecret, 215 | AccessCode accessCode, 216 | CancellationToken cancellationToken) 217 | { 218 | var headers = GetHeaders(clientId, clientSecret); 219 | var request = new Dictionary() 220 | { 221 | { grant_type, authorization_code }, 222 | { code_value, accessCode.Code }, 223 | { redirect_uri, $"{accessCode.RedirectUri}" } 224 | }; 225 | return PostRequestAsync, AuthenticationResponse>( 226 | host_name, 227 | token_uri, 228 | null, 229 | cancellationToken, 230 | request, 231 | null, 232 | headers, 233 | true); 234 | } 235 | 236 | /// 237 | /// Refresh Token - Authorization Code Flow 238 | /// 239 | /// Client Id 240 | /// Client Secret 241 | /// Refresh Token 242 | /// Cancellation Token 243 | /// Authentication Response 244 | public Task RefreshTokenAsync( 245 | string clientId, 246 | string clientSecret, 247 | string refreshToken, 248 | CancellationToken cancellationToken) 249 | { 250 | var headers = GetHeaders(clientId, clientSecret); 251 | var request = new Dictionary() 252 | { 253 | { grant_type, refresh_token }, 254 | { refresh_token, refreshToken } 255 | }; 256 | return PostRequestAsync, AuthenticationResponse>( 257 | host_name, 258 | token_uri, 259 | null, 260 | cancellationToken, 261 | request, 262 | null, 263 | headers, 264 | true); 265 | } 266 | 267 | /// 268 | /// Access Code Request - Authorization Code Flow 269 | /// 270 | /// Client Id 271 | /// Comma delimited scopes 272 | /// State 273 | /// Redirect Url 274 | /// Show Dialog 275 | /// Url 276 | public Uri GetAccessCodeRequest( 277 | string clientId, 278 | string scopes, 279 | string state, 280 | string redirectUrl, 281 | bool showDialog) 282 | { 283 | var request = new Dictionary() 284 | { 285 | { response_type, code_value }, 286 | { client_id, clientId }, 287 | { scope_value, scopes }, 288 | { state_value, HttpUtility.UrlEncode(state) }, 289 | { redirect_uri, HttpUtility.UrlEncode(redirectUrl) }, 290 | { show_dialog, $"{showDialog}".ToLower() } 291 | }; 292 | return GetUri(host_name, auth_uri, request); 293 | } 294 | } 295 | } 296 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Client/Authentication/Internal/AuthenticationResponse.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Client.Authentication.Internal; 2 | 3 | /// 4 | /// Authentication Response 5 | /// 6 | [DataContract] 7 | internal class AuthenticationResponse 8 | { 9 | /// 10 | /// An access token that can be provided in subsequent calls 11 | /// 12 | [DataMember(Name = "access_token")] 13 | public string AccessToken { get; set; } 14 | 15 | /// 16 | /// How the access token may be used: always “Bearer”. 17 | /// 18 | [DataMember(Name = "token_type")] 19 | public string TokenType { get; set; } 20 | 21 | /// 22 | /// A space-separated list of scopes which have been granted for this access token 23 | /// 24 | [DataMember(Name = "scope", EmitDefaultValue = false)] 25 | public string Scope { get; set; } 26 | 27 | /// 28 | /// The time period (in seconds) for which the access token is valid. 29 | /// 30 | [DataMember(Name = "expires_in", EmitDefaultValue = false)] 31 | public int ExpiresIn { get; set; } 32 | 33 | /// 34 | /// A token that can be sent to the Spotify Accounts service in place of an authorization code 35 | /// 36 | [DataMember(Name = "refresh_token")] 37 | public string RefreshToken { get; set; } 38 | 39 | /// 40 | /// The reason authorisation failed, for example: “access_denied”. 41 | /// 42 | [DataMember(Name = "error")] 43 | public string Error { get; set; } 44 | } 45 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Client/Authentication/Internal/ImplicitGrant.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Client.Authentication.Internal; 2 | 3 | /// 4 | /// Implicit Grant 5 | /// 6 | internal class ImplicitGrant 7 | { 8 | private const string error = "error"; 9 | private const string state = "state"; 10 | private const string access_token = "access_token"; 11 | private const string token_type = "token_type"; 12 | private const string expires_in = "expires_in"; 13 | 14 | /// 15 | /// An access token that can be provided in subsequent calls, for example to Spotify Web API services. 16 | /// 17 | public string AccessToken { get; set; } 18 | 19 | /// 20 | /// Value: “Bearer” 21 | /// 22 | public string TokenType { get; set; } 23 | 24 | /// 25 | /// The time period (in seconds) for which the access token is valid. 26 | /// 27 | public string ExpiresIn { get; set; } 28 | 29 | /// 30 | /// The value of the state parameter supplied in the request. 31 | /// 32 | public string State { get; set; } 33 | 34 | /// 35 | /// The reason authorization failed, for example: “access_denied” 36 | /// 37 | public string Error { get; set; } 38 | 39 | /// 40 | /// An authorization Uri 41 | /// 42 | public Uri ResponseUri { get; set; } 43 | 44 | /// 45 | /// Redirect Uri 46 | /// 47 | public Uri RedirectUri { get; set; } 48 | 49 | /// 50 | /// Constructor 51 | /// 52 | /// An authorization Uri 53 | /// Redirect Uri 54 | /// QueryString Dictionary 55 | public ImplicitGrant( 56 | Uri responseUri, 57 | Uri redirectUri, 58 | Dictionary dictionary) 59 | { 60 | try 61 | { 62 | ResponseUri = responseUri; 63 | RedirectUri = redirectUri; 64 | if (dictionary != null) 65 | { 66 | if (dictionary.ContainsKey(access_token)) AccessToken = dictionary[access_token]; 67 | if (dictionary.ContainsKey(token_type)) TokenType = dictionary[token_type]; 68 | if (dictionary.ContainsKey(expires_in)) ExpiresIn = dictionary[expires_in]; 69 | if (dictionary.ContainsKey(state)) State = dictionary[state]; 70 | if (dictionary.ContainsKey(error)) Error = dictionary[error]; 71 | } 72 | } 73 | finally { } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Client/Authentication/Internal/VerifierChallenge.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Client.Authentication.Internal; 2 | 3 | /// 4 | /// Verifier Challenge Request for Proof Key for Code Exchange 5 | /// 6 | internal class VerifierChallenge 7 | { 8 | private const int verifier_length = 128; 9 | private const string verifier_content = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"; 10 | private static readonly Random random = new((int)DateTime.Now.Ticks); 11 | 12 | /// 13 | /// Get Verifier 14 | /// 15 | /// Cryptographically random string between 43 and 128 characters in length 16 | private string GetVerifier() 17 | { 18 | var verifier = new StringBuilder(); 19 | for(var i = 0; i < verifier_length; i++) 20 | verifier.Append(verifier_content[random.Next(0, verifier_content.Length)]); 21 | return verifier.ToString(); 22 | } 23 | 24 | /// 25 | /// Base 64 Url Encode 26 | /// 27 | /// Values to Encode 28 | /// Encoded Values 29 | private static string Base64UrlEncode(byte[] value) => 30 | Convert.ToBase64String(value) 31 | .Replace('+', '-') 32 | .Replace('/', '_') 33 | .Replace("=", ""); 34 | 35 | /// 36 | /// Get Challenge 37 | /// 38 | /// Base 64 Encoded Verifier Hashed with SHA256 39 | private string GetChallenge() 40 | { 41 | var crypt = new SHA256Managed(); 42 | var hash = crypt.ComputeHash(Encoding.UTF8.GetBytes(Verifier)); 43 | return Base64UrlEncode(hash); 44 | } 45 | 46 | /// 47 | /// Cryptographically random string between 43 and 128 characters in length. It can contain letters, digits, underscores, periods, hyphens, or tildes 48 | /// 49 | public string Verifier { get; private set; } 50 | 51 | /// 52 | /// Base 64 Encoded Hash of Code Verifier using the SHA256 algorithm 53 | /// 54 | public string Challenge { get; private set; } 55 | 56 | /// 57 | /// Constructor 58 | /// 59 | public VerifierChallenge() 60 | { 61 | Verifier = GetVerifier(); 62 | Challenge = GetChallenge(); 63 | } 64 | } -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Client/Exceptions/AuthCodeStateException.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Client.Exceptions; 2 | 3 | /// 4 | /// Auth Code State Error 5 | /// 6 | public class AuthCodeStateException : AuthException 7 | { 8 | /// 9 | /// Constructor 10 | /// 11 | /// Message 12 | public AuthCodeStateException(string message) : base(message) { } 13 | } 14 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Client/Exceptions/AuthCodeValueException.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Client.Exceptions; 2 | 3 | /// 4 | /// Auth Code Value Error 5 | /// 6 | public class AuthCodeValueException : AuthException 7 | { 8 | /// 9 | /// Constructor 10 | /// 11 | /// Message 12 | public AuthCodeValueException(string message) : base(message) { } 13 | } 14 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Client/Exceptions/AuthCodeVerifierRequiredException.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Client.Exceptions; 2 | 3 | /// 4 | /// Auth Code Verifier Expired or Required Error 5 | /// 6 | public class AuthCodeVerifierRequiredException : AuthException { } 7 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Client/Exceptions/AuthException.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Client.Exceptions; 2 | 3 | /// 4 | /// Auth Exception 5 | /// 6 | public class AuthException : Exception 7 | { 8 | /// 9 | /// Constructor 10 | /// 11 | public AuthException() : base() { } 12 | 13 | /// 14 | /// Constructor 15 | /// 16 | /// Error Message 17 | public AuthException(string message) : base(message) { } 18 | } 19 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Client/Exceptions/AuthTokenRequiredException.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Client.Exceptions; 2 | 3 | /// 4 | /// Auth Token Expired or Required Error 5 | /// 6 | public class AuthTokenRequiredException : AuthException { } 7 | 8 | /// 9 | /// Auth User Token Expired or Required Error 10 | /// 11 | public class AuthUserTokenRequiredException : AuthTokenRequiredException { } 12 | 13 | /// 14 | /// Auth Access Token Expired or Required Error 15 | /// 16 | public class AuthAccessTokenRequiredException : AuthTokenRequiredException { } 17 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Client/Exceptions/AuthTokenStateException.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Client.Exceptions; 2 | 3 | /// 4 | /// Auth Token State Error 5 | /// 6 | public class AuthTokenStateException : AuthException 7 | { 8 | /// 9 | /// Constructor 10 | /// 11 | /// Message 12 | public AuthTokenStateException(string message) : base(message) { } 13 | } 14 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Client/Exceptions/AuthTokenValueException.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Client.Exceptions; 2 | 3 | /// 4 | /// Auth Token Value Error 5 | /// 6 | public class AuthTokenValueException : AuthException 7 | { 8 | /// 9 | /// Constructor 10 | /// 11 | /// Message 12 | public AuthTokenValueException(string message) : base(message) { } 13 | } 14 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Client/Internal/Extensions.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Client.Internal; 2 | 3 | /// 4 | /// Extension Methods 5 | /// 6 | internal static class Extensions 7 | { 8 | private const string comma = ","; 9 | private const string track = "track"; 10 | private const string episode = "episode"; 11 | 12 | /// 13 | /// Get Property Description 14 | /// 15 | /// Property Info 16 | /// Description as String 17 | private static string GetPropertyDescription( 18 | this PropertyInfo info) => 19 | info.GetCustomAttributes(typeof(DescriptionAttribute), false) 20 | .Cast() 21 | .Select(x => x.Description) 22 | .FirstOrDefault(); 23 | 24 | /// 25 | /// From Bools 26 | /// 27 | /// Source Type 28 | /// Type 29 | /// String Array 30 | private static string[] FromBools( 31 | TBool source) 32 | { 33 | List results = null; 34 | if (source != null) 35 | { 36 | foreach (PropertyInfo info in typeof(TBool).GetProperties()) 37 | { 38 | if (info.CanRead && 39 | info.PropertyType == typeof(bool?)) 40 | { 41 | object value = info.GetValue(source, null); 42 | if (value != null && (bool)value) 43 | { 44 | results ??= new List(); 45 | results.Add(info.GetPropertyDescription()); 46 | } 47 | } 48 | } 49 | } 50 | return results?.ToArray(); 51 | } 52 | 53 | /// 54 | /// Get Dictionary Value or Default 55 | /// 56 | /// Key Type 57 | /// Value Type 58 | /// Dictionary 59 | /// Key 60 | /// Default Value 61 | /// 62 | public static TValue GetValueOrDefault( 63 | this Dictionary dictionary, 64 | TKey key, TValue defaultValue = default) 65 | { 66 | if (dictionary == null) { throw new ArgumentNullException(nameof(dictionary)); } 67 | if (key == null) { throw new ArgumentNullException(nameof(key)); } 68 | return dictionary.TryGetValue(key, out TValue value) ? value : defaultValue; 69 | } 70 | 71 | /// 72 | /// Get Description 73 | /// 74 | /// Value Type 75 | /// Value 76 | /// Description as String 77 | public static string GetDescription( 78 | this TValue value) 79 | { 80 | FieldInfo field = typeof(TValue).GetField(value.ToString()); 81 | return field.GetCustomAttributes(typeof(DescriptionAttribute), false) 82 | .Cast().Select(x => x.Description).FirstOrDefault(); 83 | } 84 | 85 | /// 86 | /// Get Array of String as Delimited String 87 | /// 88 | /// Array of Strings 89 | /// Comma delimited String of Strings 90 | public static string AsDelimitedString(this string[] items) => 91 | string.Join(comma, items); 92 | 93 | /// 94 | /// Get QueryString As Dictionary 95 | /// 96 | /// Source QueryString 97 | /// Dictionary of Key Values from QueryString 98 | public static Dictionary QueryStringAsDictionary( 99 | this string querystring) 100 | { 101 | NameValueCollection nvc = HttpUtility.ParseQueryString(querystring); 102 | return nvc.AllKeys.ToDictionary(k => k, k => nvc[k]); 103 | } 104 | 105 | /// 106 | /// Get Scope 107 | /// 108 | /// Scope 109 | /// Results 110 | public static string Get(this Scope scope) => 111 | FromBools(scope)?.AsDelimitedString(); 112 | 113 | /// 114 | /// Get Include Group 115 | /// 116 | /// Include Group Object 117 | /// Results 118 | public static string[] Get(this IncludeGroup includeGroup) => 119 | FromBools(includeGroup)?.ToArray(); 120 | 121 | /// 122 | /// Get Search Type 123 | /// 124 | /// Search Type Object 125 | /// Results 126 | public static string[] Get(this SearchType searchType) => 127 | FromBools(searchType)?.ToArray(); 128 | 129 | /// 130 | /// Set Parameter 131 | /// 132 | /// Parameters 133 | /// Prefix 134 | /// Tuneable Track Object 135 | public static void SetParameter( 136 | this TuneableTrack tuneableTrack, 137 | Dictionary parameters, 138 | string prefix) 139 | { 140 | if (tuneableTrack != null) 141 | { 142 | foreach (PropertyInfo info in typeof(TuneableTrack).GetProperties()) 143 | { 144 | if (info.CanRead) 145 | { 146 | object value = info.GetValue(tuneableTrack, null); 147 | if (value != null) 148 | { 149 | parameters.Add($"{prefix}_{info.GetDescription()}", 150 | value.ToString()); 151 | } 152 | } 153 | } 154 | } 155 | } 156 | 157 | /// 158 | /// Object as Type 159 | /// 160 | /// Object Type 161 | /// Object 162 | /// Type 163 | public static TObject AsType(this object obj) => 164 | obj != null 165 | ? JsonConvert.DeserializeObject(obj.ToString()) : 166 | default; 167 | 168 | /// 169 | /// As Track 170 | /// 171 | /// 172 | /// 173 | public static Track AsTrack(this object obj) 174 | { 175 | var item = obj.AsType(); 176 | return item?.Type == track ? item : null; 177 | } 178 | 179 | /// 180 | /// As Episode 181 | /// 182 | /// 183 | /// 184 | public static Episode AsEpisode(this object obj) 185 | { 186 | var item = obj.AsType(); 187 | return item?.Type == episode ? item : null; 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Client/Internal/Helpers.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Client.Internal; 2 | 3 | /// 4 | /// Helper Methods 5 | /// 6 | internal static class Helpers 7 | { 8 | /// 9 | /// Get Playlist Tracks Request 10 | /// 11 | /// Uris 12 | /// (Optional) Uri Positions 13 | /// (Optional) Snapshot Id 14 | /// 15 | public static PlaylistTracksRequest GetPlaylistTracksRequest( 16 | List uris, 17 | List> uriPositions = null, 18 | string snapshotId = null) 19 | { 20 | var request = new PlaylistTracksRequest() 21 | { 22 | Tracks = uris.Select(uri => 23 | new PositionUriRequest() 24 | { 25 | Uri = uri 26 | }).ToList(), 27 | SnapshotId = snapshotId, 28 | }; 29 | for (int i = 0; i < request.Tracks.Count(); i++) 30 | { 31 | if (uriPositions?.Count > 0 && i < uriPositions.Count) 32 | request.Tracks[i].Positions = uriPositions[i]; 33 | } 34 | return request; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Client/Internal/SimpleServiceResult.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Client.Internal; 2 | 3 | /// 4 | /// Simple Service Result 5 | /// 6 | /// Result 7 | /// Error Result 8 | internal class SimpleServiceResult 9 | { 10 | /// 11 | /// Result 12 | /// 13 | public TResult Result { get; set; } 14 | 15 | /// 16 | /// Error Result 17 | /// 18 | public TErrorResult ErrorResult { get; set; } 19 | 20 | /// 21 | /// Http Status Code 22 | /// 23 | public HttpStatusCode HttpStatusCode { get; set; } 24 | } 25 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Client/SpotifyClientFactory.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Client; 2 | 3 | /// 4 | /// Spotify Client Factory 5 | /// 6 | public class SpotifyClientFactory 7 | { 8 | private static readonly AuthenticationClient _authenticationClient = new(); 9 | private static readonly Dictionary _authenticationCache = new(); 10 | 11 | /// 12 | /// Get or Add Authentication Cache 13 | /// 14 | /// Spotify Client Id 15 | /// Spotify Client Secret 16 | /// Authentication Cache 17 | private static AuthenticationCache GetOrAddAuthenticationCache( 18 | string clientId, 19 | string clientSecret) 20 | { 21 | if (!_authenticationCache.ContainsKey(clientId)) 22 | { 23 | var authenticationCache = new AuthenticationCache( 24 | _authenticationClient, clientId, clientSecret); 25 | _authenticationCache[clientId] = authenticationCache; 26 | } 27 | return _authenticationCache[clientId]; 28 | } 29 | 30 | /// 31 | /// Create Spotify Client 32 | /// 33 | /// (Required) Spotify Client Id 34 | /// (Optional) Spotify Client Secret 35 | /// Spotify Client 36 | public static ISpotifyClient CreateSpotifyClient( 37 | string clientId, 38 | string clientSecret = null) => 39 | new SpotifyClient(GetOrAddAuthenticationCache(clientId, clientSecret)); 40 | 41 | /// 42 | /// Create Spotify Client 43 | /// 44 | /// (Required) Http Client 45 | /// (Required) Spotify Client Id 46 | /// (Optional) Spotify Client Secret 47 | /// Spotify Client 48 | public static ISpotifyClient CreateSpotifyClient( 49 | HttpClient httpClient, 50 | string clientId, 51 | string clientSecret = null) => 52 | new SpotifyClient(GetOrAddAuthenticationCache(clientId, clientSecret), httpClient); 53 | } 54 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Enums/FollowType.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Enums; 2 | 3 | /// 4 | /// Follow Type 5 | /// 6 | public enum FollowType : byte 7 | { 8 | /// 9 | /// User 10 | /// 11 | [Description("user")] 12 | User, 13 | /// 14 | /// Artist 15 | /// 16 | [Description("artist")] 17 | Artist 18 | } -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Enums/LookupType.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Enums; 2 | 3 | /// 4 | /// Lookup Type 5 | /// 6 | public enum LookupType : byte 7 | { 8 | /// 9 | /// Categories 10 | /// 11 | [Description("browse/categories")] 12 | Categories, 13 | /// 14 | /// Category Playlists 15 | /// 16 | [Description("browse/categories_playlists")] 17 | CategoriesPlaylists, 18 | /// 19 | /// Artists 20 | /// 21 | [Description("artists")] 22 | Artists, 23 | /// 24 | /// Albums 25 | /// 26 | [Description("albums")] 27 | Albums, 28 | /// 29 | /// Tracks 30 | /// 31 | [Description("tracks")] 32 | Tracks, 33 | /// 34 | /// Album Tracks 35 | /// 36 | [Description("albums_tracks")] 37 | AlbumTracks, 38 | /// 39 | /// Artist Albums 40 | /// 41 | [Description("artists_albums")] 42 | ArtistAlbums, 43 | /// 44 | /// Playlists 45 | /// 46 | [Description("playlists")] 47 | Playlist, 48 | /// 49 | /// Playlist Tracks 50 | /// 51 | [Description("playlists_tracks")] 52 | PlaylistTracks, 53 | /// 54 | /// Audio Features 55 | /// 56 | [Description("audio-features")] 57 | AudioFeatures, 58 | /// 59 | /// Audio Analysis 60 | /// 61 | [Description("audio-analysis")] 62 | AudioAnalysis, 63 | /// 64 | /// Episodes 65 | /// 66 | [Description("episodes")] 67 | Episodes, 68 | /// 69 | /// Shows 70 | /// 71 | [Description("shows")] 72 | Shows, 73 | /// 74 | /// Show Episodes 75 | /// 76 | [Description("shows_episodes")] 77 | ShowEpisodes, 78 | /// 79 | /// Audiobooks 80 | /// 81 | [Description("audiobooks")] 82 | Audiobooks, 83 | /// 84 | /// Audiobook Chapters 85 | /// 86 | [Description("audiobooks_chapters")] 87 | AudiobookChapters, 88 | /// 89 | /// Chapters 90 | /// 91 | [Description("chapters")] 92 | Chapters 93 | } 94 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Enums/NavigateType.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Enums; 2 | 3 | /// 4 | /// Navigate Type 5 | /// 6 | public enum NavigateType 7 | { 8 | /// 9 | /// None 10 | /// 11 | None = 0, 12 | /// 13 | /// Navigate Previous 14 | /// 15 | Previous = 1, 16 | /// 17 | /// Navigate Next 18 | /// 19 | Next = 2 20 | } 21 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Enums/RepeatState.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Enums; 2 | 3 | /// 4 | /// Repeat State 5 | /// 6 | public enum RepeatState : byte 7 | { 8 | /// 9 | /// Will repeat the current track 10 | /// 11 | [Description("track")] 12 | Track, 13 | /// 14 | /// Will repeat the current context. 15 | /// 16 | [Description("context")] 17 | Context, 18 | /// 19 | /// Will turn repeat off. 20 | /// 21 | [Description("off")] 22 | Off 23 | } 24 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Enums/TimeRange.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Enums; 2 | 3 | /// 4 | /// Time Range 5 | /// 6 | public enum TimeRange : byte 7 | { 8 | /// 9 | /// Calculated from several years of data and including all new data as it becomes available 10 | /// 11 | [Description("long_term")] 12 | LongTerm, 13 | /// 14 | /// Approximately last 6 months 15 | /// 16 | [Description("medium_term")] 17 | MediumTerm, 18 | /// 19 | /// Approximately last 4 weeks 20 | /// 21 | [Description("short_term")] 22 | ShortTerm 23 | } -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Requests/Cursor.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Requests; 2 | 3 | /// 4 | /// Cursor Object 5 | /// 6 | [DataContract] 7 | public class Cursor 8 | { 9 | /// 10 | /// The cursor to use as key to find the next page of items. 11 | /// 12 | [DataMember(Name = "after")] 13 | public string After { get; set; } 14 | 15 | /// 16 | /// URL to the next page of items. (null if none) 17 | /// 18 | [DataMember(Name = "next")] 19 | public string Next { get; set; } 20 | 21 | /// 22 | /// The cursor to use as key to find the previous page of items. 23 | /// 24 | [DataMember(Name = "before")] 25 | public string Before { get; set; } 26 | 27 | /// 28 | /// The offset of the items returned (as set in the query or by default). 29 | /// 30 | [DataMember(Name = "offset")] 31 | public int? Offset { get; set; } 32 | 33 | /// 34 | /// The maximum number of items in the response (as set in the query or by default). 35 | /// 36 | [DataMember(Name = "limit")] 37 | public int? Limit { get; set; } 38 | } 39 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Requests/DevicesRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Requests; 2 | 3 | /// 4 | /// Devices Request Object 5 | /// 6 | [DataContract] 7 | public class DevicesRequest 8 | { 9 | /// 10 | /// (Required) List containing the ID of the device on which playback should be started/transferred. Although an array is accepted, only a single id is currently supported. 11 | /// 12 | [DataMember(Name = "device_ids")] 13 | public List DeviceIds { get; set; } 14 | 15 | /// 16 | /// (Optional) true: ensure playback happens on new device. false or not provided: keep the current playback state. 17 | /// 18 | [DataMember(Name = "play")] 19 | public bool? Play { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Requests/IncludeGroup.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Requests; 2 | 3 | /// 4 | /// Include Group 5 | /// 6 | public class IncludeGroup 7 | { 8 | /// 9 | /// Album 10 | /// 11 | [Description("album")] 12 | public bool? Album { get; set; } 13 | 14 | /// 15 | /// Single 16 | /// 17 | [Description("single")] 18 | public bool? Single { get; set; } 19 | 20 | /// 21 | /// Appears On 22 | /// 23 | [Description("appears_on")] 24 | public bool? AppearsOn { get; set; } 25 | 26 | /// 27 | /// Compliation 28 | /// 29 | [Description("compilation")] 30 | public bool? Compilation { get; set; } 31 | } 32 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Requests/Page.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Requests; 2 | 3 | /// 4 | /// Page 5 | /// 6 | [DataContract] 7 | public class Page 8 | { 9 | private int _page; 10 | 11 | /// 12 | /// The total number of items available to return. 13 | /// 14 | [DataMember(Name = "total")] 15 | public int Total { get; set; } 16 | 17 | /// 18 | /// The offset of the items returned (as set in the query or by default). 19 | /// 20 | [DataMember(Name = "offset")] 21 | public int Offset { get; set; } 22 | 23 | /// 24 | /// The maximum number of items in the response (as set in the query or by default). 25 | /// 26 | [DataMember(Name = "limit")] 27 | public int Limit { get; set; } 28 | 29 | /// 30 | /// Page Count 31 | /// 32 | public int Count 33 | { 34 | get { return (int)Math.Ceiling((double)Total / Limit); } 35 | } 36 | 37 | /// 38 | /// Get / Set Current Page 39 | /// 40 | public int Current 41 | { 42 | get 43 | { 44 | _page = (int)Math.Ceiling((double)Total / Offset); 45 | return _page <= 0 ? 1 : _page; 46 | } 47 | set 48 | { 49 | _page = (value < 1) ? 1 : (value > Count) ? Count : value; 50 | Offset = (_page - 1) * Limit; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Requests/PlaybackRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Requests; 2 | 3 | /// 4 | /// Playback Request Object 5 | /// 6 | [DataContract] 7 | public class PlaybackRequest 8 | { 9 | /// 10 | /// (Optional) Spotify URI of the context to play. Valid contexts are albums, artists, playlists. Example: spotify:album:1Je1IMUlBXcx1Fz0WE7oPT 11 | /// 12 | [DataMember(Name = "context_uri")] 13 | public string ContextUri { get; set; } 14 | 15 | /// 16 | /// (Optional) A JSON array of the Spotify track URIs to play. Example: spotify:track:4iV5W9uYEdYUVa79Axb7Rh, spotify:track:1301WleyT98MSxVHPZCA6M 17 | /// 18 | [DataMember(Name = "uris")] 19 | public List Uris { get; set; } 20 | 21 | /// 22 | /// (Optional) Indicates from where in the context playback should start. Only available when ContextUri corresponds to an album or playlist object, or when the uris parameter is used. “position” is zero based and can’t be negative. Example: PositionRequest with Position = 5 or a UriRequest with Uri representing the uri of the item to start at. Example: UriRequest with Uri = "spotify:track:1301WleyT98MSxVHPZCA6M" 23 | /// 24 | [DataMember(Name = "offset")] 25 | public object Offset { get; set; } 26 | 27 | /// 28 | /// (Optional) Indicates from what position to start playback. Must be a positive number. Passing in a position that is greater than the length of the track will cause the player to start playing the next song. 29 | /// 30 | [DataMember(Name = "position_ms")] 31 | public long? Position { get; set; } 32 | } 33 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Requests/PlaylistReorderRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Requests; 2 | 3 | /// 4 | /// Playlist Reorder Request Object 5 | /// 6 | [DataContract] 7 | public class PlaylistReorderRequest 8 | { 9 | /// 10 | /// (Required) The position of the first track to be reordered. 11 | /// 12 | [DataMember(Name = "range_start")] 13 | public int RangeStart { get; set; } 14 | 15 | /// 16 | /// (Required) The position where the tracks should be inserted. To reorder the tracks to the end of the playlist, simply set insert_before to the position after the last track. 17 | /// 18 | [DataMember(Name = "insert_before")] 19 | public int InsertBefore { get; set; } 20 | 21 | /// 22 | /// (Optional) The amount of tracks to be reordered. Defaults to 1 if not set. The range of tracks to be reordered begins from the RangeStart position, and includes the RangeLength subsequent tracks. 23 | /// 24 | [DataMember(Name = "range_length")] 25 | public int? RangeLength { get; set; } 26 | 27 | /// 28 | /// (Optional) The playlist’s snapshot ID against which you want to make the changes. 29 | /// 30 | [DataMember(Name = "snapshot_id")] 31 | public string SnapshotId { get; set; } 32 | } 33 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Requests/PlaylistRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Requests; 2 | 3 | /// 4 | /// Playlist Request Object 5 | /// 6 | [DataContract] 7 | public class PlaylistRequest 8 | { 9 | /// 10 | /// The new name for the playlist, for example "My New Playlist Title" 11 | /// 12 | [DataMember(Name = "name")] 13 | public string Name { get; set; } 14 | 15 | /// 16 | ///(Optional) If true the playlist will be public, if false it will be private. 17 | /// 18 | [DataMember(Name = "public")] 19 | public bool? IsPublic { get; set; } 20 | 21 | /// 22 | /// (Optional) If true , the playlist will become collaborative and other users will be able to modify the playlist in their Spotify client. Note: You can only set collaborative to true on non-public playlists. 23 | /// 24 | [DataMember(Name = "collaborative")] 25 | public bool? IsCollaborative { get; set; } 26 | 27 | /// 28 | /// (Optional) Value for playlist description as displayed in Spotify Clients and in the Web API. 29 | /// 30 | [DataMember(Name = "description")] 31 | public string Description { get; set; } 32 | } 33 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Requests/PlaylistTracksRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Requests; 2 | 3 | /// 4 | /// Playlist Tracks Request Object 5 | /// 6 | [DataContract] 7 | public class PlaylistTracksRequest 8 | { 9 | /// 10 | /// Spotify URIs and Positions of Tracks 11 | /// 12 | [DataMember(Name = "tracks")] 13 | public List Tracks { get; set; } 14 | 15 | /// 16 | /// The playlist’s snapshot ID against which you want to make the changes 17 | /// 18 | [DataMember(Name = "snapshot_id")] 19 | public string SnapshotId { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Requests/PositionRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Requests; 2 | 3 | /// 4 | /// Position Request Object 5 | /// 6 | [DataContract] 7 | public class PositionRequest 8 | { 9 | /// 10 | /// Position 11 | /// 12 | [DataMember(Name = "position")] 13 | public int? Position { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Requests/PositionUriRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Requests; 2 | 3 | /// 4 | /// Position URI Request Object 5 | /// 6 | [DataContract] 7 | public class PositionUriRequest : UriRequest 8 | { 9 | /// 10 | /// Positions for each of the Uris in the playlist, positions are zero-indexed, that is the first item in the playlist has the value 0, the second item 1, and so on 11 | /// 12 | [DataMember(Name = "positions")] 13 | public List Positions { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Requests/PublicRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Requests; 2 | 3 | /// 4 | /// Public Request Object 5 | /// 6 | [DataContract] 7 | class PublicRequest 8 | { 9 | /// 10 | /// Is Public 11 | /// 12 | [DataMember(Name = "public")] 13 | public bool? IsPublic { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Requests/Scope.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Requests; 2 | 3 | /// 4 | /// Authorisation Scopes 5 | /// 6 | public class Scope 7 | { 8 | #region Playlists 9 | 10 | /// 11 | /// Read access to user's private playlists. 12 | /// Required For 13 | /// Check if Users Follow a Playlist, 14 | /// Get a List of Current User's Playlists, 15 | /// Get a List of a User's Playlists 16 | /// 17 | [Description("playlist-read-private")] 18 | public bool? PlaylistReadPrivate { get; set; } 19 | 20 | /// 21 | /// Write access to a user's private playlists. 22 | /// Required For 23 | /// Follow a Playlist, 24 | /// Unfollow a Playlist, 25 | /// Add Tracks to a Playlist 26 | /// Change a Playlist's Details, 27 | /// Create a Playlist, 28 | /// Remove Tracks from a Playlist 29 | /// Reorder a Playlist's Tracks, 30 | /// Replace a Playlist's Tracks, 31 | /// Upload a Custom Playlist Cover Image 32 | /// 33 | [Description("playlist-modify-private")] 34 | public bool? PlaylistModifyPrivate { get; set; } 35 | 36 | /// 37 | /// Write access to a user's public playlists. 38 | /// Required For 39 | /// Follow a Playlist, 40 | /// Unfollow a Playlist, 41 | /// Add Tracks to a Playlist 42 | /// Change a Playlist's Details, 43 | /// Create a Playlist, 44 | /// Remove Tracks from a Playlist 45 | /// Reorder a Playlist's Tracks, 46 | /// Replace a Playlist's Tracks, 47 | /// Upload a Custom Playlist Cover Image 48 | /// 49 | [Description("playlist-modify-public")] 50 | public bool? PlaylistModifyPublic { get; set; } 51 | 52 | /// 53 | /// Include collaborative playlists when requesting a user's playlists. 54 | /// Required For 55 | /// Get a List of Current User's Playlists, 56 | /// Get a List of a User's Playlists 57 | /// 58 | [Description("playlist-read-collaborative")] 59 | public bool? PlaylistReadCollaborative { get; set; } 60 | 61 | #endregion Playlists 62 | 63 | #region Spotify Connect 64 | 65 | /// 66 | /// Pause a User's Playback 67 | /// Required For 68 | /// Seek To Position In Currently Playing Track, 69 | /// Set Repeat Mode On User’s Playback, 70 | /// Set Volume For User's Playback 71 | /// Skip User’s Playback To Next Track, 72 | /// Skip User’s Playback To Previous Track, 73 | /// Start/Resume a User's Playback 74 | /// Toggle Shuffle For User’s Playback 75 | /// Transfer a User's Playback 76 | /// 77 | [Description("user-modify-playback-state")] 78 | public bool? ConnectModifyPlaybackState { get; set; } 79 | 80 | /// 81 | /// Read access to a user’s currently playing track 82 | /// Required For 83 | /// Get the User's Currently Playing Track 84 | /// 85 | [Description("user-read-currently-playing")] 86 | public bool? ConnectReadCurrentlyPlaying { get; set; } 87 | 88 | /// 89 | /// Read access to a user’s player state. 90 | /// Required For 91 | /// Get a User's Available Devices, 92 | /// Get Information About The User's Current Playback, 93 | /// Get the User's Currently Playing Track 94 | /// 95 | [Description("user-read-playback-state")] 96 | public bool? ConnectReadPlaybackState { get; set; } 97 | 98 | #endregion Spotify Connect 99 | 100 | #region Listening History 101 | 102 | /// 103 | /// Read access to a user's top artists and tracks. 104 | /// Required For 105 | /// Get a User's Top Artists and Tracks 106 | /// 107 | [Description("user-top-read")] 108 | public bool? ListeningTopRead { get; set; } 109 | 110 | /// 111 | /// Read access to a user’s playback position in a content 112 | /// Optional For 113 | /// Get an Episodes, 114 | /// Get Multiple Episodes, 115 | /// Get a Show, 116 | /// Get Multiple Shows, 117 | /// Get a Show's Episodes 118 | /// 119 | [Description("user-read-playback-position")] 120 | public bool? PlaybackPositionRead { get; set; } 121 | 122 | /// 123 | /// Read access to a user’s recently played tracks 124 | /// Required For 125 | /// Get Current User's Recently Played Tracks 126 | /// 127 | [Description("user-read-recently-played")] 128 | public bool? ListeningRecentlyPlayed { get; set; } 129 | 130 | #endregion Listening History 131 | 132 | #region Playback 133 | 134 | /// 135 | /// Remote control playback of Spotify. 136 | /// 137 | [Description("app-remote-control")] 138 | public bool? PlaybackAppRemoteControl { get; set; } 139 | 140 | /// 141 | /// Control playback of a Spotify track. The user must have a Spotify Premium account. 142 | /// 143 | [Description("streaming")] 144 | public bool? PlaybackStreaming { get; set; } 145 | 146 | #endregion Playback 147 | 148 | #region Users 149 | 150 | /// 151 | /// Read access to user’s email address. 152 | /// Required For 153 | /// Get Current User's Profile 154 | /// 155 | [Description("user-read-email")] 156 | public bool? UserReadEmail { get; set; } 157 | 158 | /// 159 | /// Read access to user’s subscription details (type of user account). 160 | /// Required For 161 | /// Search for an Item, 162 | /// Get Current User's Profile 163 | /// 164 | [Description("user-read-private")] 165 | public bool? UserReadPrivate { get; set; } 166 | 167 | /// 168 | /// Write access to user-provided images 169 | /// Required For 170 | /// Upload a Custom Playlist Cover Image 171 | /// 172 | [Description("ugc-image-upload")] 173 | public bool? UserGeneratedContentImageUpload { get; set; } 174 | 175 | #endregion Users 176 | 177 | #region Follow 178 | 179 | /// 180 | /// Read access to the list of artists and other users that the user follows. 181 | /// Required For 182 | /// Check if Current User Follows Artists or Users, 183 | /// Get User's Followed Artists 184 | /// 185 | [Description("user-follow-read")] 186 | public bool? FollowRead { get; set; } 187 | 188 | /// 189 | /// Write/delete access to the list of artists and other users that the user follows. 190 | /// Required For 191 | /// Follow Artists or Users, 192 | /// Unfollow Artists or Users 193 | /// 194 | [Description("user-follow-modify")] 195 | public bool? FollowModify { get; set; } 196 | 197 | #endregion Follow 198 | 199 | #region Library 200 | 201 | /// 202 | /// Write/delete access to a user's "Your Music" library. 203 | /// Required For 204 | /// Remove Albums for Current User, 205 | /// Remove User's Saved Tracks, 206 | /// Save Albums for Current User 207 | /// Save Tracks for User 208 | /// 209 | [Description("user-library-modify")] 210 | public bool? LibraryModify { get; set; } 211 | 212 | /// 213 | /// Read access to a user's "Your Music" library. 214 | /// Required For 215 | /// Check User's Saved Albums 216 | /// Check User's Saved Tracks, 217 | /// Get Current User's Saved Albums 218 | /// Get a User's Saved Tracks 219 | /// 220 | [Description("user-library-read")] 221 | public bool? LibraryRead { get; set; } 222 | 223 | #endregion Library 224 | 225 | #region MultiScopeHelpers 226 | /// 227 | /// Returns a new Scope object with all scopes set to false 228 | /// Usage: Scope.None 229 | /// 230 | public static Scope None = new Scope().AddNone(); 231 | 232 | /// 233 | /// Returns a new Scope object with all "read" scopes set to true 234 | /// Usage : Scope.ReadAllAccess 235 | /// 236 | public static Scope ReadAllAccess => new Scope().AddReadAllAccess(); 237 | 238 | /// 239 | /// Returns a new Scope object with all "modify" scopes set to true 240 | /// Usage : Scope.ModifyAllAccess 241 | /// 242 | public static Scope ModifyAllAccess => new Scope().AddModifyAllAccess(); 243 | 244 | /// 245 | /// Returns a new Scope object with all scopes within the confines of Playlists set to true 246 | /// Usage : Scope.PlaylistAll 247 | /// 248 | public static Scope PlaylistAll => new Scope().AddPlaylistAll(); 249 | 250 | /// 251 | /// Returns a new Scope object with all scopes within the confines of Spotify Connect set to true 252 | /// Usage : Scope.SpotifyConnectAll 253 | /// 254 | public static Scope SpotifyConnectAll => new Scope().AddSpotifyConnectAll(); 255 | 256 | /// 257 | /// Returns a new Scope object with all scopes within the confines of Listening History set to true 258 | /// Usage : Scope.ListeningHistoryAll 259 | /// 260 | public static Scope ListeningHistoryAll => new Scope().AddListeningHistoryAll(); 261 | 262 | /// 263 | /// Returns a new Scope object with all scopes within the confines of Playback set to true 264 | /// Usage : Scope.PlaybackAll 265 | /// 266 | public static Scope PlaybackAll => new Scope().AddPlaybackAll(); 267 | 268 | /// 269 | /// Returns a new Scope object with all scopes within the confines of Users set to true 270 | /// Usage : Scope.UsersAll 271 | /// 272 | public static Scope UsersAll => new Scope().AddUsersAll(); 273 | 274 | /// 275 | /// Returns a new Scope object with all scopes within the confines of Users set to true 276 | /// Usage : Scope.FollowAll 277 | /// 278 | public static Scope FollowAll => new Scope().AddFollowAll(); 279 | 280 | /// 281 | /// Returns a new Scope object with all scopes within the confines of Library set to true 282 | /// Usage : Scope.LibraryAll 283 | /// 284 | public static Scope LibraryAll => new Scope().AddLibraryAll(); 285 | 286 | /// 287 | /// Returns a new Scope object with all scopes set to true 288 | /// Usage : Scope.AllPermissions 289 | /// 290 | public static Scope AllPermissions => 291 | new Scope() 292 | .AddReadAllAccess() 293 | .AddModifyAllAccess() 294 | .AddPlaylistAll() 295 | .AddSpotifyConnectAll() 296 | .AddListeningHistoryAll() 297 | .AddPlaybackAll() 298 | .AddUsersAll() 299 | .AddFollowAll() 300 | .AddLibraryAll(); 301 | 302 | #endregion MultiScopeHelpers 303 | } 304 | 305 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Requests/ScopeExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Requests; 2 | 3 | /// 4 | /// Extension Methods for Scope Class to allow fluent additions of scopes for the API 5 | /// 6 | public static class ScopeExtensions 7 | { 8 | /// 9 | /// Extension method to add no scopes 10 | /// 11 | /// Scope 12 | /// Scope 13 | public static Scope AddNone(this Scope scope) 14 | { 15 | scope.PlaylistReadCollaborative = false; 16 | scope.PlaylistReadPrivate = false; 17 | scope.ConnectReadCurrentlyPlaying = false; 18 | scope.ConnectReadPlaybackState = false; 19 | scope.ListeningTopRead = false; 20 | scope.PlaybackPositionRead = false; 21 | scope.ListeningRecentlyPlayed = false; 22 | scope.UserReadEmail = false; 23 | scope.UserReadPrivate = false; 24 | scope.FollowRead = false; 25 | scope.LibraryRead = false; 26 | 27 | scope.PlaylistModifyPrivate = false; 28 | scope.PlaylistModifyPublic = false; 29 | scope.ConnectModifyPlaybackState = false; 30 | scope.FollowModify = false; 31 | scope.LibraryModify = false; 32 | 33 | scope.PlaylistReadPrivate = false; 34 | scope.PlaylistModifyPrivate = false; 35 | scope.PlaylistModifyPublic = false; 36 | scope.PlaylistReadCollaborative = false; 37 | 38 | scope.ConnectModifyPlaybackState = false; 39 | scope.ConnectReadCurrentlyPlaying = false; 40 | scope.ConnectReadPlaybackState = false; 41 | 42 | scope.ListeningTopRead = false; 43 | scope.PlaybackPositionRead = false; 44 | scope.ListeningRecentlyPlayed = false; 45 | 46 | scope.PlaybackAppRemoteControl = false; 47 | scope.PlaybackStreaming = false; 48 | 49 | scope.UserReadEmail = false; 50 | scope.UserReadPrivate = false; 51 | scope.UserGeneratedContentImageUpload = false; 52 | 53 | scope.FollowRead = false; 54 | scope.FollowModify = false; 55 | 56 | scope.LibraryModify = false; 57 | scope.LibraryRead = false; 58 | return scope; 59 | } 60 | 61 | /// 62 | /// Extension method to add all scopes with "read" in their scope string 63 | /// 64 | /// Scope 65 | /// Scope 66 | public static Scope AddReadAllAccess(this Scope scope) 67 | { 68 | scope.PlaylistReadCollaborative = true; 69 | scope.PlaylistReadPrivate = true; 70 | scope.ConnectReadCurrentlyPlaying = true; 71 | scope.ConnectReadPlaybackState = true; 72 | scope.ListeningTopRead = true; 73 | scope.PlaybackPositionRead = true; 74 | scope.ListeningRecentlyPlayed = true; 75 | scope.UserReadEmail = true; 76 | scope.UserReadPrivate = true; 77 | scope.FollowRead = true; 78 | scope.LibraryRead = true; 79 | return scope; 80 | } 81 | 82 | /// 83 | /// Extension method to add all scopes with "modify" in their scope string 84 | /// 85 | /// Scope 86 | /// Scope 87 | public static Scope AddModifyAllAccess(this Scope scope) 88 | { 89 | scope.PlaylistModifyPrivate = true; 90 | scope.PlaylistModifyPublic = true; 91 | scope.ConnectModifyPlaybackState = true; 92 | scope.FollowModify = true; 93 | scope.LibraryModify = true; 94 | return scope; 95 | } 96 | 97 | /// 98 | /// Adds all scopes to a scope within the Playlist section of the defined Scopes 99 | /// 100 | /// Scope 101 | /// Scope 102 | public static Scope AddPlaylistAll(this Scope scope) 103 | { 104 | scope.PlaylistReadPrivate = true; 105 | scope.PlaylistModifyPrivate = true; 106 | scope.PlaylistModifyPublic = true; 107 | scope.PlaylistReadCollaborative = true; 108 | return scope; 109 | } 110 | 111 | /// 112 | /// Adds all scopes to a scope within the Spotify Connect section of the defined Scopes 113 | /// 114 | /// Scope 115 | /// Scope 116 | public static Scope AddSpotifyConnectAll(this Scope scope) 117 | { 118 | scope.ConnectModifyPlaybackState = true; 119 | scope.ConnectReadCurrentlyPlaying = true; 120 | scope.ConnectReadPlaybackState = true; 121 | return scope; 122 | } 123 | 124 | /// 125 | /// Adds all scopes to a scope within the Listening History section of the defined Scopes 126 | /// 127 | /// Scope 128 | /// Scope 129 | public static Scope AddListeningHistoryAll(this Scope scope) 130 | { 131 | scope.ListeningTopRead = true; 132 | scope.PlaybackPositionRead = true; 133 | scope.ListeningRecentlyPlayed = true; 134 | 135 | return scope; 136 | } 137 | 138 | /// 139 | /// Adds all scopes to a scope within the Playback section of the defined Scopes 140 | /// 141 | /// Scope 142 | /// Scope 143 | public static Scope AddPlaybackAll(this Scope scope) 144 | { 145 | scope.PlaybackAppRemoteControl = true; 146 | scope.PlaybackStreaming = true; 147 | return scope; 148 | } 149 | 150 | /// 151 | /// Adds all scopes to a scope within the Users section of the defined Scopes 152 | /// 153 | /// Scope 154 | /// Scope 155 | public static Scope AddUsersAll(this Scope scope) 156 | { 157 | scope.UserReadEmail = true; 158 | scope.UserReadPrivate = true; 159 | scope.UserGeneratedContentImageUpload = true; 160 | return scope; 161 | } 162 | 163 | /// 164 | /// Adds all scopes to a scope within the Follow section of the defined Scopes 165 | /// 166 | /// Scope 167 | /// Scope 168 | public static Scope AddFollowAll(this Scope scope) 169 | { 170 | scope.FollowRead = true; 171 | scope.FollowModify = true; 172 | return scope; 173 | } 174 | 175 | /// 176 | /// Adds all scopes to a scope within the Library section of the defined Scopes 177 | /// 178 | /// Scope 179 | /// Scope 180 | public static Scope AddLibraryAll(this Scope scope) 181 | { 182 | scope.LibraryModify = true; 183 | scope.LibraryRead = true; 184 | return scope; 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Requests/SearchType.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Requests; 2 | 3 | /// 4 | /// Search Type 5 | /// 6 | public class SearchType 7 | { 8 | /// 9 | /// Album 10 | /// 11 | [Description("album")] 12 | public bool? Album { get; set; } 13 | 14 | /// 15 | /// Artist 16 | /// 17 | [Description("artist")] 18 | public bool? Artist { get; set; } 19 | 20 | /// 21 | /// Playlist 22 | /// 23 | [Description("playlist")] 24 | public bool? Playlist { get; set; } 25 | 26 | /// 27 | /// Track 28 | /// 29 | [Description("track")] 30 | public bool? Track { get; set; } 31 | 32 | /// 33 | /// Show 34 | /// 35 | [Description("show")] 36 | public bool? Show { get; set; } 37 | 38 | /// 39 | /// Episode 40 | /// 41 | [Description("episode")] 42 | public bool? Episode { get; set; } 43 | 44 | /// 45 | /// Audiobook 46 | /// 47 | [Description("audiobook")] 48 | public bool? Audiobook { get; set; } 49 | } 50 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Requests/TuneableTrack.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Requests; 2 | 3 | /// 4 | /// Tuneable Track Object 5 | /// 6 | public class TuneableTrack 7 | { 8 | /// 9 | /// A confidence measure from 0.0 to 1.0 of whether the track is acoustic. 10 | /// 11 | [Description("acousticness")] 12 | public float? Acousticness { get; set; } 13 | 14 | /// 15 | /// Danceability describes how suitable a track is for dancing based on a combination of musical elements including tempo, rhythm stability, beat strength, and overall regularity. 16 | /// 17 | [Description("danceability")] 18 | public float? Danceability { get; set; } 19 | 20 | /// 21 | /// The duration of the track in milliseconds. 22 | /// 23 | [Description("duration_ms")] 24 | public long? Duration { get; set; } 25 | 26 | /// 27 | /// Energy is a measure from 0.0 to 1.0 and represents a perceptual measure of intensity and activity 28 | /// 29 | [Description("energy")] 30 | public float? Energy { get; set; } 31 | 32 | /// 33 | /// Predicts whether a track contains no vocals 34 | /// 35 | [Description("instrumentalness")] 36 | public float? Instrumentalness { get; set; } 37 | 38 | /// 39 | /// The key the track is in. Integers map to pitches using standard Pitch Class notation. 40 | /// 41 | [Description("key")] 42 | public int? Key { get; set; } 43 | 44 | /// 45 | /// Detects the presence of an audience in the recording. 46 | /// 47 | [Description("liveness")] 48 | public float? Liveness { get; set; } 49 | 50 | /// 51 | /// The overall loudness of a track in decibels (dB) 52 | /// 53 | [Description("loudness")] 54 | public float? Loudness { get; set; } 55 | 56 | /// 57 | /// Mode indicates the modality(major or minor) of a track, the type of scale from which its melodic content is derived 58 | /// 59 | [Description("mode")] 60 | public int? Mode { get; set; } 61 | 62 | /// 63 | /// The popularity of the track. The value will be between 0 and 100, with 100 being the most popular. 64 | /// 65 | [Description("popularity")] 66 | public int? Popularity { get; set; } 67 | 68 | /// 69 | /// Speechiness detects the presence of spoken words in a track. 70 | /// 71 | [Description("speechiness")] 72 | public float? Speechiness { get; set; } 73 | 74 | /// 75 | /// The overall estimated tempo of a track in beats per minute (BPM). 76 | /// 77 | [Description("tempo")] 78 | public float? Tempo { get; set; } 79 | 80 | /// 81 | /// An estimated overall time signature of a track. 82 | /// 83 | [Description("time_signature")] 84 | public int? TimeSignature { get; set; } 85 | 86 | /// 87 | /// A measure from 0.0 to 1.0 describing the musical positiveness conveyed by a track. 88 | /// 89 | [Description("valence")] 90 | public float? Valence { get; set; } 91 | } 92 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Requests/UriListRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Requests; 2 | 3 | /// 4 | /// URI List Request Object 5 | /// 6 | [DataContract] 7 | public class UriListRequest 8 | { 9 | /// 10 | /// URIs 11 | /// 12 | [DataMember(Name = "uris")] 13 | public List Uris { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Requests/UriRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Requests; 2 | 3 | /// 4 | /// URI Request Object 5 | /// 6 | [DataContract] 7 | public class UriRequest 8 | { 9 | /// 10 | /// Spotify URI 11 | /// 12 | [DataMember(Name = "uri")] 13 | public string Uri { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Actions.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Actions Object 5 | /// 6 | [DataContract] 7 | public class Actions 8 | { 9 | /// 10 | /// Allows to update the user interface based on which playback actions are available within the current context 11 | /// 12 | [DataMember(Name = "disallows")] 13 | public Disallows Disallows { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Album.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Album Object 5 | /// 6 | [DataContract] 7 | public class Album : SimplifiedAlbum 8 | { 9 | /// 10 | /// The copyright statements of the album. 11 | /// 12 | [DataMember(Name = "copyrights")] 13 | public List Copyrights { get; set; } 14 | 15 | /// 16 | /// Known external IDs for the album. 17 | /// 18 | [DataMember(Name = "external_ids")] 19 | public ExternalId ExternalId { get; set; } 20 | 21 | /// 22 | /// A list of the genres used to classify the album. For example: "Prog Rock" , "Post-Grunge" 23 | /// 24 | [DataMember(Name = "genres")] 25 | public List Genres { get; set; } 26 | 27 | /// 28 | /// The label for the album. 29 | /// 30 | [DataMember(Name = "label")] 31 | public string Label { get; set; } 32 | 33 | /// 34 | /// The popularity of the album. The value will be between 0 and 100, with 100 being the most popular 35 | /// 36 | [DataMember(Name = "popularity")] 37 | public int Popularity { get; set; } 38 | 39 | /// 40 | /// The date the album was first released, for example 1981. Depending on the precision, it might be shown as 1981-12 or 1981-12-15 41 | /// 42 | [DataMember(Name = "release_date")] 43 | public string ReleaseDate { get; set; } 44 | 45 | /// 46 | /// The precision with which ReleaseDate value is known: year , month , or day. 47 | /// 48 | [DataMember(Name = "release_date_precision")] 49 | public string ReleaseDatePrecision { get; set; } 50 | 51 | /// 52 | /// The tracks of the album. 53 | /// 54 | [DataMember(Name = "tracks")] 55 | public Paging Tracks { get; set; } 56 | } 57 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Artist.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Artist Object 5 | /// 6 | [DataContract] 7 | public class Artist : SimplifiedArtist 8 | { 9 | /// 10 | /// Information about the followers of the artist. 11 | /// 12 | [DataMember(Name = "followers")] 13 | public Followers Followers { get; set; } 14 | 15 | /// 16 | /// A list of the genres the artist is associated with. For example: "Prog Rock" , "Post-Grunge". 17 | /// 18 | [DataMember(Name = "genres")] 19 | public List Genres { get; set; } 20 | 21 | /// 22 | /// Images of the artist in various sizes, widest first. 23 | /// 24 | [DataMember(Name = "images")] 25 | public List Images { get; set; } 26 | 27 | /// 28 | /// The popularity of the artist. The value will be between 0 and 100, with 100 being the most popular. 29 | /// 30 | [DataMember(Name = "popularity")] 31 | public int Popularity { get; set; } 32 | } 33 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/AudioAnalysis.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Audio Analysis Object 5 | /// 6 | [DataContract] 7 | public class AudioAnalysis : BaseResponse 8 | { 9 | /// 10 | /// The time intervals of the bars throughout the track 11 | /// 12 | [DataMember(Name = "bars")] 13 | public List Bars { get; set; } 14 | 15 | /// 16 | /// The time intervals of beats throughout the track. 17 | /// 18 | [DataMember(Name = "beats")] 19 | public List Beats { get; set; } 20 | 21 | /// 22 | /// Sections are defined by large variations in rhythm or timbre, e.g.chorus, verse, bridge, guitar solo, etc. 23 | /// 24 | [DataMember(Name = "sections")] 25 | public List
Sections { get; set; } 26 | 27 | /// 28 | /// Audio segments attempts to subdivide a song into many segments, with each segment containing a roughly consitent sound throughout its duration. 29 | /// 30 | [DataMember(Name = "segments")] 31 | public List Segments { get; set; } 32 | 33 | /// 34 | /// A tatum represents the lowest regular pulse train that a listener intuitively infers from the timing of perceived musical events 35 | /// 36 | [DataMember(Name = "tatums")] 37 | public List Tatums { get; set; } 38 | } 39 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/AudioFeatures.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Audio Features Object 5 | /// 6 | public class AudioFeatures : Content 7 | { 8 | /// 9 | /// A confidence measure from 0.0 to 1.0 of whether the track is acoustic. 10 | /// 11 | [DataMember(Name = "acousticness")] 12 | public float? Acousticness { get; set; } 13 | 14 | /// 15 | /// An HTTP URL to access the full audio analysis of this track. 16 | /// 17 | [DataMember(Name = "analysis_url")] 18 | public string AnalysisUrl { get; set; } 19 | 20 | /// 21 | /// Danceability describes how suitable a track is for dancing based on a combination of musical elements including tempo, rhythm stability, beat strength, and overall regularity. A value of 0.0 is least danceable and 1.0 is most danceable. 22 | /// 23 | [DataMember(Name = "danceability")] 24 | public float? Danceability { get; set; } 25 | 26 | /// 27 | /// The duration of the track in milliseconds. 28 | /// 29 | [DataMember(Name = "duration_ms")] 30 | public long? Duration { get; set; } 31 | 32 | /// 33 | /// Energy is a measure from 0.0 to 1.0 and represents a perceptual measure of intensity and activity 34 | /// 35 | [DataMember(Name = "energy")] 36 | public float? Energy { get; set; } 37 | 38 | /// 39 | /// Predicts whether a track contains no vocals. “Ooh” and “aah” sounds are treated as instrumental in this context. Rap or spoken word tracks are clearly “vocal”. The closer the instrumentalness value is to 1.0, the greater likelihood the track contains no vocal content. Values above 0.5 are intended to represent instrumental tracks, but confidence is higher as the value approaches 1.0. 40 | /// 41 | [DataMember(Name = "instrumentalness")] 42 | public float? Instrumentalness { get; set; } 43 | 44 | /// 45 | /// The key the track is in. Integers map to pitches using standard Pitch Class notation. 46 | /// 47 | [DataMember(Name = "key")] 48 | public int? Key { get; set; } 49 | 50 | /// 51 | /// Detects the presence of an audience in the recording. Higher liveness values represent an increased probability that the track was performed live. A value above 0.8 provides strong likelihood that the track is live. 52 | /// 53 | [DataMember(Name = "liveness")] 54 | public float? Liveness { get; set; } 55 | 56 | /// 57 | /// The overall loudness of a track in decibels (dB). Loudness values are averaged across the entire track and are useful for comparing relative loudness of tracks. Loudness is the quality of a sound that is the primary psychological correlate of physical strength (amplitude). Values typical range between -60 and 0 db. 58 | /// 59 | [DataMember(Name = "loudness")] 60 | public float? Loudness { get; set; } 61 | 62 | /// 63 | /// Mode indicates the modality(major or minor) of a track, the type of scale from which its melodic content is derived. Major is represented by 1 and minor is 0. 64 | /// 65 | [DataMember(Name = "mode")] 66 | public int? Mode { get; set; } 67 | 68 | /// 69 | /// Speechiness detects the presence of spoken words in a track. The more exclusively speech-like the recording (e.g. talk show, audio book, poetry), the closer to 1.0 the attribute value. Values above 0.66 describe tracks that are probably made entirely of spoken words. Values between 0.33 and 0.66 describe tracks that may contain both music and speech, either in sections or layered, including such cases as rap music. Values below 0.33 most likely represent music and other non-speech-like tracks. 70 | /// 71 | [DataMember(Name = "speechiness")] 72 | public float? Speechiness { get; set; } 73 | 74 | /// 75 | /// The overall estimated tempo of a track in beats per minute (BPM). In musical terminology, tempo is the speed or pace of a given piece and derives directly from the average beat duration. 76 | /// 77 | [DataMember(Name = "tempo")] 78 | public float? Tempo { get; set; } 79 | 80 | /// 81 | /// An estimated overall time signature of a track. The time signature (meter) is a notational convention to specify how many beats are in each bar (or measure). 82 | /// 83 | [DataMember(Name = "time_signature")] 84 | public int? TimeSignature { get; set; } 85 | 86 | /// 87 | /// A link to the Web API endpoint providing full details of the track. 88 | /// 89 | [DataMember(Name = "track_href")] 90 | public string TrackHref { get; set; } 91 | 92 | /// 93 | /// A measure from 0.0 to 1.0 describing the musical positiveness conveyed by a track. Tracks with high valence sound more positive (e.g. happy, cheerful, euphoric), while tracks with low valence sound more negative (e.g. sad, depressed, angry). 94 | /// 95 | [DataMember(Name = "valence")] 96 | public float? Valence { get; set; } 97 | } 98 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Audiobook.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Audiobook Object 5 | /// 6 | [DataContract] 7 | public class Audiobook : SimplifiedAudiobook 8 | { 9 | /// 10 | /// The chapters of the audiobook. 11 | /// 12 | [DataMember(Name = "chapters")] 13 | public Paging Chapters { get; set; } 14 | } -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Author.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Author Object 5 | /// 6 | [DataContract] 7 | public class Author 8 | { 9 | /// 10 | /// The name of the author 11 | /// 12 | [DataMember(Name = "name")] 13 | public string Label { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/AvailableGenreSeeds.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Available Genre Seeds Object 5 | /// 6 | public class AvailableGenreSeeds : BaseResponse 7 | { 8 | /// 9 | /// Genres 10 | /// 11 | [DataMember(Name = "genres")] 12 | public List Genres { get; set; } 13 | } 14 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/AvailableMarkets.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Available Markets Object 5 | /// 6 | public class AvailableMarkets : BaseResponse 7 | { 8 | /// 9 | /// Get the list of markets where Spotify is available 10 | /// 11 | [DataMember(Name = "markets")] 12 | public List Markets { get; set; } 13 | } 14 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/BaseResponse.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Base Response Object 5 | /// 6 | [DataContract] 7 | public abstract class BaseResponse 8 | { 9 | /// 10 | /// Error Object 11 | /// 12 | [DataMember(Name = "error")] 13 | public ErrorResponse Error { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Bools.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// List of true or false values 5 | /// 6 | [DataContract] 7 | public class Bools : List 8 | { 9 | /// 10 | /// Constructor 11 | /// 12 | public Bools() { } 13 | 14 | /// 15 | /// Constructor 16 | /// 17 | /// Error Response 18 | internal Bools(ErrorResponse errorResponse) => 19 | Error = errorResponse; 20 | 21 | /// 22 | /// Error Object 23 | /// 24 | [DataMember(Name = "error")] 25 | public ErrorResponse Error { get; set; } 26 | } 27 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Category.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Category Object 5 | /// 6 | [DataContract] 7 | public class Category : Content 8 | { 9 | /// 10 | /// The category icon, in various sizes. 11 | /// 12 | [DataMember(Name = "icons")] 13 | public List Images { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Chapter.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Chapter Object 5 | /// 6 | public class Chapter : SimplifiedChapter 7 | { 8 | /// 9 | /// Audiobook Object 10 | /// 11 | [DataMember(Name = "audiobook")] 12 | public SimplifiedAudiobook Audiobook { get; set; } 13 | } 14 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Content.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Content 5 | /// 6 | [DataContract] 7 | public abstract class Content : Context 8 | { 9 | /// 10 | /// The base-62 identifier that you can find at the end of the Spotify URI for the object 11 | /// 12 | [DataMember(Name = "id")] 13 | public string Id { get; set; } 14 | 15 | /// 16 | /// The name of the content 17 | /// 18 | [DataMember(Name = "name")] 19 | public string Name { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/ContentResponse.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Content Response 5 | /// 6 | [DataContract] 7 | public class ContentResponse : BaseResponse 8 | { 9 | /// 10 | /// Message 11 | /// 12 | [DataMember(Name = "message")] 13 | public string Message { get; set; } 14 | 15 | /// 16 | /// Paging Object of Albums 17 | /// 18 | [DataMember(Name = "albums")] 19 | public Paging Albums { get; set; } 20 | 21 | /// 22 | /// Paging Object of Category 23 | /// 24 | [DataMember(Name = "categories")] 25 | public Paging Categories { get; set; } 26 | 27 | /// 28 | /// Paging Object of Artists 29 | /// 30 | [DataMember(Name = "artists")] 31 | public Paging Artists { get; set; } 32 | 33 | /// 34 | /// Paging Object of Simplified Playlists 35 | /// 36 | [DataMember(Name = "playlists")] 37 | public Paging Playlists { get; set; } 38 | 39 | /// 40 | /// Paging Object of Tracks 41 | /// 42 | [DataMember(Name = "tracks")] 43 | public Paging Tracks { get; set; } 44 | 45 | /// 46 | /// Paging Object of Simplified Show Objects 47 | /// 48 | [DataMember(Name = "shows")] 49 | public Paging Shows { get; set; } 50 | 51 | /// 52 | /// Paging Object of Simplified Episode Objects 53 | /// 54 | [DataMember(Name = "episodes")] 55 | public Paging Episodes { get; set; } 56 | 57 | /// 58 | /// Paging Object of Simplified Audiobook Objects 59 | /// 60 | [DataMember(Name = "audiobooks")] 61 | public Paging Audiobooks { get; set; } 62 | } 63 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Context.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Context Object 5 | /// 6 | [DataContract] 7 | public class Context : BaseResponse 8 | { 9 | /// 10 | /// The object type of the object 11 | /// 12 | [DataMember(Name = "type")] 13 | public string Type { get; set; } 14 | 15 | /// 16 | /// A link to the Web API endpoint providing full details of the object 17 | /// 18 | [DataMember(Name = "href")] 19 | public string Href { get; set; } 20 | 21 | /// 22 | /// Known external URLs for this object. 23 | /// 24 | [DataMember(Name = "external_urls")] 25 | public ExternalUrl ExternalUrls { get; set; } 26 | 27 | /// 28 | /// The Spotify URI for the object 29 | /// 30 | [DataMember(Name = "uri")] 31 | public string Uri { get; set; } 32 | } 33 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Copyright.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Copyright Object 5 | /// 6 | [DataContract] 7 | public class Copyright 8 | { 9 | /// 10 | /// The copyright text for this album. 11 | /// 12 | [DataMember(Name = "text")] 13 | public string Text { get; set; } 14 | 15 | /// 16 | /// The type of copyright: C = the copyright, P = the sound recording (performance) copyright. 17 | /// 18 | [DataMember(Name = "type")] 19 | public string Type { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/CurrentlyPlaying.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Currently Playing Object 5 | /// 6 | [DataContract] 7 | public class CurrentlyPlaying : SimplifiedCurrentlyPlaying 8 | { 9 | /// 10 | /// The device that is currently active 11 | /// 12 | [DataMember(Name = "device")] 13 | public Device Device { get; set; } 14 | 15 | /// 16 | /// off, track, context 17 | /// 18 | [DataMember(Name = "repeat_state")] 19 | public string RepeatState { get; set; } 20 | 21 | /// 22 | /// If shuffle is on or off 23 | /// 24 | [DataMember(Name = "shuffle_state")] 25 | public bool ShuffleState { get; set; } 26 | } 27 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/CursorPaging.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Cursor Paging Object 5 | /// 6 | /// Object Type 7 | [DataContract] 8 | public class CursorPaging : Cursor 9 | { 10 | /// 11 | /// Error Object 12 | /// 13 | [DataMember(Name = "error")] 14 | public ErrorResponse Error { get; set; } 15 | 16 | /// 17 | /// A link to the Web API endpoint returning the full result of the request. 18 | /// 19 | [DataMember(Name = "href")] 20 | public string Href { get; set; } 21 | 22 | /// 23 | /// The requested data. 24 | /// 25 | [DataMember(Name = "items")] 26 | public List Items { get; set; } 27 | 28 | /// 29 | /// The cursors used to find the next set of items. 30 | /// 31 | [DataMember(Name = "cursors")] 32 | public Cursor Cursors { get; set; } 33 | 34 | /// 35 | /// The total number of items available to return. 36 | /// 37 | [DataMember(Name = "total")] 38 | public int Total { get; set; } 39 | 40 | /// 41 | /// IEnumerable of Type 42 | /// 43 | public IEnumerable ReadOnlyItems => Items; 44 | 45 | /// 46 | /// Constructor 47 | /// 48 | public CursorPaging() => 49 | Items = new List(); 50 | } 51 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Device.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Device Object 5 | /// 6 | [DataContract] 7 | public class Device 8 | { 9 | /// 10 | /// The device ID. This may be null. 11 | /// 12 | [DataMember(Name = "id")] 13 | public string Id { get; set; } 14 | 15 | /// 16 | /// If this device is the currently active device. 17 | /// 18 | [DataMember(Name = "is_active")] 19 | public bool IsActive { get; set; } 20 | 21 | /// 22 | /// If this device is currently in a private session. 23 | /// 24 | [DataMember(Name = "is_private_session")] 25 | public bool IsPrivateSession { get; set; } 26 | 27 | /// 28 | /// Whether controlling this device is restricted. If true then no commands will be accepted by this device. 29 | /// 30 | [DataMember(Name = "is_restricted")] 31 | public bool IsRestricted { get; set; } 32 | 33 | /// 34 | /// The name of the device. 35 | /// 36 | [DataMember(Name = "name")] 37 | public string Name { get; set; } 38 | 39 | /// 40 | /// Device type, such as “computer”, “smartphone” or “speaker”. 41 | /// 42 | [DataMember(Name = "type")] 43 | public string Type { get; set; } 44 | 45 | /// 46 | /// The current volume in percent. This may be null. 47 | /// 48 | [DataMember(Name = "volume_percent")] 49 | public int? Volume { get; set; } 50 | } 51 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Devices.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Devices Object 5 | /// 6 | [DataContract] 7 | public class Devices : BaseResponse 8 | { 9 | /// 10 | /// A list of 0..n Device objects. 11 | /// 12 | [DataMember(Name = "devices")] 13 | public List Items { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Disallows.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Disallows Object 5 | /// 6 | [DataContract] 7 | public class Disallows 8 | { 9 | /// 10 | /// Interrupting playback not allowed? 11 | /// 12 | [DataMember(Name = "interrupting_playback")] 13 | public bool IsInterruptingPlaybackNotAllowed { get; set; } 14 | 15 | /// 16 | /// Pausing not allowed? 17 | /// 18 | [DataMember(Name = "pausing")] 19 | public bool IsPausingNotAllowed { get; set; } 20 | 21 | /// 22 | /// Resuming not allowed? 23 | /// 24 | [DataMember(Name = "resuming")] 25 | public bool IsResumingNotAllowed { get; set; } 26 | 27 | /// 28 | /// Seeking not allowed? Will be set to true while playing an ad track 29 | /// 30 | [DataMember(Name = "seeking")] 31 | public bool IsSeekingNotAllowed { get; set; } 32 | 33 | /// 34 | /// Skipping next not allowed? Will be set to true while playing an ad track 35 | /// 36 | [DataMember(Name = "skipping_next")] 37 | public bool IsSkippingNextNotAllowed { get; set; } 38 | 39 | /// 40 | /// Skipping previous not allowed? Will be set to true while playing an ad track 41 | /// 42 | [DataMember(Name = "skipping_prev")] 43 | public bool IsSkippingPrevNotAllowed { get; set; } 44 | 45 | /// 46 | /// Toggling repeat context not allowed? 47 | /// 48 | [DataMember(Name = "toggling_repeat_context")] 49 | public bool IsTogglingRepeatContextNotAllowed { get; set; } 50 | 51 | /// 52 | /// Toggling shuffle not allowed? 53 | /// 54 | [DataMember(Name = "toggling_shuffle")] 55 | public bool IsTogglingShuffleNotAllowed { get; set; } 56 | 57 | /// 58 | /// Toggling repeat track not allowed? 59 | /// 60 | [DataMember(Name = "toggling_repeat_track")] 61 | public bool IsTogglingRepeatTrackNotAllowed { get; set; } 62 | 63 | /// 64 | /// Transferring playback not allowed? 65 | /// 66 | [DataMember(Name = "transferring_playback")] 67 | public bool IsTransferringPlaybackNotAllowed { get; set; } 68 | } 69 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Episode.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Episode Object 5 | /// 6 | public class Episode : SimplifiedEpisode 7 | { 8 | /// 9 | /// The show on which the episode belongs. 10 | /// 11 | [DataMember(Name = "show")] 12 | public SimplifiedShow Show { get; set; } 13 | } 14 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/ErrorResponse.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Error Object 5 | /// 6 | [DataContract] 7 | public class ErrorResponse 8 | { 9 | /// 10 | /// The HTTP status code 11 | /// 12 | [DataMember(Name = "status")] 13 | public int StatusCode { get; set; } 14 | 15 | /// 16 | /// A short description of the cause of the error. 17 | /// 18 | [DataMember(Name = "message")] 19 | public string Message { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/ExternalId.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// External Id Object 5 | /// 6 | [DataContract] 7 | public class ExternalId : Dictionary 8 | { 9 | /// 10 | /// International Standard Recording Code 11 | /// 12 | public string Isrc => this.GetValueOrDefault("isrc"); 13 | 14 | /// 15 | /// International Article Number 16 | /// 17 | public string Ean => this.GetValueOrDefault("ean"); 18 | 19 | /// 20 | /// Universal Product Code 21 | /// 22 | public string Upc => this.GetValueOrDefault("upc"); 23 | } 24 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/ExternalUrl.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// External Url Object 5 | /// 6 | [DataContract] 7 | public class ExternalUrl : Dictionary 8 | { 9 | /// 10 | /// An external, public URL to the object. 11 | /// 12 | public string Spotify => this.GetValueOrDefault("spotify"); 13 | } -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Followers.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Followers Object 5 | /// 6 | [DataContract] 7 | public class Followers 8 | { 9 | /// 10 | /// A link to the Web API endpoint providing full details of the followers; null if not available 11 | /// 12 | [DataMember(Name = "href")] 13 | public string Href { get; set; } 14 | 15 | /// 16 | /// The total number of followers. 17 | /// 18 | [DataMember(Name = "total")] 19 | public int Total { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Image.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Image Object 5 | /// 6 | [DataContract] 7 | public class Image 8 | { 9 | /// 10 | /// The image height in pixels. If unknown: null or not returned. 11 | /// 12 | [DataMember(Name = "height")] 13 | public int? Height { get; set; } 14 | 15 | /// 16 | /// The source URL of the image. 17 | /// 18 | [DataMember(Name = "url")] 19 | public string Url { get; set; } 20 | 21 | /// 22 | /// The image width in pixels. If unknown: null or not returned. 23 | /// 24 | [DataMember(Name = "width")] 25 | public int? Width { get; set; } 26 | } 27 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Internal/ContentCursorResponse.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses.Internal; 2 | 3 | /// 4 | /// Content Cursor Response 5 | /// 6 | internal class ContentCursorResponse 7 | { 8 | /// 9 | /// Cursor Paging Object of Artist 10 | /// 11 | [DataMember(Name = "artist")] 12 | public CursorPaging Artists { get; set; } 13 | } 14 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Internal/InternalResponse.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses.Internal; 2 | 3 | /// 4 | /// Internal Response 5 | /// 6 | internal class InternalResponse : BaseResponse { } 7 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/LinkedTrack.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Linked Track Object 5 | /// 6 | [DataContract] 7 | public class LinkedTrack : Content { } 8 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/LookupResponse.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Lookup Response 5 | /// 6 | [DataContract] 7 | public class LookupResponse : BaseResponse 8 | { 9 | /// 10 | /// List of Album Object 11 | /// 12 | [DataMember(Name = "albums")] 13 | public List Albums { get; set; } 14 | 15 | /// 16 | /// List of Artist Object 17 | /// 18 | [DataMember(Name = "artists")] 19 | public List Artists { get; set; } 20 | 21 | /// 22 | /// List of Track Object 23 | /// 24 | [DataMember(Name = "tracks")] 25 | public List Tracks { get; set; } 26 | 27 | /// 28 | /// List of Audio Feature Object 29 | /// 30 | [DataMember(Name = "audio_features")] 31 | public List AudioFeatures { get; set; } 32 | 33 | /// 34 | /// List of Episode Object 35 | /// 36 | [DataMember(Name = "episodes")] 37 | public List Episodes { get; set; } 38 | 39 | /// 40 | /// List of Show Object 41 | /// 42 | [DataMember(Name = "shows")] 43 | public List Shows { get; set; } 44 | 45 | /// 46 | /// List of Audiobook Object 47 | /// 48 | [DataMember(Name = "audiobooks")] 49 | public List Audiobooks { get; set; } 50 | 51 | /// 52 | /// List of Chapter Object 53 | /// 54 | [DataMember(Name = "chapters")] 55 | public List Chapters { get; set; } 56 | } 57 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Narrator.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Narrator Object 5 | /// 6 | [DataContract] 7 | public class Narrator 8 | { 9 | /// 10 | /// The name of the Narrator 11 | /// 12 | [DataMember(Name = "name")] 13 | public string Label { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Paging.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Paging Object 5 | /// 6 | /// Object Type 7 | [DataContract] 8 | public class Paging : Page 9 | { 10 | /// 11 | /// Error Object 12 | /// 13 | [DataMember(Name = "error")] 14 | public ErrorResponse Error { get; set; } 15 | 16 | /// 17 | /// A link to the Web API endpoint returning the full result of the request. 18 | /// 19 | [DataMember(Name = "href")] 20 | public string Href { get; set; } 21 | 22 | /// 23 | /// The requested data. 24 | /// 25 | [DataMember(Name = "items")] 26 | public List Items { get; set; } 27 | 28 | /// 29 | /// URL to the next page of items. (null if none) 30 | /// 31 | [DataMember(Name = "next")] 32 | public string Next { get; set; } 33 | 34 | /// 35 | /// URL to the previous page of items. (null if none) 36 | /// 37 | [DataMember(Name = "previous")] 38 | public string Previous { get; set; } 39 | 40 | /// 41 | /// IEnumerable of Type 42 | /// 43 | public IEnumerable ReadOnlyItems => Items; 44 | 45 | /// 46 | /// Page 47 | /// 48 | public Page Page { get { return this; } } 49 | 50 | /// 51 | /// Constructor 52 | /// 53 | public Paging() 54 | { 55 | Items = new List(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/PlayHistory.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Play History Object 5 | /// 6 | [DataContract] 7 | public class PlayHistory : BaseResponse 8 | { 9 | /// 10 | /// The track the user listened to. 11 | /// 12 | [DataMember(Name = "track")] 13 | public Track Track { get; set; } 14 | 15 | /// 16 | /// The date and time the track was played. Format yyyy-MM-ddTHH:mm:ss 17 | /// 18 | [DataMember(Name = "played_at")] 19 | public string PlayedAt { get; set; } 20 | 21 | /// 22 | /// The context the track was played from. 23 | /// 24 | [DataMember(Name = "context")] 25 | public Context Context { get; set; } 26 | } 27 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Playlist.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Playlist Object 5 | /// 6 | [DataContract] 7 | public class Playlist : SimplifiedPlaylist 8 | { 9 | /// 10 | /// The playlist description. Only returned for modified, verified playlists, otherwise null. 11 | /// 12 | [DataMember(Name = "description")] 13 | public string Description { get; set; } 14 | 15 | /// 16 | /// Information about the followers of the playlist. 17 | /// 18 | [DataMember(Name = "followers")] 19 | public Followers Followers { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/PlaylistTrack.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Playlist Track Object 5 | /// 6 | [DataContract] 7 | public class PlaylistTrack : BaseResponse 8 | { 9 | /// 10 | /// The date and time the track was added. 11 | /// 12 | [DataMember(Name = "added_at")] 13 | public DateTime? AddedAt { get; set; } 14 | 15 | /// 16 | /// The Spotify user who added the track. 17 | /// 18 | [DataMember(Name = "added_by")] 19 | public PublicUser AddedBy { get; set; } 20 | 21 | /// 22 | /// Whether this track is a local file or not. 23 | /// 24 | [DataMember(Name = "is_local")] 25 | public bool IsLocal { get; set; } 26 | 27 | /// 28 | /// Information about the track or episode. 29 | /// 30 | [DataMember(Name = "track")] 31 | public object Item { get; set; } 32 | 33 | /// 34 | /// Information about the track 35 | /// 36 | [IgnoreDataMember] 37 | public Track Track => Item.AsTrack(); 38 | 39 | /// 40 | /// Information about the episode 41 | /// 42 | [IgnoreDataMember] 43 | public Episode Episode => Item.AsEpisode(); 44 | } 45 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/PrivateUser.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Private User Object 5 | /// 6 | [DataContract] 7 | public class PrivateUser : PublicUser 8 | { 9 | /// 10 | /// The country of the user, as set in the user’s account profile.An ISO 3166-1 alpha-2 country code.This field is only available when the current user has granted access to the user-read-private scope. 11 | /// 12 | [DataMember(Name = "country")] 13 | public string Country { get; set; } 14 | 15 | /// 16 | /// The user’s email address, as entered by the user when creating their account. his field is only available when the current user has granted access to the user-read-email scope 17 | /// 18 | [DataMember(Name = "email")] 19 | public string Email { get; set; } 20 | 21 | /// 22 | /// The user’s Spotify subscription level: “premium”, “free”, etc. This field is only available when the current user has granted access to the user-read-private scope. 23 | /// 24 | [DataMember(Name = "product")] 25 | public string Product { get; set; } 26 | } 27 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/PublicUser.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Public User Object 5 | /// 6 | [DataContract] 7 | public class PublicUser : Content 8 | { 9 | /// 10 | /// The name displayed on the user’s profile. null if not available. 11 | /// 12 | [DataMember(Name = "display_name")] 13 | public string DisplayName { get; set; } 14 | 15 | /// 16 | /// Information about the followers of this user. 17 | /// 18 | [DataMember(Name = "followers")] 19 | public Followers Followers { get; set; } 20 | 21 | /// 22 | /// The user’s profile image. 23 | /// 24 | [DataMember(Name = "images")] 25 | public List Images { get; set; } 26 | } 27 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Queue.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Queue 5 | /// 6 | [DataContract] 7 | public class Queue 8 | { 9 | /// 10 | /// Currently Playing Track or Episode. Can be null 11 | /// 12 | [DataMember(Name = "currently_playing")] 13 | public Album CurrentlyPlaying { get; set; } 14 | 15 | /// 16 | /// Tracks or Episodes in the Queue 17 | /// 18 | [DataMember(Name = "queue")] 19 | public List Albums { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/RecommendationSeed.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Recommendation Seed Object 5 | /// 6 | [DataContract] 7 | public class RecommendationSeed : Content 8 | { 9 | /// 10 | /// The number of tracks available after min_* and max_* filters have been applied. 11 | /// 12 | [DataMember(Name = "afterFilteringSize")] 13 | public int AfterFilteringSize { get; set; } 14 | 15 | /// 16 | /// The number of tracks available after relinking for regional availability. 17 | /// 18 | [DataMember(Name = "afterRelinkingSize")] 19 | public int AfterRelinkingSize { get; set; } 20 | 21 | /// 22 | /// The number of recommended tracks available for this seed. 23 | /// 24 | [DataMember(Name = "initialPoolSize")] 25 | public int InitialPoolSize { get; set; } 26 | } 27 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/RecommendationsResponse.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Recommendations Response Object 5 | /// 6 | [DataContract] 7 | public class RecommendationsResponse : BaseResponse 8 | { 9 | /// 10 | /// An array of recommendation seed objects. 11 | /// 12 | [DataMember(Name = "seeds")] 13 | public List Seeds { get; set; } 14 | 15 | /// 16 | /// An array of track object (simplified) ordered according to the parameters supplied. 17 | /// 18 | [DataMember(Name = "tracks")] 19 | public List Tracks { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/ResumePoint.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Resume Point Object 5 | /// 6 | [DataContract] 7 | public class ResumePoint 8 | { 9 | /// 10 | /// Whether or not the episode has been fully played by the user 11 | /// 12 | [DataMember(Name = "fully_played")] 13 | public bool FullyPlayed { get; set; } 14 | 15 | /// 16 | /// The user’s most recent position in the episode in milliseconds 17 | /// 18 | [DataMember(Name = "resume_position_ms")] 19 | public long ResumePosition { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/SavedAlbum.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Saved Album Object 5 | /// 6 | [DataContract] 7 | public class SavedAlbum : BaseResponse 8 | { 9 | /// 10 | /// The date and time the album was saved Timestamps are returned in ISO 8601 format as Coordinated Universal Time (UTC) with a zero offset: YYYY-MM-DDTHH:MM:SSZ. If the time is imprecise (for example, the date/time of an album release), an additional field indicates the precision; see for example, ReleaseDate in an album object. 11 | /// 12 | [DataMember(Name = "added_at")] 13 | public string AddedAt { get; set; } 14 | 15 | /// 16 | /// Information about the album. 17 | /// 18 | [DataMember(Name = "album")] 19 | public Album Album { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/SavedEpisode.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Saved Episode Object 5 | /// 6 | public class SavedEpisode : BaseResponse 7 | { 8 | /// 9 | /// The date and time the episode was saved. Timestamps are returned in ISO 8601 format as Coordinated Universal Time (UTC) with a zero offset: YYYY-MM-DDTHH:MM:SSZ. If the time is imprecise (for example, the date/time of an show release), an additional field indicates the precision; see for example, ReleaseDate in a show object. 10 | /// 11 | [DataMember(Name = "added_at")] 12 | public string AddedAt { get; set; } 13 | 14 | /// 15 | /// Information about the episode 16 | /// 17 | [DataMember(Name = "episode")] 18 | public SimplifiedEpisode Episode { get; set; } 19 | } 20 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/SavedShow.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Saved Show Object 5 | /// 6 | public class SavedShow : BaseResponse 7 | { 8 | /// 9 | /// The date and time the show was saved. Timestamps are returned in ISO 8601 format as Coordinated Universal Time (UTC) with a zero offset: YYYY-MM-DDTHH:MM:SSZ. If the time is imprecise (for example, the date/time of an show release), an additional field indicates the precision; see for example, ReleaseDate in a show object. 10 | /// 11 | [DataMember(Name = "added_at")] 12 | public string AddedAt { get; set; } 13 | 14 | /// 15 | /// Information about the show 16 | /// 17 | [DataMember(Name = "show")] 18 | public SimplifiedShow Show { get; set; } 19 | } 20 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/SavedTrack.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Saved Track Object 5 | /// 6 | [DataContract] 7 | public class SavedTrack : BaseResponse 8 | { 9 | /// 10 | /// The date and time the track was saved. Timestamps are returned in ISO 8601 format as Coordinated Universal Time (UTC) with a zero offset: YYYY-MM-DDTHH:MM:SSZ. If the time is imprecise (for example, the date/time of an album release), an additional field indicates the precision; see for example, release_date in an album object. 11 | /// 12 | [DataMember(Name = "added_at")] 13 | public string AddedAt { get; set; } 14 | 15 | /// 16 | /// Information about the track. 17 | /// 18 | [DataMember(Name = "track")] 19 | public Track Track { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Section.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Section Object 5 | /// 6 | [DataContract] 7 | public class Section : TimeInterval 8 | { 9 | /// 10 | /// The overall loudness of the section in decibels (dB). 11 | /// 12 | [DataMember(Name = "loudness")] 13 | public float? Loudness { get; set; } 14 | 15 | /// 16 | /// The overall estimated tempo of the section in beats per minute (BPM). 17 | /// 18 | [DataMember(Name = "tempo")] 19 | public float? Tempo { get; set; } 20 | 21 | /// 22 | /// The confidence, from 0.0 to 1.0, of the reliability of the tempo. 23 | /// 24 | [DataMember(Name = "tempo_confidence")] 25 | public float? TempoConfidence { get; set; } 26 | 27 | /// 28 | /// The estimated overall key of the section. The values in this field ranging from 0 to 11 mapping to pitches using standard Pitch Class notation 29 | /// 30 | [DataMember(Name = "key")] 31 | public int? Key { get; set; } 32 | 33 | /// 34 | /// The confidence, from 0.0 to 1.0, of the reliability of the key. 35 | /// 36 | [DataMember(Name = "key_confidence")] 37 | public float? KeyConfidence { get; set; } 38 | 39 | /// 40 | /// Indicates the modality (major or minor) of a track, the type of scale from which its melodic content is derived.This field will contain a 0 for “minor”, a 1 for “major”, or a -1 for no result. 41 | /// 42 | [DataMember(Name = "mode")] 43 | public int? Mode { get; set; } 44 | 45 | /// 46 | /// The confidence, from 0.0 to 1.0, of the reliability of the mode. 47 | /// 48 | [DataMember(Name = "mode_confidence")] 49 | public float? ModeConfidence { get; set; } 50 | 51 | /// 52 | /// An estimated overall time signature of a track. The time signature (meter) is a notational convention to specify how many beats are in each bar (or measure). The time signature ranges from 3 to 7 indicating time signatures of “3/4”, to “7/4”. 53 | /// 54 | [DataMember(Name = "time_signature")] 55 | public int? TimeSignature { get; set; } 56 | 57 | /// 58 | /// The confidence, from 0.0 to 1.0, of the reliability of the time_signature. 59 | /// 60 | [DataMember(Name = "time_signature_confidence")] 61 | public float? TimeSignatureConfidence { get; set; } 62 | } 63 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Segment.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Segment Object 5 | /// 6 | [DataContract] 7 | public class Segment : TimeInterval 8 | { 9 | /// 10 | /// The onset loudness of the segment in decibels (dB). 11 | /// 12 | [DataMember(Name = "loudness_start")] 13 | public float? LoudnessStart { get; set; } 14 | 15 | /// 16 | /// The peak loudness of the segment in decibels (dB). 17 | /// 18 | [DataMember(Name = "loudness_max")] 19 | public float? LoudnessMax { get; set; } 20 | 21 | /// 22 | /// The segment-relative offset of the segment peak loudness in seconds. 23 | /// 24 | [DataMember(Name = "loudness_max_time")] 25 | public float? LoudnessMaxTime { get; set; } 26 | 27 | /// 28 | /// The offset loudness of the segment in decibels (dB). 29 | /// 30 | [DataMember(Name = "loudness_end")] 31 | public float? LoudnessEnd { get; set; } 32 | 33 | /// 34 | /// A “chroma” vector representing the pitch content of the segment, corresponding to the 12 pitch classes C, C#, D to B, with values ranging from 0 to 1 that describe the relative dominance of every pitch in the chromatic scale 35 | /// 36 | [DataMember(Name = "pitches")] 37 | public List Pitches { get; set; } 38 | 39 | /// 40 | /// Timbre is the quality of a musical note or sound that distinguishes different types of musical instruments, or voices. 41 | /// 42 | [DataMember(Name = "timbre")] 43 | public List Timbre { get; set; } 44 | } 45 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Show.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Show Object 5 | /// 6 | public class Show : SimplifiedShow 7 | { 8 | /// 9 | /// A list of the show’s episodes. 10 | /// 11 | [DataMember(Name = "episodes")] 12 | public Paging Episodes { get; set; } 13 | } 14 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/SimplifiedAlbum.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Simplified Album Object 5 | /// 6 | [DataContract] 7 | public class SimplifiedAlbum : Content 8 | { 9 | /// 10 | /// The field is present when getting an artist’s albums. Possible values are “album”, “single”, “compilation”, “appears_on”. 11 | /// 12 | [DataMember(Name = "album_group")] 13 | public string AlbumGroup { get; set; } 14 | 15 | /// 16 | /// The type of the album: one of "album" , "single" , or "compilation". 17 | /// 18 | [DataMember(Name = "album_type")] 19 | public string AlbumType { get; set; } 20 | 21 | /// 22 | /// The artists of the album. Each artist object includes a link in href to more detailed information about the artist. 23 | /// 24 | [DataMember(Name = "artists")] 25 | public List Artists { get; set; } 26 | 27 | /// 28 | /// The markets in which the album is available: ISO 3166-1 alpha-2 country codes 29 | /// 30 | [DataMember(Name = "available_markets")] 31 | public List AvailableMarkets { get; set; } 32 | 33 | /// 34 | /// The cover art for the album in various sizes, widest first. 35 | /// 36 | [DataMember(Name = "images")] 37 | public List Images { get; set; } 38 | 39 | /// 40 | /// The total number of tracks 41 | /// 42 | [DataMember(Name = "total_tracks")] 43 | public int TotalTracks { get; set; } 44 | } 45 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/SimplifiedArtist.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Simplified Artist Object 5 | /// 6 | [DataContract] 7 | public class SimplifiedArtist : Content { } 8 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/SimplifiedAudiobook.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Simplified Audiobook Object 5 | /// 6 | [DataContract] 7 | public class SimplifiedAudiobook : Content 8 | { 9 | /// 10 | /// The author(s) for the audiobook 11 | /// 12 | [DataMember(Name = "authors")] 13 | public List Authors { get; set; } 14 | 15 | /// 16 | /// A list of the countries in which the audiobook can be played, identified by their ISO 3166-1 alpha-2 code 17 | /// 18 | [DataMember(Name = "available_markets")] 19 | public List AvailableMarkets { get; set; } 20 | 21 | /// 22 | /// The copyright statements of the audiobook. 23 | /// 24 | [DataMember(Name = "copyrights")] 25 | public List Copyrights { get; set; } 26 | 27 | /// 28 | /// A description of the audiobook. HTML tags are stripped away from this field, use html_description field in case HTML tags are needed. 29 | /// 30 | [DataMember(Name = "description")] 31 | public string Description { get; set; } 32 | 33 | /// 34 | /// A description of the audiobook. This field may contain HTML tags. 35 | /// 36 | [DataMember(Name = "html_description")] 37 | public string HtmlDescription { get; set; } 38 | 39 | /// 40 | /// Whether or not the audiobook has explicit content (true = yes it does; false = no it does not OR unknown). 41 | /// 42 | [DataMember(Name = "explicit")] 43 | public bool IsExplicit { get; set; } 44 | 45 | /// 46 | /// The cover art for the audiobook in various sizes, widest first. 47 | /// 48 | [DataMember(Name = "images")] 49 | public List Images { get; set; } 50 | 51 | /// 52 | /// A list of the languages used in the audiobook, identified by their ISO 639 code. 53 | /// 54 | [DataMember(Name = "languages")] 55 | public List Languages { get; set; } 56 | 57 | /// 58 | /// The media type of the audiobook. 59 | /// 60 | [DataMember(Name = "media_type")] 61 | public string MediaType { get; set; } 62 | 63 | /// 64 | /// The narrators(s) of the audiobook 65 | /// 66 | [DataMember(Name = "narrators")] 67 | public List Narrators { get; set; } 68 | 69 | /// 70 | /// The publisher of the audiobook. 71 | /// 72 | [DataMember(Name = "publisher")] 73 | public string Publisher { get; set; } 74 | 75 | /// 76 | /// The number of chapters in this audiobook. 77 | /// 78 | [DataMember(Name = "total_chapters")] 79 | public int? TotalChapters { get; set; } 80 | } 81 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/SimplifiedChapter.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Simplified Chapter Object 5 | /// 6 | public class SimplifiedChapter : Content 7 | { 8 | /// 9 | /// A URL to a 30 second preview (MP3 format) of the chapter - null if not available. 10 | /// 11 | [DataMember(Name = "audio_preview_url")] 12 | public string Preview { get; set; } 13 | 14 | /// 15 | /// The number of the chapter. 16 | /// 17 | [DataMember(Name = "chapter_number")] 18 | public int ChapterNumber { get; set; } 19 | 20 | /// 21 | /// A description of the chapter. HTML tags are stripped away from this field, use html_description field in case HTML tags are needed. 22 | /// 23 | [DataMember(Name = "description")] 24 | public string Description { get; set; } 25 | 26 | /// 27 | /// A description of the chapter. This field may contain HTML tags. 28 | /// 29 | [DataMember(Name = "html_description")] 30 | public string HtmlDescription { get; set; } 31 | 32 | /// 33 | /// The chapter length in milliseconds 34 | /// 35 | [DataMember(Name = "duration_ms")] 36 | public long Duration { get; set; } 37 | 38 | /// 39 | /// Whether or not the chapter has explicit content ( true = yes it does; false = no it does not OR unknown) 40 | /// 41 | [DataMember(Name = "explicit")] 42 | public bool IsExplicit { get; set; } 43 | 44 | /// 45 | /// The cover art for the chapter in various sizes, widest first 46 | /// 47 | [DataMember(Name = "images")] 48 | public List Images { get; set; } 49 | 50 | /// 51 | /// True if the chapter is playable in the given market. Otherwise false 52 | /// 53 | [DataMember(Name = "is_playable")] 54 | public bool IsPlayable { get; set; } 55 | 56 | /// 57 | /// A list of the languages used in the chapter, identified by their ISO 639 code 58 | /// 59 | [DataMember(Name = "languages")] 60 | public List Languages { get; set; } 61 | 62 | /// 63 | /// The date the chapter was first released, for example 1981-12-15. Depending on the precision, it might be shown as 1981 or 1981-12 64 | /// 65 | [DataMember(Name = "release_date")] 66 | public string ReleaseDate { get; set; } 67 | 68 | /// 69 | /// The precision with which ReleaseDate value is known: year, month, or day 70 | /// 71 | [DataMember(Name = "release_date_precision")] 72 | public string ReleaseDatePrecision { get; set; } 73 | 74 | /// 75 | /// The user's most recent position in the chapter. Set if the supplied access token is a user token and has the scope user-read-playback-position 76 | /// 77 | [DataMember(Name = "resume_point")] 78 | public ResumePoint ResumePoint { get; set; } 79 | 80 | /// 81 | /// Included in the response when a content restriction is applied. 82 | /// 83 | [DataMember(Name = "restrictions")] 84 | public TrackRestriction Restrictions { get; set; } 85 | } 86 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/SimplifiedCurrentlyPlaying.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Simplified Currently Playing Object 5 | /// 6 | [DataContract] 7 | public class SimplifiedCurrentlyPlaying : BaseResponse 8 | { 9 | /// 10 | /// A Context Object. Can be null 11 | /// 12 | [DataMember(Name = "context")] 13 | public Context Context { get; set; } 14 | 15 | /// 16 | /// Unix Millisecond Timestamp when data was fetched 17 | /// 18 | [DataMember(Name = "timestamp")] 19 | public long TimeStamp { get; set; } 20 | 21 | /// 22 | /// Progress into the currently playing track. Can be null. 23 | /// 24 | [DataMember(Name = "progress_ms")] 25 | public long? Progress { get; set; } 26 | 27 | /// 28 | /// If something is currently playing, return true. 29 | /// 30 | [DataMember(Name = "is_playing")] 31 | public bool IsPlaying { get; set; } 32 | 33 | /// 34 | /// The currently playing item. Can be null. 35 | /// 36 | [DataMember(Name = "item")] 37 | public object Item { get; set; } 38 | 39 | /// 40 | /// The currently playing track. Can be null. 41 | /// 42 | [IgnoreDataMember] 43 | public Track Track => Item.AsTrack(); 44 | 45 | /// 46 | /// The currently playing episode. Can be null. 47 | /// 48 | [IgnoreDataMember] 49 | public Episode Episode => Item.AsEpisode(); 50 | 51 | /// 52 | /// The object type of the currently playing item. Can be one of track, episode, ad or unknown. 53 | /// 54 | [DataMember(Name = "currently_playing_type")] 55 | public string Type { get; set; } 56 | 57 | /// 58 | /// Allows to update the user interface based on which playback actions are available within the current context 59 | /// 60 | [DataMember(Name = "actions")] 61 | public Actions Actions { get; set; } 62 | } 63 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/SimplifiedEpisode.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Simplified Episode Object 5 | /// 6 | public class SimplifiedEpisode : Content 7 | { 8 | /// 9 | /// A URL to a 30 second preview (MP3 format) of the episode - null if not available 10 | /// 11 | [DataMember(Name = "audio_preview_url")] 12 | public string Preview { get; set; } 13 | 14 | /// 15 | /// The description of the episode 16 | /// 17 | [DataMember(Name = "description")] 18 | public string Description { get; set; } 19 | 20 | /// 21 | /// The episode length in milliseconds 22 | /// 23 | [DataMember(Name = "duration_ms")] 24 | public long Duration { get; set; } 25 | 26 | /// 27 | /// Whether or not the episode has explicit content ( true = yes it does; false = no it does not OR unknown) 28 | /// 29 | [DataMember(Name = "explicit")] 30 | public bool IsExplicit { get; set; } 31 | 32 | /// 33 | /// The cover art for the episode in various sizes, widest first 34 | /// 35 | [DataMember(Name = "images")] 36 | public List Images { get; set; } 37 | 38 | /// 39 | /// True if the episode is hosted outside of Spotify's CDN 40 | /// 41 | [DataMember(Name = "is_externally_hosted")] 42 | public bool IsExternallyHosted { get; set; } 43 | 44 | /// 45 | /// True if the episode is playable in the given market. Otherwise false 46 | /// 47 | [DataMember(Name = "is_playable")] 48 | public bool IsPlayable { get; set; } 49 | 50 | /// 51 | /// A list of the languages used in the episode, identified by their ISO 639 code 52 | /// 53 | [DataMember(Name = "languages")] 54 | public List Languages { get; set; } 55 | 56 | /// 57 | /// The date the episode was first released, for example 1981-12-15. Depending on the precision, it might be shown as 1981 or 1981-12 58 | /// 59 | [DataMember(Name = "release_date")] 60 | public string ReleaseDate { get; set; } 61 | 62 | /// 63 | /// The precision with which ReleaseDate value is known: year, month, or day 64 | /// 65 | [DataMember(Name = "release_date_precision")] 66 | public string ReleaseDatePrecision { get; set; } 67 | 68 | /// 69 | /// The user's most recent position in the episode. Set if the supplied access token is a user token and has the scope user-read-playback-position 70 | /// 71 | [DataMember(Name = "resume_point")] 72 | public ResumePoint ResumePoint { get; set; } 73 | } 74 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/SimplifiedPlaylist.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Simplified Playlist Object 5 | /// 6 | [DataContract] 7 | public class SimplifiedPlaylist : Content 8 | { 9 | /// 10 | /// Returns true if the owner allows other users to modify the playlist. 11 | /// 12 | [DataMember(Name = "collaborative")] 13 | public bool Collaborative { get; set; } 14 | 15 | /// 16 | /// Images for the playlist. The array may be empty or contain up to three images. The images are returned by size in descending order. 17 | /// 18 | [DataMember(Name = "images")] 19 | public List Images { get; set; } 20 | 21 | /// 22 | /// The user who owns the playlist 23 | /// 24 | [DataMember(Name = "owner")] 25 | public PublicUser Owner { get; set; } 26 | 27 | /// 28 | /// The playlist’s public/private status: true the playlist is public, false the playlist is private, null the playlist status is not relevant 29 | /// 30 | [DataMember(Name = "public")] 31 | public bool? Public { get; set; } 32 | 33 | /// 34 | /// The version identifier for the current playlist. 35 | /// 36 | [DataMember(Name = "snapshot_id")] 37 | public string SnapshotId { get; set; } 38 | 39 | /// 40 | /// Information about the tracks of the playlist. 41 | /// 42 | [DataMember(Name = "tracks")] 43 | public Paging Tracks { get; set; } 44 | } 45 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/SimplifiedShow.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Simplified Show Object 5 | /// 6 | public class SimplifiedShow : Content 7 | { 8 | /// 9 | /// A list of the countries in which the show can be played, identified by their ISO 3166-1 alpha-2 code 10 | /// 11 | [DataMember(Name = "available_markets")] 12 | public List AvailableMarkets { get; set; } 13 | 14 | /// 15 | /// The copyright statements of the show 16 | /// 17 | [DataMember(Name = "copyrights")] 18 | public List Copyrights { get; set; } 19 | 20 | /// 21 | /// A description of the show 22 | /// 23 | [DataMember(Name = "description")] 24 | public string Description { get; set; } 25 | 26 | /// 27 | /// Whether or not the show has explicit content ( true = yes it does; false = no it does not OR unknown) 28 | /// 29 | [DataMember(Name = "explicit")] 30 | public bool IsExplicit { get; set; } 31 | 32 | /// 33 | /// The cover art for the show in various sizes, widest first 34 | /// 35 | [DataMember(Name = "images")] 36 | public List Images { get; set; } 37 | 38 | /// 39 | /// True if all of the show's episodes are hosted outside of Spotify’s CDN 40 | /// 41 | [DataMember(Name = "is_externally_hosted")] 42 | public bool IsExternallyHosted { get; set; } 43 | 44 | /// 45 | /// A list of the languages used in the show, identified by their ISO 639 code 46 | /// 47 | [DataMember(Name = "languages")] 48 | public List Languages { get; set; } 49 | 50 | /// 51 | /// The media type of the show 52 | /// 53 | [DataMember(Name = "media_type")] 54 | public string MediaType { get; set; } 55 | 56 | /// 57 | /// The publisher of the show 58 | /// 59 | [DataMember(Name = "publisher")] 60 | public string Publisher { get; set; } 61 | } 62 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/SimplifiedTrack.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Simplified Track Object 5 | /// 6 | [DataContract] 7 | public class SimplifiedTrack : Content 8 | { 9 | /// 10 | /// The artists who performed the track. Each artist object includes a link in href to more detailed information about the artist. 11 | /// 12 | [DataMember(Name = "artists")] 13 | public List Artists { get; set; } 14 | 15 | /// 16 | /// A list of the countries in which the track can be played, identified by their ISO 3166-1 alpha-2 code. 17 | /// 18 | [DataMember(Name = "available_markets")] 19 | public List AvailableMarkets { get; set; } 20 | 21 | /// 22 | /// The disc number (usually 1 unless the album consists of more than one disc). 23 | /// 24 | [DataMember(Name = "disc_number")] 25 | public int DiscNumber { get; set; } 26 | 27 | /// 28 | /// The track length in milliseconds. 29 | /// 30 | [DataMember(Name = "duration_ms")] 31 | public long Duration { get; set; } 32 | 33 | /// 34 | /// Whether or not the track has explicit lyrics ( true = yes it does; false = no it does not OR unknown). 35 | /// 36 | [DataMember(Name = "explicit")] 37 | public bool IsExplicit { get; set; } 38 | 39 | /// 40 | /// Part of the response when Track Relinking is applied. If true , the track is playable in the given market. Otherwise false. 41 | /// 42 | [DataMember(Name = "is_playable")] 43 | public bool IsPlayable { get; set; } 44 | 45 | /// 46 | /// Part of the response when Track Relinking is applied and is only part of the response if the track linking, in fact, exists 47 | /// 48 | [DataMember(Name = "linked_from")] 49 | public LinkedTrack LinkedFrom { get; set; } 50 | 51 | /// 52 | /// A link to a 30 second preview (MP3 format) of the track. 53 | /// 54 | [DataMember(Name = "preview_url")] 55 | public string Preview { get; set; } 56 | 57 | /// 58 | /// The number of the track. If an album has several discs, the track number is the number on the specified disc. 59 | /// 60 | [DataMember(Name = "track_number")] 61 | public int TrackNumber { get; set; } 62 | 63 | /// 64 | /// Whether or not the track is from a local file. 65 | /// 66 | [DataMember(Name = "is_local")] 67 | public bool IsLocal { get; set; } 68 | } 69 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Snapshot.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Snapshot Response Object 5 | /// 6 | [DataContract] 7 | public class Snapshot : Status 8 | { 9 | /// 10 | /// Can be used to identify playlist version in future requests 11 | /// 12 | [DataMember(Name = "snapshot_id")] 13 | public string SnapshotId { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Status.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Status Response 5 | /// 6 | [DataContract] 7 | public class Status : BaseResponse 8 | { 9 | /// 10 | /// Status Code 11 | /// 12 | public HttpStatusCode StatusCode { get; set; } 13 | 14 | /// 15 | /// Code 16 | /// 17 | public int Code => (int)StatusCode; 18 | 19 | /// 20 | /// Success 21 | /// 22 | public bool Success { get; set; } 23 | } 24 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/TimeInterval.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Time Interval Object 5 | /// 6 | [DataContract] 7 | public class TimeInterval 8 | { 9 | /// 10 | /// The starting point in seconds. 11 | /// 12 | [DataMember(Name = "start")] 13 | public float? Start { get; set; } 14 | 15 | /// 16 | /// The duration in seconds 17 | /// 18 | [DataMember(Name = "duration")] 19 | public float? Duration { get; set; } 20 | 21 | /// 22 | /// The reliability confidence, from 0.0 to 1.0 23 | /// 24 | [DataMember(Name = "confidence")] 25 | public float? Confidence { get; set; } 26 | } 27 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/Track.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Track Object 5 | /// 6 | [DataContract] 7 | public class Track : SimplifiedTrack 8 | { 9 | /// 10 | /// The album on which the track appears.The album object includes a link in href to full information about the album. 11 | /// 12 | [DataMember(Name = "album")] 13 | public SimplifiedAlbum Album { get; set; } 14 | 15 | /// 16 | /// Known external IDs for the track. 17 | /// 18 | [DataMember(Name = "external_ids")] 19 | public ExternalId ExternalId { get; set; } 20 | 21 | /// 22 | /// The popularity of the track. The value will be between 0 and 100, with 100 being the most popular. 23 | /// 24 | [DataMember(Name = "popularity")] 25 | public int Popularity { get; set; } 26 | 27 | /// 28 | /// Part of the response when Track Relinking is applied, the original track is not available in the given market 29 | /// 30 | [DataMember(Name = "restrictions")] 31 | public TrackRestriction Restrictions { get; set; } 32 | } 33 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Responses/TrackRestriction.cs: -------------------------------------------------------------------------------- 1 | namespace Spotify.NetStandard.Responses; 2 | 3 | /// 4 | /// Track Restriction Object 5 | /// 6 | [DataContract] 7 | public class TrackRestriction 8 | { 9 | /// 10 | /// Contains the reason why the track is not available e.g. market 11 | /// 12 | [DataMember(Name = "reason")] 13 | public string Reason { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Spotify.NetStandard.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netstandard2.0 4 | enable 5 | 2.1.0 6 | RoguePlanetoid 7 | Comentsys 8 | Spotify API .NET Standard Library 9 | https://github.com/RoguePlanetoid/Spotify-NetStandard 10 | https://github.com/RoguePlanetoid/Spotify-NetStandard 11 | 12 | 1.0.0 Initial Release 13 | 1.0.1 Added Multi Scope Helpers by parkeradam 14 | 1.0.2 Fixed Extension Methods 15 | 1.1.0 Added Authenticated Get and Fixed Cursor Methods 16 | 1.1.1 Fixed Cursor and Paging Navigation 17 | 1.1.2 Fixed and Improved Authentication Exceptions including minor Client Changes 18 | 1.1.3 Removed User Birthdate Value and Scope 19 | 1.1.4 Fixed Token Storage and Get Playlist Tracks 20 | 1.1.5 Added Actions Object, Disallows Object, Simplified Playlist Object and updated related methods 21 | 1.2.0 Added Add an Item to the User's Playback Queue, Updated Get a Playlist and Get Playlist's Tracks to support Fields Parameter and Fixed Check/Lookup Methods Return Error Status Correctly 22 | 1.5.0 Added Save Shows for Current User, Get User's Saved Shows, Remove User's Saved Shows, Get an Episode, Get Multiple Episodes, Get a Show, Get Multiple Shows and Get a Show's Episodes plus PlaybackPositionRead Scope. Updated Get the User's Currently Playing Track, Get Information About The User's Current Playback and Search for an Item 23 | 1.5.5 Fixed issue with Market and Country being used correctly 24 | 1.6.0 Updated Remove Tracks from Playlist to support Positions and Added Paging Method 25 | 1.6.5 Updated Get a Playlist and Get a Playlist's Items to support Additional Types 26 | 1.6.6 Fixed Track or Episode identification issue with Playlist Track and Currently Playing Objects 27 | 1.7.0 Added Authorization Code Flow with Proof Key for Code Exchange (PKCE), Updated Track Restrictions and Newtonsoft.Json 28 | 1.7.5 Added Authorization Code Flow with Proof Key for Code Exchange (PKCE) for API 29 | 1.7.6 Fixed issue with Resume Point not returning Resume Position Correctly 30 | 1.7.7 Fixed issue with Authentication Cache Response Uri 31 | 1.8.0 Updated Authentication Flow with PKCE for Refresh Token 32 | 1.9.0 Added External HttpClient Support and Uno Platform Compatibility 33 | 2.0.0 Refactored Code, Added User Episodes, Audiobook, Chapter and Queue, Updated Authorisation Code Flow with Code Verifier using Proof Key for Code Exchange (PKCE), Removed Authorisation Code Flow without Code Verifier and Original Proof Key for Code Exchange (PKCE) Flow 34 | 2.1.0 Restored Authorisation Code Flow 35 | 36 | true 37 | 2.1.0.0 38 | MIT 39 | 2.1.0.0 40 | 10.0 41 | README.md 42 | spotify.netstandard.png 43 | 44 | 45 | 46 | C:\GitHub\Spotify-NetStandard\Spotify.NetStandard\Spotify.NetStandard\Spotify.NetStandard.xml 47 | 48 | 49 | 50 | C:\GitHub\Spotify-NetStandard\Spotify.NetStandard\Spotify.NetStandard\Spotify.NetStandard.xml 51 | 52 | 53 | 54 | 55 | True 56 | \ 57 | 58 | 59 | True 60 | \ 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /Spotify.NetStandard/Spotify.NetStandard/Usings.cs: -------------------------------------------------------------------------------- 1 | global using Newtonsoft.Json; 2 | global using Spotify.NetStandard.Client.Authentication; 3 | global using Spotify.NetStandard.Client.Authentication.Enums; 4 | global using Spotify.NetStandard.Client.Authentication.Internal; 5 | global using Spotify.NetStandard.Client.Exceptions; 6 | global using Spotify.NetStandard.Client.Interfaces; 7 | global using Spotify.NetStandard.Client.Internal; 8 | global using Spotify.NetStandard.Enums; 9 | global using Spotify.NetStandard.Requests; 10 | global using Spotify.NetStandard.Responses; 11 | global using Spotify.NetStandard.Responses.Internal; 12 | global using System.Collections.Specialized; 13 | global using System.ComponentModel; 14 | global using System.Net; 15 | global using System.Net.Http.Headers; 16 | global using System.Reflection; 17 | global using System.Runtime.Serialization; 18 | global using System.Security.Cryptography; 19 | global using System.Text; 20 | global using System.Web; 21 | --------------------------------------------------------------------------------