├── ExampleConsoleApp
├── .gitignore
├── appsettings.json
├── ExampleConsoleApp.csproj
├── Startup.cs
├── Program.cs
└── SpotifyAuthentication.cs
├── SpotifyIcon.png
├── SpotifyWebApi
├── Api
│ ├── Follow
│ │ └── IFollowApi.cs
│ ├── UserLibrary
│ │ └── IUserLibraryApi.cs
│ ├── Personalization
│ │ └── IPersonalizationApi.cs
│ ├── UserProfile
│ │ ├── IUserProfileApi.cs
│ │ └── UserProfileApi.cs
│ ├── Search
│ │ └── ISearchApi.cs
│ ├── Track
│ │ ├── ITrackApi.cs
│ │ └── TrackApi.cs
│ ├── Browse
│ │ ├── BrowseApi.cs
│ │ └── IBrowseApi.cs
│ ├── Album
│ │ ├── IAlbumApi.cs
│ │ └── AlbumApi.cs
│ ├── Artist
│ │ ├── IArtistApi.cs
│ │ └── ArtistApi.cs
│ ├── BaseApi.cs
│ ├── Player
│ │ ├── PlayerApi.cs
│ │ └── IPlayerApi.cs
│ └── Playlist
│ │ ├── PlaylistApi.cs
│ │ └── IPlaylistApi.cs
├── Properties
│ └── AssemblyInfo.cs
├── FodyWeavers.xml
├── Model
│ ├── Cursor.cs
│ ├── DeviceList.cs
│ ├── List
│ │ ├── MultipleAlbums.cs
│ │ ├── MultipleTracks.cs
│ │ ├── MultipleArtists.cs
│ │ └── MultiplePlaylists.cs
│ ├── Enum
│ │ ├── ContextType.cs
│ │ ├── RepeatState.cs
│ │ ├── AlbumType.cs
│ │ ├── EnumExtensions.cs
│ │ └── Scopes.cs
│ ├── Copyright.cs
│ ├── Error.cs
│ ├── Followers.cs
│ ├── Exception
│ │ ├── NotFoundException.cs
│ │ ├── ForbiddenException.cs
│ │ ├── BadRequestException.cs
│ │ ├── UserNotPremiumException.cs
│ │ ├── InternalServerErrorException.cs
│ │ ├── InvalidUriException.cs
│ │ ├── ServiceUnavailableException.cs
│ │ ├── TooManyRequestsException.cs
│ │ ├── BadGatewayException.cs
│ │ └── ValidationException.cs
│ ├── Auth
│ │ ├── TokenAuthenticationType.cs
│ │ └── Token.cs
│ ├── PlaylistTracksRef.cs
│ ├── Image.cs
│ ├── PlaylistCreate.cs
│ ├── Search
│ │ ├── SearchResult.cs
│ │ └── ApiSearchResult.cs
│ ├── Uri
│ │ ├── UriType.cs
│ │ └── SpotifyUri.cs
│ ├── PlaylistTrack.cs
│ ├── Context.cs
│ ├── LinkedFrom.cs
│ ├── CurrentlyPlaying.cs
│ ├── SimpleArtist.cs
│ ├── CursorPaging.cs
│ ├── Paging.cs
│ ├── Device.cs
│ ├── WebResponse.cs
│ ├── PublicUser.cs
│ ├── FullArtist.cs
│ ├── SimpleAlbum.cs
│ ├── CurrentlyPlayingContext.cs
│ ├── PrivateUser.cs
│ ├── SimplePlaylist.cs
│ ├── SimpleTrack.cs
│ ├── FullPlaylist.cs
│ ├── FullAlbum.cs
│ └── FullTrack.cs
├── Auth
│ ├── AuthCode
│ │ └── AccessTokenRequest.cs
│ ├── AuthParameters.cs
│ ├── ImplicitGrant.cs
│ └── ClientCredentials.cs
├── Business
│ ├── ApiHelper.cs
│ ├── HelperExtensions.cs
│ ├── Validation.cs
│ └── ApiClient.cs
├── SpotifyWebApi.cs
├── ISpotifyWebApi.cs
└── SpotifyWebApi.csproj
├── Test
├── Api
│ ├── ArtistTest.cs
│ ├── PlaylistTest.cs
│ ├── BaseApiTest.cs
│ └── AlbumTest.cs
├── Auth
│ └── AuthCode
│ │ └── AuthorizationCodeTests.cs
├── Business
│ ├── WebRequestHelperTest.cs
│ └── ValidationTest.cs
├── Test.csproj
├── TestBase.cs
├── TestData.cs
└── Model
│ └── SpotifyUriTest.cs
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
└── workflows
│ ├── push.yml
│ └── release.yml
├── LICENSE.md
├── Solution.ruleset
├── SpotifyWebApi.sln
├── .gitattributes
├── README.md
└── .gitignore
/ExampleConsoleApp/.gitignore:
--------------------------------------------------------------------------------
1 | appsettings.development.json
--------------------------------------------------------------------------------
/SpotifyIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimmerks/SpotifyWebApi/HEAD/SpotifyIcon.png
--------------------------------------------------------------------------------
/ExampleConsoleApp/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Spotify":{
3 | "ClientId": "",
4 | "ClientSecret": "",
5 | "RedirectUri": ""
6 | }
7 | }
--------------------------------------------------------------------------------
/SpotifyWebApi/Api/Follow/IFollowApi.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Api.Follow
2 | {
3 | ///
4 | /// The follow api.
5 | ///
6 | public interface IFollowApi
7 | {
8 | }
9 | }
--------------------------------------------------------------------------------
/Test/Api/ArtistTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace SpotifyWebApiTest.Api
6 | {
7 | class ArtistTest
8 | {
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Api/UserLibrary/IUserLibraryApi.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Api.UserLibrary
2 | {
3 | ///
4 | /// The user library api.
5 | ///
6 | public interface IUserLibraryApi
7 | {
8 | }
9 | }
--------------------------------------------------------------------------------
/SpotifyWebApi/Api/Personalization/IPersonalizationApi.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Api.Personalization
2 | {
3 | ///
4 | /// The personalization api.
5 | ///
6 | public interface IPersonalizationApi
7 | {
8 | }
9 | }
--------------------------------------------------------------------------------
/SpotifyWebApi/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | // Internals only visible for testing purpose.
2 |
3 | using System.Runtime.CompilerServices;
4 | using Fody;
5 |
6 | [assembly: InternalsVisibleTo("SpotifyWebApiTest")]
7 | [assembly: ConfigureAwait(false)]
8 |
--------------------------------------------------------------------------------
/SpotifyWebApi/FodyWeavers.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Cursor.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using Newtonsoft.Json;
4 |
5 | ///
6 | /// The .
7 | ///
8 | public class Cursor
9 | {
10 | ///
11 | /// Gets or sets the after.
12 | ///
13 | [JsonProperty("after")]
14 | public string After { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/DeviceList.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using System.Collections.Generic;
4 | using Newtonsoft.Json;
5 |
6 | ///
7 | /// The device list object.
8 | ///
9 | internal class DeviceList
10 | {
11 | ///
12 | /// A list of devices.
13 | ///
14 | [JsonProperty("devices")]
15 | public List Devices { get; set; }
16 | }
17 | }
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/List/MultipleAlbums.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model.List
2 | {
3 | using System.Collections.Generic;
4 | using Newtonsoft.Json;
5 |
6 | ///
7 | /// The .
8 | ///
9 | public class MultipleAlbums
10 | {
11 | ///
12 | /// Gets or sets the albums.
13 | ///
14 | [JsonProperty("albums")]
15 | public IList Albums { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/List/MultipleTracks.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model.List
2 | {
3 | using System.Collections.Generic;
4 | using Newtonsoft.Json;
5 |
6 | ///
7 | /// The .
8 | ///
9 | public class MultipleTracks
10 | {
11 | ///
12 | /// Gets or sets the tracks.
13 | ///
14 | [JsonProperty("tracks")]
15 | public IList Tracks { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/List/MultipleArtists.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model.List
2 | {
3 | using System.Collections.Generic;
4 | using Newtonsoft.Json;
5 |
6 | ///
7 | /// The .
8 | ///
9 | public class MultipleArtists
10 | {
11 | ///
12 | /// Gets or sets the artists.
13 | ///
14 | [JsonProperty("artists")]
15 | public IList Artists { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Enum/ContextType.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model.Enum
2 | {
3 | ///
4 | /// The .
5 | ///
6 | public enum ContextType
7 | {
8 | ///
9 | /// TODO
10 | ///
11 | Album,
12 |
13 | ///
14 | /// TODO
15 | ///
16 | Artist,
17 |
18 | ///
19 | /// TODO
20 | ///
21 | Playlist,
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/List/MultiplePlaylists.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model.List
2 | {
3 | using System.Collections.Generic;
4 | using Newtonsoft.Json;
5 |
6 | ///
7 | /// The .
8 | ///
9 | public class MultiplePlaylists
10 | {
11 | ///
12 | /// Gets or sets the playlists.
13 | ///
14 | [JsonProperty("playlists")]
15 | public IList Playlists { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Copyright.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using Newtonsoft.Json;
4 |
5 | ///
6 | /// Class Copyright.
7 | ///
8 | public class Copyright
9 | {
10 | ///
11 | /// Gets or sets the text.
12 | ///
13 | [JsonProperty("text")]
14 | public string Text { get; set; }
15 |
16 | ///
17 | /// Gets or sets the type.
18 | ///
19 | [JsonProperty("type")]
20 | public string Type { get; set; }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Enum/RepeatState.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model.Enum
2 | {
3 | ///
4 | /// The .
5 | ///
6 | public enum RepeatState
7 | {
8 | ///
9 | /// Will repeat the current track.
10 | ///
11 | Track,
12 |
13 | ///
14 | /// Will repeat the current context.
15 | ///
16 | Context,
17 |
18 | ///
19 | /// Will turn repeat off.
20 | ///
21 | Off
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Error.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using Newtonsoft.Json;
4 |
5 | ///
6 | /// The class.
7 | ///
8 | public class Error
9 | {
10 | ///
11 | /// Gets or sets the status.
12 | ///
13 | [JsonProperty("status")]
14 | public int Status { get; set; }
15 |
16 | ///
17 | /// Gets or sets the message.
18 | ///
19 | [JsonProperty("message")]
20 | public string Message { get; set; }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Followers.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using Newtonsoft.Json;
4 |
5 | ///
6 | /// The class.
7 | ///
8 | public class Followers
9 | {
10 | ///
11 | /// Gets or sets the href.
12 | ///
13 | [JsonProperty("href")]
14 | public string Href { get; set; }
15 |
16 | ///
17 | /// Gets or sets the total.
18 | ///
19 | [JsonProperty("total")]
20 | public int Total { get; set; }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Test/Auth/AuthCode/AuthorizationCodeTests.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApiTest.Auth.AuthCode
2 | {
3 | using SpotifyWebApi.Auth;
4 | using SpotifyWebApi.Model.Enum;
5 | using Xunit;
6 |
7 | ///
8 | /// The class.
9 | ///
10 | public class AuthorizationCodeTests
11 | {
12 | ///
13 | /// Gets the URL test.
14 | ///
15 | [Fact]
16 | public void GetUrlTest()
17 | {
18 | // TODO: Add test.
19 | Assert.True(true);
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Additional context**
24 | ```csharp
25 | // The code you used while getting this bug
26 | ```
27 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Exception/NotFoundException.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model.Exception
2 | {
3 | using System;
4 |
5 | ///
6 | /// The .
7 | ///
8 | public class NotFoundException : Exception
9 | {
10 | ///
11 | /// Initializes a new instance of the class.
12 | ///
13 | /// The message that describes the error.
14 | public NotFoundException(string message)
15 | : base(message)
16 | {
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Exception/ForbiddenException.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model.Exception
2 | {
3 | using System;
4 |
5 | ///
6 | /// The server understood the request, but is refusing to fulfill it.
7 | ///
8 | public class ForbiddenException : Exception
9 | {
10 | ///
11 | /// Initializes a new instance of the class.
12 | ///
13 | /// The exception message.
14 | public ForbiddenException(string message)
15 | : base(message)
16 | {
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Exception/BadRequestException.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model.Exception
2 | {
3 | using System;
4 |
5 | ///
6 | /// The request could not be understood by the server due to malformed syntax.
7 | ///
8 | public class BadRequestException : Exception
9 | {
10 | ///
11 | /// Initializes a new instance of the class.
12 | ///
13 | /// The exception message.
14 | public BadRequestException(string message)
15 | : base(message)
16 | {
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Exception/UserNotPremiumException.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model.Exception
2 | {
3 | using System;
4 |
5 | ///
6 | /// The .
7 | ///
8 | public class UserNotPremiumException : Exception
9 | {
10 | ///
11 | /// Initializes a new instance of the class.
12 | ///
13 | /// The message that describes the error.
14 | public UserNotPremiumException(string message)
15 | : base(message)
16 | {
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Exception/InternalServerErrorException.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model.Exception
2 | {
3 | using System;
4 |
5 | ///
6 | /// An error you should (according to Spotify) never recieve.
7 | ///
8 | public class InternalServerErrorException : Exception
9 | {
10 | ///
11 | /// Initializes a new instance of the class.
12 | ///
13 | /// The exception message.
14 | public InternalServerErrorException(string message)
15 | : base(message)
16 | {
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Auth/TokenAuthenticationType.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model.Auth
2 | {
3 | ///
4 | /// Enum defining token types.
5 | ///
6 | public enum TokenAuthenticationType
7 | {
8 | ///
9 | /// Token generated using Authorization Code.
10 | ///
11 | AuthorizationCode = 0,
12 |
13 | ///
14 | /// Token generated using Client Credentials.
15 | ///
16 | ClientCredentials = 1,
17 |
18 | ///
19 | /// Token generated using Implicit Grant.
20 | ///
21 | ImplicitGrant = 2
22 | }
23 | }
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Exception/InvalidUriException.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model.Exception
2 | {
3 | using System;
4 |
5 | ///
6 | /// Exception that gets thrown when creating a spotify uri from a non valid string.
7 | ///
8 | public class InvalidUriException : Exception
9 | {
10 | ///
11 | /// Initializes a new instance of the class.
12 | ///
13 | /// The message that describes the error.
14 | public InvalidUriException(string message)
15 | : base(message)
16 | {
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Enum/AlbumType.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model.Enum
2 | {
3 | using System;
4 |
5 | ///
6 | /// Enum AlbumType
7 | ///
8 | [Flags]
9 | public enum AlbumType
10 | {
11 | ///
12 | /// The album
13 | ///
14 | Album = 1,
15 |
16 | ///
17 | /// The single
18 | ///
19 | Single = 2,
20 |
21 | ///
22 | /// The appears on
23 | ///
24 | AppearsOn = 4,
25 |
26 | ///
27 | /// The compilation
28 | ///
29 | Compilation = 8
30 | }
31 | }
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/PlaylistTracksRef.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using Newtonsoft.Json;
4 |
5 | ///
6 | /// The class.
7 | ///
8 | public class PlaylistTracksRef
9 | {
10 | ///
11 | /// A link to the Web API endpoint where full details of the playlist's tracks can be retrieved.
12 | ///
13 | [JsonProperty("href")]
14 | public string Href { get; set; }
15 |
16 | ///
17 | /// Number of tracks in the playlist.
18 | ///
19 | [JsonProperty("total")]
20 | public int? Total { get; set; }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: feature-request
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Exception/ServiceUnavailableException.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model.Exception
2 | {
3 | using System;
4 |
5 | ///
6 | /// The server is currently unable to handle the request due to a temporary condition which will be alleviated after some delay.
7 | ///
8 | public class ServiceUnavailableException : Exception
9 | {
10 | ///
11 | /// Initializes a new instance of the class.
12 | ///
13 | /// The exception message.
14 | public ServiceUnavailableException(string message)
15 | : base(message)
16 | {
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Exception/TooManyRequestsException.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model.Exception
2 | {
3 | using System;
4 |
5 | ///
6 | /// Rate limiting has been applied.
7 | /// See here.
8 | ///
9 | public class TooManyRequestsException : Exception
10 | {
11 | ///
12 | /// Initializes a new instance of the class.
13 | ///
14 | /// The exception message.
15 | public TooManyRequestsException(string message)
16 | : base(message)
17 | {
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Exception/BadGatewayException.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model.Exception
2 | {
3 | using System;
4 | using Newtonsoft.Json;
5 | using Newtonsoft.Json.Converters;
6 |
7 | ///
8 | /// The server was acting as a gateway or proxy and received an invalid response from the upstream server.
9 | ///
10 | public class BadGatewayException : Exception
11 | {
12 | ///
13 | /// Initializes a new instance of the class.
14 | ///
15 | /// The exception message.
16 | public BadGatewayException(string message)
17 | : base(message)
18 | {
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Image.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using Newtonsoft.Json;
4 |
5 | ///
6 | /// The class.
7 | ///
8 | public class Image
9 | {
10 | ///
11 | /// Gets or sets the height.
12 | ///
13 | [JsonProperty("height")]
14 | public int? Height { get; set; }
15 |
16 | ///
17 | /// Gets or sets the URL.
18 | ///
19 | [JsonProperty("url")]
20 | public string Url { get; set; }
21 |
22 | ///
23 | /// Gets or sets the width.
24 | ///
25 | [JsonProperty("width")]
26 | public int? Width { get; set; }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Exception/ValidationException.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) companyPlaceholder. All rights reserved.
3 | //
4 |
5 | namespace SpotifyWebApi.Model.Exception
6 | {
7 | using System;
8 |
9 | ///
10 | /// The .
11 | ///
12 | public class ValidationException : Exception
13 | {
14 | ///
15 | /// Initializes a new instance of the class.
16 | ///
17 | /// The validation message.
18 | public ValidationException(string message)
19 | : base(message)
20 | {
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/PlaylistCreate.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using Newtonsoft.Json;
4 |
5 | ///
6 | /// The playlist create object
7 | ///
8 | public class PlaylistCreate
9 | {
10 | ///
11 | /// The name of the playlist
12 | ///
13 | [JsonProperty("name")]
14 | public string Name { get; set; }
15 |
16 | ///
17 | /// The playlist description.
18 | ///
19 | [JsonProperty("description")]
20 | public string Description { get; set; }
21 |
22 | ///
23 | /// The playlist visibility.
24 | ///
25 | [JsonProperty("public")]
26 | public bool Public { get; set; }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Auth/AuthCode/AccessTokenRequest.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Auth.AuthCode
2 | {
3 | using Newtonsoft.Json;
4 |
5 | ///
6 | /// The class.
7 | ///
8 | internal class AccessTokenRequest
9 | {
10 | ///
11 | /// The grant type.
12 | ///
13 | [JsonProperty("grant_type")]
14 | public string GrantType { get; set; }
15 |
16 | ///
17 | /// The code.
18 | ///
19 | [JsonProperty("code")]
20 | public string Code { get; set; }
21 |
22 | ///
23 | /// The redirect uri.
24 | ///
25 | [JsonProperty("redirect_uri")]
26 | public string RedirectUri { get; set; }
27 | }
28 | }
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Search/SearchResult.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model.Search
2 | {
3 | using System.Collections.Generic;
4 |
5 | ///
6 | /// A search result of a search query.
7 | ///
8 | public class SearchResult
9 | {
10 | ///
11 | /// The albums.
12 | ///
13 | public List Albums { get; set; }
14 |
15 | ///
16 | /// The artists.
17 | ///
18 | public List Artists { get; set; }
19 |
20 | ///
21 | /// The tracks.
22 | ///
23 | public List Tracks { get; set; }
24 |
25 | ///
26 | /// The playlists.
27 | ///
28 | public List Playlists { get; set; }
29 | }
30 | }
--------------------------------------------------------------------------------
/.github/workflows/push.yml:
--------------------------------------------------------------------------------
1 | name: Push
2 |
3 | on:
4 | push:
5 | pull_request:
6 |
7 | jobs:
8 | build:
9 | name: Build
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 | - uses: actions/checkout@v2
14 | - name: Setup .NET Core
15 | uses: actions/setup-dotnet@v1
16 | with:
17 | dotnet-version: 3.1.101
18 |
19 | - name: Restore packages
20 | uses: actions/cache@v1
21 | with:
22 | path: ~/.nuget/packages
23 | key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
24 | restore-keys: |
25 | ${{ runner.os }}-nuget-
26 |
27 | - name: Restore packages
28 | run: dotnet restore --use-lock-file --locked-mode
29 |
30 | - name: Build with dotnet
31 | run: dotnet build --configuration Release
32 |
33 | - name: Test with dotnet
34 | run: dotnet test --configuration Release
35 |
--------------------------------------------------------------------------------
/Test/Business/WebRequestHelperTest.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApiTest.Business
2 | {
3 | using System;
4 | using SpotifyWebApi.Business;
5 | using SpotifyWebApi.Model;
6 | using SpotifyWebApi.Model.Auth;
7 | using Xunit;
8 |
9 | ///
10 | /// The .
11 | ///
12 | public class WebRequestHelperTest
13 | {
14 |
15 | ///
16 | /// TODO
17 | ///
18 | [Fact]
19 | public void TestGet()
20 | {
21 | // TODO: Add test.
22 | Assert.True(true);
23 | }
24 |
25 | ///
26 | /// TODO
27 | ///
28 | [Fact]
29 | public void TestCreateUpdateDeletePlaylist()
30 | {
31 | // TODO: Add test.
32 | Assert.True(true);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/ExampleConsoleApp/ExampleConsoleApp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp3.1
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | Always
24 |
25 |
26 | Always
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Uri/UriType.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model.Uri
2 | {
3 | using System.Runtime.Serialization;
4 |
5 | ///
6 | /// Enum UriType
7 | ///
8 | [DataContract]
9 | public enum UriType
10 | {
11 | ///
12 | /// The user.
13 | ///
14 | [EnumMember]
15 | User,
16 |
17 | ///
18 | /// The track.
19 | ///
20 | [EnumMember]
21 | Track,
22 |
23 | ///
24 | /// The artist.
25 | ///
26 | [EnumMember]
27 | Artist,
28 |
29 | ///
30 | /// The album.
31 | ///
32 | [EnumMember]
33 | Album,
34 |
35 | ///
36 | /// The playlist.
37 | ///
38 | [EnumMember]
39 | Playlist,
40 |
41 | ///
42 | /// A local uri.
43 | ///
44 | [EnumMember]
45 | Local,
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/PlaylistTrack.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using System;
4 | using Newtonsoft.Json;
5 |
6 | ///
7 | /// The class.
8 | ///
9 | public class PlaylistTrack
10 | {
11 | ///
12 | /// Gets or sets the added at.
13 | ///
14 | [JsonProperty("added_at")]
15 | public DateTime AddedAt { get; set; }
16 |
17 | ///
18 | /// Gets or sets the added by.
19 | ///
20 | [JsonProperty("added_by")]
21 | public PublicUser AddedBy { get; set; }
22 |
23 | ///
24 | /// Gets or sets a value indicating whether this instance is local.
25 | ///
26 | [JsonProperty("is_local")]
27 | public bool IsLocal { get; set; }
28 |
29 | ///
30 | /// Gets or sets the track.
31 | ///
32 | [JsonProperty("track")]
33 | public FullTrack Track { get; set; }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Pim Merks
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.
--------------------------------------------------------------------------------
/Test/Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 | false
6 | SpotifyWebApiTest
7 | SpotifyWebApiTest
8 | ..\Solution.ruleset
9 | bin\Debug\$(TargetFramework)\SpotifyWebApiTest.xml
10 |
11 |
12 |
13 |
14 | NU5105
15 | true
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/ExampleConsoleApp/Startup.cs:
--------------------------------------------------------------------------------
1 | namespace ExampleConsoleApp
2 | {
3 | using System.IO;
4 | using System.Threading.Tasks;
5 | using Microsoft.Extensions.Configuration;
6 | using Microsoft.Extensions.DependencyInjection;
7 |
8 | class Startup
9 | {
10 | static async Task Main(string[] args)
11 | {
12 | var serviceCollection = new ServiceCollection();
13 |
14 | var builder = new ConfigurationBuilder()
15 | .SetBasePath(Directory.GetCurrentDirectory())
16 | .AddJsonFile("appsettings.json", false)
17 | .AddJsonFile("appsettings.development.json", true);
18 |
19 | IConfiguration configuration = builder.Build();
20 |
21 | serviceCollection.AddScoped(_ => configuration);
22 | serviceCollection.AddScoped();
23 | serviceCollection.AddScoped();
24 |
25 | var serviceProvider = serviceCollection.BuildServiceProvider();
26 |
27 | var p = serviceProvider.GetRequiredService();
28 | await p.Run();
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/Test/TestBase.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApiTest
2 | {
3 | using SpotifyWebApi;
4 | using Xunit;
5 | using Xunit.Abstractions;
6 |
7 | ///
8 | /// The .
9 | ///
10 | public class TestBase : IClassFixture
11 | {
12 | ///
13 | /// An instance of test data.
14 | ///
15 | protected readonly TestData TestData;
16 |
17 | ///
18 | /// An instance of to provide logging while testing.
19 | ///
20 | protected readonly ITestOutputHelper Output;
21 |
22 | ///
23 | /// Gets the api from the test data.
24 | ///
25 | protected ISpotifyWebApi Api { get; }
26 |
27 | ///
28 | /// The base test class.
29 | ///
30 | public TestBase(TestData testData, ITestOutputHelper output)
31 | {
32 | this.TestData = testData;
33 | this.Output = output;
34 | this.Api = new SpotifyWebApi(this.TestData.ClientCredentialsToken);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Enum/EnumExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model.Enum
2 | {
3 | using System;
4 |
5 | ///
6 | /// The .
7 | ///
8 | public static class EnumExtensions
9 | {
10 | ///
11 | /// Ases the string.
12 | ///
13 | /// Type of the album.
14 | /// System.String.
15 | /// albumType - null
16 | public static string AsString(this AlbumType albumType)
17 | {
18 | switch (albumType)
19 | {
20 | case AlbumType.Album:
21 | return "album";
22 | case AlbumType.Single:
23 | return "single";
24 | case AlbumType.AppearsOn:
25 | return "appears_on";
26 | case AlbumType.Compilation:
27 | return "compilation";
28 | default:
29 | throw new ArgumentOutOfRangeException(nameof(albumType), albumType, null);
30 | }
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Search/ApiSearchResult.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model.Search
2 | {
3 | using Newtonsoft.Json;
4 |
5 | ///
6 | /// The internal .
7 | ///
8 | public class ApiSearchResult
9 | {
10 | ///
11 | /// The albums.
12 | ///
13 | [JsonProperty("albums", NullValueHandling = NullValueHandling.Ignore)]
14 | public Paging Albums { get; set; }
15 |
16 | ///
17 | /// The artists.
18 | ///
19 | [JsonProperty("artists", NullValueHandling = NullValueHandling.Ignore)]
20 | public Paging Artists { get; set; }
21 |
22 | ///
23 | /// The tracks.
24 | ///
25 | [JsonProperty("tracks", NullValueHandling = NullValueHandling.Ignore)]
26 | public Paging Tracks { get; set; }
27 |
28 | ///
29 | /// The playlists.
30 | ///
31 | [JsonProperty("playlists", NullValueHandling = NullValueHandling.Ignore)]
32 | public Paging Playlists { get; set; }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Context.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using System.Collections.Generic;
4 | using Enum;
5 | using Newtonsoft.Json;
6 |
7 | ///
8 | /// The .
9 | ///
10 | public class Context
11 | {
12 | ///
13 | /// Gets or sets the uri of the context.
14 | ///
15 | [JsonProperty("uri")]
16 | public string Uri { get; set; }
17 |
18 | ///
19 | /// Gets or sets the href of the context, or null if not available.
20 | ///
21 | [JsonProperty("href")]
22 | public string Href { get; set; }
23 |
24 | ///
25 | /// Gets or sets the external urls of the context, or null if not available.
26 | ///
27 | [JsonProperty("external_urls")]
28 | public Dictionary ExternalUrls { get; set; }
29 |
30 | ///
31 | /// Gets or sets the object type of the item's context. Can be one of "album", "artist" or "playlist".
32 | ///
33 | [JsonProperty("type")]
34 | public ContextType Type { get; set; }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Auth/AuthParameters.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Auth
2 | {
3 | using Model.Enum;
4 |
5 | ///
6 | /// The .
7 | ///
8 | public class AuthParameters
9 | {
10 | ///
11 | /// Gets or sets the authentication client id.
12 | ///
13 | public string ClientId { get; set; }
14 |
15 | ///
16 | /// Gets or sets the authentication client secret.
17 | /// Note that this is only used for the flow.
18 | ///
19 | public string ClientSecret { get; set; }
20 |
21 | ///
22 | /// Gets or sets the authentication redirect uri.
23 | ///
24 | public string RedirectUri { get; set; }
25 |
26 | ///
27 | /// Gets or sets a value indicating wheter to show the login screen every time the user is requested to login.
28 | ///
29 | public bool ShowDialog { get; set; }
30 |
31 | ///
32 | /// Gets or sets the authentication scopes.
33 | ///
34 | public string Scopes { get; set; }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/LinkedFrom.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using System.Collections.Generic;
4 | using Newtonsoft.Json;
5 | using Uri;
6 |
7 | ///
8 | /// The class.
9 | ///
10 | public class LinkedFrom
11 | {
12 | ///
13 | /// Gets or sets the external urls.
14 | ///
15 | [JsonProperty("external_urls")]
16 | public Dictionary ExternalUrls { get; set; }
17 |
18 | ///
19 | /// Gets or sets the href.
20 | ///
21 | [JsonProperty("href")]
22 | public string Href { get; set; }
23 |
24 | ///
25 | /// Gets or sets the identifier.
26 | ///
27 | [JsonProperty("id")]
28 | public string Id { get; set; }
29 |
30 | ///
31 | /// Gets or sets the type.
32 | ///
33 | [JsonProperty("type")]
34 | public string Type { get; set; }
35 |
36 | ///
37 | /// Gets or sets the URI.
38 | ///
39 | [JsonProperty("uri")]
40 | public SpotifyUri Uri { get; set; }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/CurrentlyPlaying.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using Newtonsoft.Json;
4 |
5 | ///
6 | /// The .
7 | ///
8 | public class CurrentlyPlaying
9 | {
10 | ///
11 | /// Gets or sets a Context Object. Can be null.
12 | ///
13 | [JsonProperty("Context")]
14 | public Context Context { get; set; }
15 |
16 | ///
17 | /// Gets or sets unix Millisecond Timestamp when data was fetched
18 | ///
19 | [JsonProperty("timestamp")]
20 | public long Timestamp { get; set; }
21 |
22 | ///
23 | /// Gets or sets progress into the currently playing track. Can be null.
24 | ///
25 | [JsonProperty("progress_ms")]
26 | public int ProgressMs { get; set; }
27 |
28 | ///
29 | /// Gets or sets if something is currently playing.
30 | ///
31 | [JsonProperty("is_playing")]
32 | public bool IsPlaying { get; set; }
33 |
34 | ///
35 | /// Gets or sets the currently playing track. Can be null.
36 | ///
37 | [JsonProperty("item")]
38 | public FullTrack Item { get; set; }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/SimpleArtist.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using System.Collections.Generic;
4 | using Newtonsoft.Json;
5 | using Uri;
6 |
7 | ///
8 | /// The class.
9 | ///
10 | public class SimpleArtist
11 | {
12 | ///
13 | /// Gets or sets the external urls.
14 | ///
15 | [JsonProperty("external_urls")]
16 | public Dictionary ExternalUrls { get; set; }
17 |
18 | ///
19 | /// Gets or sets the href.
20 | ///
21 | [JsonProperty("href")]
22 | public string Href { get; set; }
23 |
24 | ///
25 | /// Gets or sets the identifier.
26 | ///
27 | [JsonProperty("id")]
28 | public string Id { get; set; }
29 |
30 | ///
31 | /// Gets or sets the name.
32 | ///
33 | [JsonProperty("name")]
34 | public string Name { get; set; }
35 |
36 | ///
37 | /// Gets or sets the type.
38 | ///
39 | [JsonProperty("type")]
40 | public string Type { get; set; }
41 |
42 | ///
43 | /// Gets or sets the URI.
44 | ///
45 | [JsonProperty("uri")]
46 | public SpotifyUri Uri { get; set; }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Api/UserProfile/IUserProfileApi.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Api.UserProfile
2 | {
3 | using System.Threading.Tasks;
4 | using Model;
5 | using Model.Enum;
6 | using Model.Uri;
7 |
8 | ///
9 | /// The user profile api.
10 | ///
11 | public interface IUserProfileApi
12 | {
13 | ///
14 | /// Get detailed profile information about the current user (including the current user’s username).
15 | ///
16 | /// A object representing the current user.
17 | ///
18 | /// A valid access token from the Spotify Accounts service: see the Web API Authorization Guide for details.
19 | /// The access token must have been issued on behalf of the current user.
20 | /// Reading the user’s email address requires the scope;
21 | /// reading country and product subscription level requires the scope.
22 | ///
23 | Task GetMe();
24 |
25 | ///
26 | /// Get public profile information about a Spotify user.
27 | ///
28 | /// The user’s Spotify user ID.
29 | /// The requested user.
30 | Task GetUser(SpotifyUri userUri);
31 | }
32 | }
--------------------------------------------------------------------------------
/SpotifyWebApi/Api/Search/ISearchApi.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Api.Search
2 | {
3 | using System.Threading.Tasks;
4 | using Model.Enum;
5 | using Model.Search;
6 |
7 | ///
8 | /// The search api.
9 | ///
10 | public interface ISearchApi
11 | {
12 | ///
13 | /// Get Spotify catalog information about artists, albums, tracks or playlists that match a keyword string.
14 | /// Note: There is only support for 20 results per category.
15 | /// TODO: Add support for more than 20 results per category.
16 | ///
17 | /// The search query's keywords (and optional field filters and operators).
18 | /// For more info see: https://developer.spotify.com/web-api/search-item/
19 | /// A list of item types to search across.
20 | /// Optional. An ISO 3166-1 alpha-2 country code.
21 | /// Optional. The starting offset of the search.
22 | /// The maximum results to return per category.
23 | /// A list of s.
24 | Task Search(
25 | string query,
26 | string searchType,
27 | string market = "",
28 | int offset = 0,
29 | int resultLimit = 20);
30 | }
31 | }
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/CursorPaging.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using System.Collections.Generic;
4 | using Newtonsoft.Json;
5 |
6 | ///
7 | /// The class.
8 | ///
9 | /// The type of
10 | public class CursorPaging
11 | {
12 | ///
13 | /// Gets or sets the href.
14 | ///
15 | [JsonProperty("href")]
16 | public string Href { get; set; }
17 |
18 | ///
19 | /// Gets or sets the items.
20 | ///
21 | [JsonProperty("items")]
22 | public List Items { get; set; }
23 |
24 | ///
25 | /// Gets or sets the limit.
26 | ///
27 | [JsonProperty("limit")]
28 | public int Limit { get; set; }
29 |
30 | ///
31 | /// Gets or sets the next.
32 | ///
33 | [JsonProperty("next")]
34 | public string Next { get; set; }
35 |
36 | ///
37 | /// Gets or sets the cursors.
38 | ///
39 | [JsonProperty("cursors")]
40 | public Cursor Cursors { get; set; }
41 |
42 | ///
43 | /// Gets or sets the total.
44 | ///
45 | [JsonProperty("total")]
46 | public int Total { get; set; }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Api/Track/ITrackApi.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Api.Track
2 | {
3 | using System.Collections;
4 | using System.Collections.Generic;
5 | using System.Threading.Tasks;
6 | using Model;
7 | using Model.Uri;
8 |
9 | ///
10 | /// The track api.
11 | ///
12 | public interface ITrackApi
13 | {
14 | ///
15 | /// Get Spotify catalog information for a single track identified by its
16 | ///
17 | /// The for the track.
18 | /// Optional. An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking.
19 | /// A object.
20 | Task GetTrack(SpotifyUri uri, string market = null);
21 |
22 | ///
23 | /// Get Spotify catalog information for multiple tracks based on their s.
24 | ///
25 | /// A list of s. Note a maximum of 50 tracks is allowed.
26 | /// Optional. An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking.
27 | /// A list of objects.
28 | Task> GetTracks(IList uris, string market = null);
29 | }
30 | }
--------------------------------------------------------------------------------
/Solution.ruleset:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Business/ApiHelper.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Business
2 | {
3 | using System;
4 | using System.Net;
5 | using Model.Auth;
6 |
7 | ///
8 | /// The .
9 | ///
10 | internal static class ApiHelper
11 | {
12 | ///
13 | /// The base uri for all api requests.
14 | ///
15 | public const string BaseUri = "https://api.spotify.com/v1";
16 |
17 | ///
18 | /// Creates a new from the specified .
19 | ///
20 | /// The uri of the request.
21 | /// A new from the specified uri.
22 | public static HttpWebRequest CreateRequest(Uri uri)
23 | {
24 | var request = WebRequest.CreateHttp(uri);
25 | request.ContentType = "application/x-www-form-urlencoded";
26 | return request;
27 | }
28 |
29 | ///
30 | /// Encodes a string to Base64.
31 | ///
32 | /// The string to encode.
33 | /// The base 64 encoded string.
34 | public static string Base64Encode(string plainText)
35 | {
36 | var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
37 | return System.Convert.ToBase64String(plainTextBytes);
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Api/UserProfile/UserProfileApi.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Api.UserProfile
2 | {
3 | using System.Threading.Tasks;
4 | using Business;
5 | using Model;
6 | using Model.Auth;
7 | using Model.Uri;
8 |
9 | ///
10 | ///
11 | /// The .
12 | ///
13 | public class UserProfileApi : BaseApi, IUserProfileApi
14 | {
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | /// A valid .
19 | public UserProfileApi(Token token)
20 | : base(token)
21 | {
22 | }
23 |
24 | ///
25 | public async Task GetMe()
26 | {
27 | var r = await ApiClient.GetAsync(
28 | MakeUri("me"), this.Token);
29 |
30 | if (r.Response is PrivateUser res)
31 | {
32 | return res;
33 | }
34 | return new PrivateUser();
35 | }
36 |
37 | ///
38 | public async Task GetUser(SpotifyUri userUri)
39 | {
40 | var r = await ApiClient.GetAsync(
41 | MakeUri($"users/{userUri.Id}"), this.Token);
42 |
43 | if (r.Response is PublicUser res)
44 | {
45 | return res;
46 | }
47 | return new PublicUser();
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | push:
5 | tags:
6 | - v[0-9]+.[0-9]+.[0-9]+
7 |
8 | jobs:
9 | release:
10 | name: Release ${{ github.ref }}
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - uses: actions/checkout@v2
15 | - name: Setup .NET Core
16 | uses: actions/setup-dotnet@v1
17 | with:
18 | dotnet-version: 3.1.101
19 |
20 | - name: Restore cache
21 | uses: actions/cache@v1
22 | with:
23 | path: ~/.nuget/packages
24 | key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
25 | restore-keys: |
26 | ${{ runner.os }}-nuget-
27 |
28 | - name: Restore packages
29 | run: dotnet restore --use-lock-file --locked-mode
30 |
31 | - name: Build with dotnet
32 | run: dotnet build --configuration Release
33 |
34 | - name: Test with dotnet
35 | run: dotnet test --configuration Release
36 |
37 | - name: Process version of the tag
38 | id: version
39 | uses: ncipollo/semantic-version-action@v1
40 |
41 | - name: Pack package
42 | env:
43 | version: ${{ steps.version.outputs.major }}.${{ steps.version.outputs.minor }}.${{ steps.version.outputs.patch }}
44 | run: dotnet pack --configuration Release --output build --include-symbols --include-source -p:Version=$version -p:SymbolPackageFormat=snupkg
45 |
46 | - name: Publish package
47 | env:
48 | api_key: ${{ secrets.NUGET_API_KEY }}
49 | source: ${{ secrets.NUGET_URI }}
50 | run: dotnet nuget push build/*.nupkg --source $source --api-key $api_key
51 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Paging.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using System.Collections.Generic;
4 | using Newtonsoft.Json;
5 |
6 | ///
7 | /// The class.
8 | ///
9 | /// The type of
10 | public class Paging
11 | {
12 | ///
13 | /// Gets or sets the href.
14 | ///
15 | [JsonProperty("href")]
16 | public string Href { get; set; }
17 |
18 | ///
19 | /// Gets or sets the items.
20 | ///
21 | [JsonProperty("items")]
22 | public List Items { get; set; }
23 |
24 | ///
25 | /// Gets or sets the limit.
26 | ///
27 | [JsonProperty("limit")]
28 | public int Limit { get; set; }
29 |
30 | ///
31 | /// Gets or sets the next.
32 | ///
33 | [JsonProperty("next")]
34 | public string Next { get; set; }
35 |
36 | ///
37 | /// Gets or sets the offset.
38 | ///
39 | [JsonProperty("offset")]
40 | public int Offset { get; set; }
41 |
42 | ///
43 | /// Gets or sets the previous.
44 | ///
45 | [JsonProperty("previous")]
46 | public string Previous { get; set; }
47 |
48 | ///
49 | /// Gets or sets the total.
50 | ///
51 | [JsonProperty("total")]
52 | public int Total { get; set; }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Device.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using Newtonsoft.Json;
4 |
5 | ///
6 | /// The .
7 | ///
8 | public class Device
9 | {
10 | ///
11 | /// Gets or sets the device ID. This may be null.
12 | ///
13 | [JsonProperty("id")]
14 | public string Id { get; set; }
15 |
16 | ///
17 | /// Gets or sets a value indicating if this device is the currently active device.
18 | ///
19 | [JsonProperty("is_active")]
20 | public bool IsActive { get; set; }
21 |
22 | ///
23 | /// Gets or sets a value indicating whether controlling this device is restricted.
24 | /// At present if this is "true" then no Web API commands will be accepted by this device.
25 | ///
26 | [JsonProperty("is_restricted")]
27 | public bool IsRestricted { get; set; }
28 |
29 | ///
30 | /// Gets or sets the name of the device.
31 | ///
32 | [JsonProperty("name")]
33 | public string Name { get; set; }
34 |
35 | ///
36 | /// Gets or sets device type, such as "Computer", "Smartphone" or "Speaker".
37 | ///
38 | [JsonProperty("type")]
39 | public string Type { get; set; }
40 |
41 | ///
42 | /// Gets or sets the current volume in percent. This may be null.
43 | ///
44 | [JsonProperty("volume_percent")]
45 | public int? VolumePercent { get; set; }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/WebResponse.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using System;
4 | using System.Net;
5 |
6 | ///
7 | /// The .
8 | ///
9 | public class WebResponse
10 | {
11 | ///
12 | /// Initializes a new instance of the class.
13 | ///
14 | /// The response.
15 | /// The status code.
16 | private WebResponse(object response, HttpStatusCode statusCode)
17 | {
18 | this.Response = response;
19 | this.StatusCode = statusCode;
20 | }
21 |
22 | ///
23 | /// The response.
24 | ///
25 | public object Response { get; set; }
26 |
27 | ///
28 | /// Gets the type of the response.
29 | ///
30 | public Type Type => this.Response.GetType();
31 |
32 | ///
33 | /// Gets or sets the status code of the html request.
34 | ///
35 | public HttpStatusCode StatusCode { get; set; }
36 |
37 | ///
38 | /// Makes the specified response.
39 | ///
40 | /// The response.
41 | /// The status code.
42 | /// The new webresponse.
43 | public static WebResponse Make(object response, HttpStatusCode statusCode)
44 | {
45 | return new WebResponse(response, statusCode);
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/PublicUser.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using System.Collections.Generic;
4 | using Newtonsoft.Json;
5 | using Uri;
6 |
7 | ///
8 | /// The class.
9 | ///
10 | public class PublicUser
11 | {
12 | ///
13 | /// Gets or sets the display name.
14 | ///
15 | [JsonProperty("display_name")]
16 | public string DisplayName { get; set; }
17 |
18 | ///
19 | /// Gets or sets the external urls.
20 | ///
21 | [JsonProperty("external_urls")]
22 | public Dictionary ExternalUrls { get; set; }
23 |
24 | ///
25 | /// Gets or sets the followers.
26 | ///
27 | [JsonProperty("followers")]
28 | public Followers Followers { get; set; }
29 |
30 | ///
31 | /// Gets or sets the href.
32 | ///
33 | [JsonProperty("href")]
34 | public string Href { get; set; }
35 |
36 | ///
37 | /// Gets or sets the identifier.
38 | ///
39 | [JsonProperty("id")]
40 | public string Id { get; set; }
41 |
42 | ///
43 | /// Gets or sets the images.
44 | ///
45 | [JsonProperty("images")]
46 | public List Images { get; set; }
47 |
48 | ///
49 | /// Gets or sets the type.
50 | ///
51 | [JsonProperty("type")]
52 | public string Type { get; set; }
53 |
54 | ///
55 | /// Gets or sets the URI.
56 | ///
57 | [JsonProperty("uri")]
58 | public SpotifyUri Uri { get; set; }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Api/Browse/BrowseApi.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Api.Browse
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using global::SpotifyWebApi.Business;
8 | using Model;
9 | using Model.Auth;
10 |
11 | ///
12 | ///
13 | /// The .
14 | ///
15 | public class BrowseApi : BaseApi, IBrowseApi
16 | {
17 | ///
18 | /// Initializes a new instance of the class.
19 | ///
20 | /// A valid .
21 | public BrowseApi(Token token)
22 | : base(token)
23 | {
24 | }
25 |
26 | ///
27 | public async Task<(string Message, IList Playlists)> GetFeaturedPlaylists(
28 | string locale,
29 | string country,
30 | DateTime? timeStamp,
31 | int maxResults,
32 | int offset)
33 | {
34 | var r = await ApiClient.GetAsync(
35 | MakeUri(
36 | $"browse/featured-playlists",
37 | ("locale", locale),
38 | ("country", country),
39 | ("timestamp", $"{timeStamp:O}")),
40 | this.Token);
41 |
42 | if (r.Response is FeaturedPlaylistResponse res)
43 | {
44 | return (res.Message, res.Playlists);
45 | }
46 | return (string.Empty, new List());
47 | }
48 |
49 | private class FeaturedPlaylistResponse
50 | {
51 | public string Message { get; set; }
52 |
53 | public List Playlists { get; set; }
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Api/Album/IAlbumApi.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Api.Album
2 | {
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 | using Model;
6 | using Model.Uri;
7 |
8 | ///
9 | /// The album api.
10 | ///
11 | public interface IAlbumApi
12 | {
13 | ///
14 | /// Get Spotify catalog information for a single album.
15 | ///
16 | /// The for the album
17 | /// Optional. An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking.
18 | /// The retrieved .
19 | Task GetAlbum(SpotifyUri albumUri, string market = "");
20 |
21 | ///
22 | /// Get Spotify catalog information for multiple albums identified by their Spotify URIs.
23 | ///
24 | /// A list of the Spotify URIs for the albums. Maximum: 20 IDs.
25 | /// Optional. An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking.
26 | /// The retrieved s.
27 | Task> GetAlbums(IList albumUris, string market = "");
28 |
29 | ///
30 | /// Get Spotify catalog information about an album’s tracks. Optional parameters can be used to limit the number of tracks returned.
31 | ///
32 | /// The for the album
33 | /// Optional. An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking.
34 | /// The retrieved tracks.
35 | Task> GetAlbumTracks(SpotifyUri albumUri, string market = "");
36 | }
37 | }
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/FullArtist.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using System.Collections.Generic;
4 | using Newtonsoft.Json;
5 | using Uri;
6 |
7 | ///
8 | /// The class.
9 | ///
10 | public class FullArtist
11 | {
12 | ///
13 | /// Gets or sets the external urls.
14 | ///
15 | [JsonProperty("external_urls")]
16 | public Dictionary ExternalUrls { get; set; }
17 |
18 | ///
19 | /// Gets or sets the followers.
20 | ///
21 | [JsonProperty("followers")]
22 | public Followers Followers { get; set; }
23 |
24 | ///
25 | /// Gets or sets the genres.
26 | ///
27 | [JsonProperty("genres")]
28 | public List Genres { get; set; }
29 |
30 | ///
31 | /// Gets or sets the href.
32 | ///
33 | [JsonProperty("href")]
34 | public string Href { get; set; }
35 |
36 | ///
37 | /// Gets or sets the identifier.
38 | ///
39 | [JsonProperty("id")]
40 | public string Id { get; set; }
41 |
42 | ///
43 | /// Gets or sets the images.
44 | ///
45 | [JsonProperty("images")]
46 | public List Images { get; set; }
47 |
48 | ///
49 | /// Gets or sets the name.
50 | ///
51 | [JsonProperty("name")]
52 | public string Name { get; set; }
53 |
54 | ///
55 | /// Gets or sets the popularity.
56 | ///
57 | [JsonProperty("popularity")]
58 | public int Popularity { get; set; }
59 |
60 | ///
61 | /// Gets or sets the type.
62 | ///
63 | [JsonProperty("type")]
64 | public string Type { get; set; }
65 |
66 | ///
67 | /// Gets or sets the URI.
68 | ///
69 | [JsonProperty("uri")]
70 | public SpotifyUri Uri { get; set; }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Api/Track/TrackApi.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) companyPlaceholder. All rights reserved.
3 | //
4 |
5 | namespace SpotifyWebApi.Api.Track
6 | {
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Linq;
10 | using System.Text;
11 | using System.Threading.Tasks;
12 | using Business;
13 | using Model;
14 | using Model.Auth;
15 | using Model.Uri;
16 |
17 | ///
18 | /// The .
19 | ///
20 | public class TrackApi : BaseApi, ITrackApi
21 | {
22 | ///
23 | /// Initializes a new instance of the class.
24 | ///
25 | /// A valid access token.
26 | public TrackApi(Token token)
27 | : base(token)
28 | {
29 | }
30 |
31 | ///
32 | public async Task GetTrack(SpotifyUri uri, string market)
33 | {
34 | var r = await ApiClient.GetAsync(
35 | MakeUri(
36 | $"tracks/{uri.Id}",
37 | ("market", market)),
38 | this.Token);
39 |
40 | if (r.Response is FullTrack res)
41 | {
42 | return res;
43 | }
44 | return new FullTrack();
45 | }
46 |
47 | ///
48 | public async Task> GetTracks(IList uris, string market)
49 | {
50 | Validation.ValidateList(uris, 1, 50);
51 | var r = await ApiClient.GetAsync>(
52 | MakeUri(
53 | $"tracks",
54 | ("ids", string.Join(",", uris.Select(x => x.Id))),
55 | ("market", market)),
56 | this.Token);
57 |
58 | if (r.Response is List res)
59 | {
60 | return res;
61 | }
62 | return new List();
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/SimpleAlbum.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using System.Collections.Generic;
4 | using Newtonsoft.Json;
5 | using Uri;
6 |
7 | ///
8 | /// The class.
9 | ///
10 | public class SimpleAlbum
11 | {
12 | ///
13 | /// Gets or sets the type of the album.
14 | ///
15 | [JsonProperty("album_type")]
16 | public string AlbumType { get; set; }
17 |
18 | ///
19 | /// Gets or sets the artists.
20 | ///
21 | [JsonProperty("artists")]
22 | public List Artists { get; set; }
23 |
24 | ///
25 | /// Gets or sets the available markets.
26 | ///
27 | [JsonProperty("available_markets")]
28 | public List AvailableMarkets { get; set; }
29 |
30 | ///
31 | /// Gets or sets the external urls.
32 | ///
33 | [JsonProperty("external_url")]
34 | public Dictionary ExternalUrls { get; set; }
35 |
36 | ///
37 | /// Gets or sets the href.
38 | ///
39 | [JsonProperty("href")]
40 | public string Href { get; set; }
41 |
42 | ///
43 | /// Gets or sets the identifier.
44 | ///
45 | [JsonProperty("id")]
46 | public string Id { get; set; }
47 |
48 | ///
49 | /// Gets or sets the images.
50 | ///
51 | [JsonProperty("images")]
52 | public List Images { get; set; }
53 |
54 | ///
55 | /// Gets or sets the name.
56 | ///
57 | [JsonProperty("name")]
58 | public string Name { get; set; }
59 |
60 | ///
61 | /// Gets or sets the type.
62 | ///
63 | [JsonProperty("type")]
64 | public string Type { get; set; }
65 |
66 | ///
67 | /// Gets or sets the URI.
68 | ///
69 | [JsonProperty("uri")]
70 | public SpotifyUri Uri { get; set; }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Test/Api/PlaylistTest.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApiTest.Api
2 | {
3 | using System.Diagnostics;
4 | using System.Threading.Tasks;
5 | using SpotifyWebApi.Api.Playlist;
6 | using SpotifyWebApi.Model.Uri;
7 | using Xunit;
8 | using Xunit.Abstractions;
9 |
10 | ///
11 | /// The .
12 | ///
13 | public class PlaylistTest : TestBase
14 | {
15 | ///
16 | public PlaylistTest(TestData testData, ITestOutputHelper output) : base(testData, output)
17 | {
18 | }
19 |
20 | ///
21 | /// Tests the method.
22 | ///
23 | /// A playlist uri.
24 | /// The expected track count.
25 | [Theory(Skip = "Unsupported")]
26 | [InlineData("spotify:user:1141820105:playlist:26JXqOmOpnO3hJ4Ij1EEKL", 20)]
27 | [InlineData("spotify:user:1141820105:playlist:4ReouBjlGOwe1btf1CAvIh", 100)]
28 | [InlineData("spotify:user:1141820105:playlist:2Iiwx1mspBbv9eV3gah2B9", 200)]
29 | [InlineData("spotify:user:1141820105:playlist:2vIxq3ZWHDDgrVfAzmIbDf", 1000)]
30 | // [InlineData("spotify:user:1141820105:playlist:4y6G7PQjyw48ha4SdbLF0A", 10000)]
31 | public async Task GetPlaylistTracksTest(string uri, int expectedTrackCount)
32 | {
33 | var st = Stopwatch.StartNew();
34 | var tracks = await this.Api.Playlist.GetPlaylistTracks(SpotifyUri.Make(uri));
35 | st.Stop();
36 | this.Output.WriteLine($"Getting {expectedTrackCount} tracks took {st.Elapsed:c}");
37 | Assert.Equal(expectedTrackCount, tracks.Count);
38 | }
39 |
40 | ///
41 | /// A test for correct retrieval of a playlist.
42 | ///
43 | [Fact(Skip = "Unsupported")]
44 | public async Task GetPlaylistTest()
45 | {
46 | var pl = await this.Api.Playlist.GetPlaylist(
47 | "spotify:user:1141820105:playlist:26JXqOmOpnO3hJ4Ij1EEKL");
48 | Assert.NotNull(pl);
49 | Assert.Equal("Test Playlist (20 songs)", pl.Name);
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/Test/TestData.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApiTest
2 | {
3 | using System;
4 | using System.Diagnostics;
5 | using SpotifyWebApi;
6 | using SpotifyWebApi.Auth;
7 | using SpotifyWebApi.Model.Auth;
8 | using SpotifyWebApi.Model.Enum;
9 | using Xunit.Abstractions;
10 |
11 | ///
12 | /// A class containing some test data used for all tests.
13 | ///
14 | public class TestData
15 | {
16 | ///
17 | /// An instance of a without access to personal information.
18 | ///
19 | public Token ClientCredentialsToken { get; }
20 |
21 | ///
22 | /// An instance of a with access to personal information.
23 | ///
24 | public Token PersonalToken { get; }
25 |
26 | ///
27 | /// Initializes the test data.
28 | ///
29 | public TestData()
30 | {
31 | // So to make the tests work, we need to get a Client Id and Secret.
32 | // I have chosen to save that data in environment variables.
33 | // Key: 'SpotifyWebApiTestData' Value: 'ClientId:ClientSecret'
34 | var variables = Environment.GetEnvironmentVariable("SpotifyWebApiTestData")?.Split(':');
35 | if (variables == null)
36 | {
37 | throw new Exception("Did you set the environment variables before testing?");
38 | }
39 |
40 | var clientId = variables[0];
41 | var clientSecret = variables[1];
42 |
43 | this.ClientCredentialsToken = this.GetClientCredentialsToken(clientId, clientSecret);
44 | // this.PersonalToken = this.GetImplicitGrantToken(clientId);
45 | }
46 |
47 | private Token GetClientCredentialsToken(string clientId, string clientSecret)
48 | {
49 | return ClientCredentials.GetToken(new AuthParameters
50 | {
51 | ClientId = clientId,
52 | ClientSecret = clientSecret,
53 | Scopes = Scopes.All
54 | });
55 | }
56 |
57 | private Token GetImplicitGrantToken(string clientId)
58 | {
59 | throw new NotImplementedException();
60 | }
61 | }
62 | }
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/CurrentlyPlayingContext.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using System;
4 | using Newtonsoft.Json;
5 |
6 | ///
7 | /// The .
8 | ///
9 | public class CurrentlyPlayingContext
10 | {
11 | ///
12 | /// Gets or sets the device that is currently active.
13 | ///
14 | [JsonProperty("device")]
15 | public Device Device { get; set; }
16 |
17 | ///
18 | /// Gets or sets the repeat state: off, track, context.
19 | ///
20 | [JsonProperty("repeat_state")]
21 | public string RepeatState { get; set; }
22 |
23 | ///
24 | /// Gets or sets a value indicating whether shuffle is on or off
25 | ///
26 | [JsonProperty("shuffle_state")]
27 | public bool ShuffleState { get; set; }
28 |
29 | ///
30 | /// Gets or sets the context.
31 | ///
32 | [JsonProperty("context")]
33 | public Context Context { get; set; }
34 |
35 | ///
36 | /// Gets or sets the Unix Millisecond Timestamp when data was fetched
37 | ///
38 | [JsonProperty("timestamp")]
39 | public long TimestampMs { get; set; }
40 |
41 | ///
42 | /// Gets the object of the
43 | ///
44 | public DateTime Timestamp => DateTimeOffset.FromUnixTimeMilliseconds(this.TimestampMs).LocalDateTime;
45 |
46 | ///
47 | /// Gets or sets the progress into the currently playing track. Can be null.
48 | ///
49 | [JsonProperty("progress_ms")]
50 | public int? ProgressMs { get; set; }
51 |
52 | ///
53 | /// Gets or sets a value indicating whether if something is currently playing.
54 | ///
55 | [JsonProperty("is_playing")]
56 | public bool IsPlaying { get; set; }
57 |
58 | ///
59 | /// Gets or sets the currently playing track. Can be null.
60 | ///
61 | [JsonProperty("item")]
62 | public FullTrack Item { get; set; }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Auth/ImplicitGrant.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) companyPlaceholder. All rights reserved.
3 | //
4 |
5 | namespace SpotifyWebApi.Auth
6 | {
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Linq;
10 | using System.Text;
11 | using System.Threading.Tasks;
12 | using Model.Auth;
13 | using Model.Enum;
14 |
15 | ///
16 | /// The .
17 | ///
18 | public static class ImplicitGrant
19 | {
20 | ///
21 | /// Retrieves the authentication url for authenticating with the spotify web api.
22 | ///
23 | /// The to use while creating the url.
24 | /// The state to use while creating the url.
25 | /// For more info see 'https://developer.spotify.com/web-api/authorization-guide/#implicit_grant_flow'
26 | /// The url that the user can use to authenticate this application.
27 | public static string GetUrl(AuthParameters parameters, string state)
28 | {
29 | return $"https://accounts.spotify.com/authorize/?" +
30 | $"client_id={parameters.ClientId}" +
31 | $"&response_type=token" +
32 | $"&redirect_uri={parameters.RedirectUri}" +
33 | $"&scope={parameters.Scopes}" +
34 | $"&state={state}" +
35 | $"&show_dialog={(parameters.ShowDialog ? "true" : "false")}";
36 | }
37 |
38 | ///
39 | /// Creates a token from the callback url.
40 | ///
41 | /// The accesstoken.
42 | /// The tokentype.
43 | /// The expires in.
44 | /// A valid .
45 | public static Token Callback(string accessToken, string tokenType, int expiresIn)
46 | {
47 | return Token.Make(
48 | accessToken,
49 | null,
50 | tokenType,
51 | expiresIn,
52 | authenticationType: TokenAuthenticationType.ImplicitGrant);
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/SpotifyWebApi/SpotifyWebApi.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi
2 | {
3 | using System;
4 | using Api;
5 | using Api.Album;
6 | using Api.Artist;
7 | using Api.Browse;
8 | using Api.Follow;
9 | using Api.Personalization;
10 | using Api.Player;
11 | using Api.Playlist;
12 | using Api.Search;
13 | using Api.Track;
14 | using Api.UserLibrary;
15 | using Api.UserProfile;
16 | using Model.Auth;
17 |
18 | ///
19 | /// The main Api class.
20 | ///
21 | public class SpotifyWebApi : BaseApi, ISpotifyWebApi
22 | {
23 | ///
24 | /// Initializes a new instance of the class.
25 | ///
26 | /// A valid .
27 | public SpotifyWebApi(Token token)
28 | : base(token)
29 | {
30 | }
31 |
32 | ///
33 | public IAlbumApi Album => new AlbumApi(this.Token);
34 |
35 | ///
36 | public IArtistApi Artist => new ArtistApi(this.Token);
37 |
38 | ///
39 | public IBrowseApi Browse => throw new NotImplementedException("This api is not yet implemented!");
40 |
41 | ///
42 | public IFollowApi Follow => throw new NotImplementedException("This api is not yet implemented!");
43 |
44 | ///
45 | public IPersonalizationApi Personalization => throw new NotImplementedException("This api is not yet implemented!");
46 |
47 | ///
48 | public IPlayerApi Player => new PlayerApi(this.Token);
49 |
50 | ///
51 | public IPlaylistApi Playlist => new PlaylistApi(this.Token);
52 |
53 | ///
54 | public ISearchApi Search => throw new NotImplementedException("This api is not yet implemented!");
55 |
56 | ///
57 | public ITrackApi Track => new TrackApi(this.Token);
58 |
59 | ///
60 | public IUserLibraryApi UserLibrary => throw new NotImplementedException("This api is not yet implemented!");
61 |
62 | ///
63 | public IUserProfileApi UserProfile => new UserProfileApi(this.Token);
64 |
65 | ///
66 | public void SetToken(Token token)
67 | {
68 | this.UpdateToken(token);
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/ExampleConsoleApp/Program.cs:
--------------------------------------------------------------------------------
1 | namespace ExampleConsoleApp
2 | {
3 | using System;
4 | using System.Collections.Specialized;
5 | using System.Diagnostics;
6 | using System.Linq;
7 | using System.Net;
8 | using System.Threading.Tasks;
9 | using Microsoft.Extensions.Configuration;
10 | using SpotifyWebApi;
11 | using SpotifyWebApi.Auth;
12 | using SpotifyWebApi.Model.Auth;
13 | using SpotifyWebApi.Model.Enum;
14 |
15 | public class Program
16 | {
17 | private readonly IConfiguration configuration;
18 | private readonly SpotifyAuthentication spotifyAuthentication;
19 |
20 | public Program(IConfiguration configuration, SpotifyAuthentication spotifyAuthentication)
21 | {
22 | this.configuration = configuration;
23 | this.spotifyAuthentication = spotifyAuthentication;
24 | }
25 |
26 | public async Task Run()
27 | {
28 | var token = await this.spotifyAuthentication.GetToken();
29 |
30 | Console.Clear();
31 | Console.WriteLine("Successfully logged in!");
32 |
33 | // Use the api with access to personal data.
34 | var api = new SpotifyWebApi(token);
35 | var me = await api.UserProfile.GetMe();
36 |
37 | Console.WriteLine($"Hello {me.DisplayName}");
38 |
39 | var playlists = await api.Playlist.GetMyPlaylists();
40 | Console.WriteLine("Your playlists:");
41 | Console.WriteLine(string.Join(", ", playlists.Select(x => x.Name)));
42 |
43 | Console.WriteLine();
44 |
45 | var devices = await api.Player.GetAvailableDevices();
46 | Console.WriteLine("Your devices:");
47 | foreach (var device in devices)
48 | {
49 | Console.Write($"{device.Name}, ");
50 | }
51 |
52 | // Console.WriteLine("Refreshing token...");
53 | // var newToken = await AuthorizationCode.RefreshTokenAsync(this.parameters, token);
54 | // Console.WriteLine($"old: {token.AccessToken}");
55 | // Console.WriteLine($"new: {newToken.AccessToken}");
56 | //
57 | // api.SetToken(newToken);
58 | //
59 | // me = await api.UserProfile.GetMe();
60 | //
61 | // Console.WriteLine($"Hello {me.DisplayName}");
62 |
63 | Console.ReadLine();
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/Test/Model/SpotifyUriTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace SpotifyWebApiTest.Model
6 | {
7 | using SpotifyWebApi.Model.Exception;
8 | using SpotifyWebApi.Model.Uri;
9 | using Xunit;
10 |
11 | ///
12 | /// A class testing the correct functioning of .
13 | ///
14 | public class SpotifyUriTest
15 | {
16 | ///
17 | /// Tests the SpotifyUri.Make() method.
18 | ///
19 | /// The uri to convert.
20 | /// The .
21 | [Theory]
22 | [InlineData("spotify:album:1JG04tRkcORA9RP3p06oGp", UriType.Album)]
23 | [InlineData("spotify:artist:2JPBDCZC133viR1884BIEi", UriType.Artist)]
24 | [InlineData("spotify:user:1141820105:playlist:2vIxq3ZWHDDgrVfAzmIbDf", UriType.Playlist)]
25 | [InlineData("spotify:track:0ZGZTut99seZYeJTLy7QZG", UriType.Track)]
26 | [InlineData("spotify:user:1141820105", UriType.User)]
27 | public void UriTypeTest(string u, UriType type)
28 | {
29 | var uri = SpotifyUri.Make(u);
30 | Assert.Equal(u, uri.FullUri);
31 | Assert.Equal(type, uri.Type);
32 | }
33 |
34 | ///
35 | /// Tests the SpotifyUri.Make method for correct exceptions.
36 | ///
37 | [Fact]
38 | public void UriExceptionTest()
39 | {
40 | Assert.Throws(() => SpotifyUri.Make(""));
41 | Assert.Throws(() => SpotifyUri.Make("", UriType.Album));
42 | Assert.Throws(() => SpotifyUri.Make("a:a:a:a:a"));
43 | Assert.Throws(() => SpotifyUri.Make("spotify:::"));
44 | }
45 |
46 | ///
47 | /// Tests the SpotifyUri.Make method for correct functioning.
48 | ///
49 | [Fact]
50 | public void UriTest()
51 | {
52 | var u1 = SpotifyUri.Make("0ZGZTut99seZYeJTLy7QZG", UriType.Track);
53 | var u2 = SpotifyUri.Make("2vIxq3ZWHDDgrVfAzmIbDf", UriType.Playlist);
54 |
55 | Assert.Equal(UriType.Track, u1.Type);
56 | Assert.Equal("spotify:track:0ZGZTut99seZYeJTLy7QZG", u1.FullUri);
57 | Assert.Equal(UriType.Playlist, u2.Type);
58 | Assert.Equal("spotify:playlist:2vIxq3ZWHDDgrVfAzmIbDf", u2.FullUri);
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Auth/ClientCredentials.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Auth
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Collections.Specialized;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Net;
9 | using System.Net.Http.Headers;
10 | using System.Text;
11 | using System.Threading.Tasks;
12 | using Business;
13 | using Model.Auth;
14 | using Newtonsoft.Json;
15 |
16 | ///
17 | /// The .
18 | ///
19 | public static class ClientCredentials
20 | {
21 | ///
22 | /// Retrieves a valid token from the Spotify web api.
23 | ///
24 | /// The used for this token.
25 | /// A valid .
26 | public static Token GetToken(AuthParameters parameters)
27 | {
28 | var req = ApiHelper.CreateRequest(new Uri("https://accounts.spotify.com/api/token"));
29 |
30 | var headers = new NameValueCollection
31 | {
32 | ["Authorization"] = "Basic " + ApiHelper.Base64Encode($"{parameters.ClientId}:{parameters.ClientSecret}"),
33 | };
34 |
35 | req.Headers = new WebHeaderCollection
36 | {
37 | headers
38 | };
39 |
40 | var data = Encoding.ASCII.GetBytes("grant_type=client_credentials");
41 |
42 | req.Method = "POST";
43 | req.ContentType = "application/x-www-form-urlencoded";
44 | req.ContentLength = data.Length;
45 |
46 | using (var stream = req.GetRequestStream())
47 | {
48 | stream.Write(data, 0, data.Length);
49 | }
50 |
51 | var response = (HttpWebResponse)req.GetResponse();
52 |
53 | // Get the stream containing content returned by the server.
54 | var dataStream = response.GetResponseStream();
55 |
56 | // Open the stream using a StreamReader for easy access.
57 | var reader = new StreamReader(dataStream ?? throw new InvalidOperationException());
58 |
59 | // Read the content.
60 | var json = reader.ReadToEnd();
61 |
62 | var token = JsonConvert.DeserializeObject(json);
63 | token.CanAccessPersonalData = false;
64 | token.AuthenticationType = TokenAuthenticationType.ClientCredentials;
65 |
66 | return token;
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/PrivateUser.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using System.Collections.Generic;
4 | using Newtonsoft.Json;
5 | using Uri;
6 |
7 | ///
8 | /// The class.
9 | ///
10 | public class PrivateUser
11 | {
12 | ///
13 | /// Gets or sets the birthdate.
14 | ///
15 | [JsonProperty("birthdate")]
16 | public string Birthdate { get; set; }
17 |
18 | ///
19 | /// Gets or sets the country.
20 | ///
21 | [JsonProperty("country")]
22 | public string Country { get; set; }
23 |
24 | ///
25 | /// Gets or sets the display name.
26 | ///
27 | [JsonProperty("display_name")]
28 | public string DisplayName { get; set; }
29 |
30 | ///
31 | /// Gets or sets the email.
32 | ///
33 | [JsonProperty("email")]
34 | public string Email { get; set; }
35 |
36 | ///
37 | /// Gets or sets the external urls.
38 | ///
39 | [JsonProperty("external_urls")]
40 | public Dictionary ExternalUrls { get; set; }
41 |
42 | ///
43 | /// Gets or sets the followers.
44 | ///
45 | [JsonProperty("followers")]
46 | public Followers Followers { get; set; }
47 |
48 | ///
49 | /// Gets or sets the href.
50 | ///
51 | [JsonProperty("href")]
52 | public string Href { get; set; }
53 |
54 | ///
55 | /// Gets or sets the identifier.
56 | ///
57 | [JsonProperty("id")]
58 | public string Id { get; set; }
59 |
60 | ///
61 | /// Gets or sets the images.
62 | ///
63 | [JsonProperty("images")]
64 | public List Images { get; set; }
65 |
66 | ///
67 | /// Gets or sets the product.
68 | ///
69 | [JsonProperty("product")]
70 | public string Product { get; set; }
71 |
72 | ///
73 | /// Gets or sets the type.
74 | ///
75 | [JsonProperty("type")]
76 | public string Type { get; set; }
77 |
78 | ///
79 | /// Gets or sets the URI.
80 | ///
81 | [JsonProperty("uri")]
82 | public SpotifyUri Uri { get; set; }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/SpotifyWebApi.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27130.2036
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpotifyWebApi", "SpotifyWebApi\SpotifyWebApi.csproj", "{CCD1CAF9-1E3E-42C7-8BBA-A9522C56942D}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "Test\Test.csproj", "{588425FE-3536-40E5-9C61-0CC44598BF42}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Folder", "Solution Folder", "{EBCC8FE0-7CF5-4D01-9C51-4283CFFAAA1D}"
11 | ProjectSection(SolutionItems) = preProject
12 | .gitattributes = .gitattributes
13 | .gitignore = .gitignore
14 | README.md = README.md
15 | Solution.ruleset = Solution.ruleset
16 | SpotifyIcon.png = SpotifyIcon.png
17 | EndProjectSection
18 | EndProject
19 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleConsoleApp", "ExampleConsoleApp\ExampleConsoleApp.csproj", "{2B3BE9FE-CAAC-4EFB-8EBB-2AEA23229592}"
20 | EndProject
21 | Global
22 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
23 | Debug|Any CPU = Debug|Any CPU
24 | Release|Any CPU = Release|Any CPU
25 | EndGlobalSection
26 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
27 | {CCD1CAF9-1E3E-42C7-8BBA-A9522C56942D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
28 | {CCD1CAF9-1E3E-42C7-8BBA-A9522C56942D}.Debug|Any CPU.Build.0 = Debug|Any CPU
29 | {CCD1CAF9-1E3E-42C7-8BBA-A9522C56942D}.Release|Any CPU.ActiveCfg = Release|Any CPU
30 | {CCD1CAF9-1E3E-42C7-8BBA-A9522C56942D}.Release|Any CPU.Build.0 = Release|Any CPU
31 | {588425FE-3536-40E5-9C61-0CC44598BF42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
32 | {588425FE-3536-40E5-9C61-0CC44598BF42}.Debug|Any CPU.Build.0 = Debug|Any CPU
33 | {588425FE-3536-40E5-9C61-0CC44598BF42}.Release|Any CPU.ActiveCfg = Release|Any CPU
34 | {588425FE-3536-40E5-9C61-0CC44598BF42}.Release|Any CPU.Build.0 = Release|Any CPU
35 | {2B3BE9FE-CAAC-4EFB-8EBB-2AEA23229592}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
36 | {2B3BE9FE-CAAC-4EFB-8EBB-2AEA23229592}.Debug|Any CPU.Build.0 = Debug|Any CPU
37 | {2B3BE9FE-CAAC-4EFB-8EBB-2AEA23229592}.Release|Any CPU.ActiveCfg = Release|Any CPU
38 | {2B3BE9FE-CAAC-4EFB-8EBB-2AEA23229592}.Release|Any CPU.Build.0 = Release|Any CPU
39 | EndGlobalSection
40 | GlobalSection(SolutionProperties) = preSolution
41 | HideSolutionNode = FALSE
42 | EndGlobalSection
43 | GlobalSection(ExtensibilityGlobals) = postSolution
44 | SolutionGuid = {16D90C67-7447-4F44-A250-6CA7BD2358F9}
45 | EndGlobalSection
46 | EndGlobal
47 |
--------------------------------------------------------------------------------
/Test/Business/ValidationTest.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApiTest.Business
2 | {
3 | using System.Collections.Generic;
4 | using SpotifyWebApi.Business;
5 | using SpotifyWebApi.Model.Auth;
6 | using SpotifyWebApi.Model.Exception;
7 | using Xunit;
8 |
9 | ///
10 | /// The .
11 | ///
12 | public class ValidationTest
13 | {
14 | ///
15 | /// Test method for .
16 | ///
17 | [Fact]
18 | public void ValidateValidListTest()
19 | {
20 | var validList = new List {0, 1, 2};
21 | Validation.ValidateList(validList, 0, 3);
22 | Validation.ValidateList(validList, 1, 3);
23 | Validation.ValidateList(validList, 2, 3);
24 | }
25 |
26 | ///
27 | /// Test method for .
28 | ///
29 | [Fact]
30 | public void ValidateNonValidListTest()
31 | {
32 | var nonvalidList = new List();
33 | Assert.Throws(() => Validation.ValidateList(nonvalidList, 0, 3));
34 | Assert.Throws(() => Validation.ValidateList(nonvalidList, 1, 3));
35 | Assert.Throws(() => Validation.ValidateList(nonvalidList, 2, 3));
36 | }
37 |
38 | ///
39 | /// Test method for .
40 | ///
41 | [Fact]
42 | public void ValidateIntegerTest()
43 | {
44 | Validation.ValidateInteger(0, 0, 2);
45 | Validation.ValidateInteger(1, 0, 2);
46 | Validation.ValidateInteger(2, 0, 2);
47 |
48 | Assert.Throws(() => Validation.ValidateInteger(5, 0, 2));
49 | Assert.Throws(() => Validation.ValidateInteger(5, 0, 2));
50 | Assert.Throws(() => Validation.ValidateInteger(5, 0, 2));
51 | Assert.Throws(() => Validation.ValidateInteger(5, 0, 2));
52 | }
53 |
54 | ///
55 | /// Test method for .
56 | ///
57 | [Fact]
58 | public void ValidateTokenTest()
59 | {
60 | Assert.Throws(() => Validation.ValidateToken(null));
61 | Assert.Throws(() => Validation.ValidateToken(new Token()));
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/SpotifyWebApi/ISpotifyWebApi.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi
2 | {
3 | using Api.Album;
4 | using Api.Artist;
5 | using Api.Browse;
6 | using Api.Follow;
7 | using Api.Personalization;
8 | using Api.Player;
9 | using Api.Playlist;
10 | using Api.Search;
11 | using Api.Track;
12 | using Api.UserLibrary;
13 | using Api.UserProfile;
14 | using Model.Auth;
15 |
16 | ///
17 | /// The .
18 | ///
19 | public interface ISpotifyWebApi
20 | {
21 | ///
22 | /// Gets the implementation of .
23 | ///
24 | IAlbumApi Album { get; }
25 |
26 | ///
27 | /// Gets the implementation of .
28 | ///
29 | IArtistApi Artist { get; }
30 |
31 | ///
32 | /// Gets the implementation of .
33 | ///
34 | IBrowseApi Browse { get; }
35 |
36 | ///
37 | /// Gets the implementation of .
38 | ///
39 | IFollowApi Follow { get; }
40 |
41 | ///
42 | /// Gets the implementation of .
43 | ///
44 | IPersonalizationApi Personalization { get; }
45 |
46 | ///
47 | /// Gets the implementation of .
48 | ///
49 | IPlayerApi Player { get; }
50 |
51 | ///
52 | /// Gets the implementation of .
53 | ///
54 | IPlaylistApi Playlist { get; }
55 |
56 | ///
57 | /// Gets the implementation of .
58 | ///
59 | ISearchApi Search { get; }
60 |
61 | ///
62 | /// Gets the implementation of .
63 | ///
64 | ITrackApi Track { get; }
65 |
66 | ///
67 | /// Gets the implementation of .
68 | ///
69 | IUserLibraryApi UserLibrary { get; }
70 |
71 | ///
72 | /// Gets the implementation of .
73 | ///
74 | IUserProfileApi UserProfile { get; }
75 |
76 | ///
77 | /// Allows for setting a new token after refreshing it.
78 | ///
79 | /// The refreshed .
80 | void SetToken(Token token);
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/SimplePlaylist.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using System.Collections.Generic;
4 | using Newtonsoft.Json;
5 | using Uri;
6 |
7 | ///
8 | /// The class.
9 | ///
10 | public class SimplePlaylist
11 | {
12 | ///
13 | /// Gets or sets a value indicating whether this is collaborative.
14 | ///
15 | [JsonProperty("collaborative")]
16 | public bool Collaborative { get; set; }
17 |
18 | ///
19 | /// Gets or sets the external urls.
20 | ///
21 | [JsonProperty("external_urls")]
22 | public Dictionary ExternalUrls { get; set; }
23 |
24 | ///
25 | /// Gets or sets the href.
26 | ///
27 | [JsonProperty("href")]
28 | public string Href { get; set; }
29 |
30 | ///
31 | /// Gets or sets the identifier.
32 | ///
33 | [JsonProperty("id")]
34 | public string Id { get; set; }
35 |
36 | ///
37 | /// Gets or sets the images.
38 | ///
39 | [JsonProperty("images")]
40 | public List Images { get; set; }
41 |
42 | ///
43 | /// Gets or sets the name.
44 | ///
45 | [JsonProperty("name")]
46 | public string Name { get; set; }
47 |
48 | ///
49 | /// Gets or sets the owner.
50 | ///
51 | [JsonProperty("owner")]
52 | public PublicUser Owner { get; set; }
53 |
54 | ///
55 | /// Gets or sets a value indicating whether this is public.
56 | ///
57 | [JsonProperty("public")]
58 | public bool? Public { get; set; }
59 |
60 | ///
61 | /// Gets or sets the snapshot identifier.
62 | ///
63 | [JsonProperty("snapshot_id")]
64 | public string SnapshotId { get; set; }
65 |
66 | ///
67 | /// Gets or sets the tracks.
68 | ///
69 | [JsonProperty("tracks")]
70 | public PlaylistTracksRef Tracks { get; set; }
71 |
72 | ///
73 | /// Gets or sets the type.
74 | ///
75 | [JsonProperty("type")]
76 | public string Type { get; set; }
77 |
78 | ///
79 | /// Gets or sets the URI.
80 | ///
81 | [JsonProperty("uri")]
82 | public SpotifyUri Uri { get; set; }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/SpotifyWebApi/SpotifyWebApi.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 | ..\Solution.ruleset
6 | bin\$(Configuration)\$(TargetFramework)\SpotifyWebApiTest.xml
7 |
8 | SpotifyWebApi
9 | SpotifyWebApi
10 |
11 |
12 | SpotifyWebApi-Core
13 | Spotify Web Api
14 | Pim Merks
15 | Pim Merks
16 | A Spotify Web API wrapper for C#. View the changelog here: https://github.com/pimmerks/SpotifyWebApi/releases
17 | Pim Merks
18 | ICON.png
19 | LICENSE.md
20 |
21 | https://github.com/pimmerks/SpotifyWebApi
22 | https://github.com/pimmerks/SpotifyWebApi
23 | true
24 | Spotify;SpotifyWebApi;Web;Api;REST;Spotify;WebApi;Net;Core;Standard;Framework
25 | true
26 | https://github.com/pimmerks/SpotifyWebApi
27 | master
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | all
44 | runtime; build; native; contentfiles; analyzers
45 |
46 |
47 | all
48 |
49 |
50 | all
51 |
52 |
53 |
54 |
55 |
56 | NU5105
57 | true
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/SimpleTrack.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using System.Collections.Generic;
4 | using Newtonsoft.Json;
5 | using Uri;
6 |
7 | ///
8 | /// The class.
9 | ///
10 | public class SimpleTrack
11 | {
12 | ///
13 | /// Gets or sets the artists.
14 | ///
15 | [JsonProperty("artists")]
16 | public List Artists { get; set; }
17 |
18 | ///
19 | /// Gets or sets the available markets.
20 | ///
21 | [JsonProperty("available_markets")]
22 | public List AvailableMarkets { get; set; }
23 |
24 | ///
25 | /// Gets or sets the disc number.
26 | ///
27 | [JsonProperty("disc_number")]
28 | public int DiscNumber { get; set; }
29 |
30 | ///
31 | /// Gets or sets the duration ms.
32 | ///
33 | [JsonProperty("duration_ms")]
34 | public int DurationMs { get; set; }
35 |
36 | ///
37 | /// Gets or sets a value indicating whether this is explicit.
38 | ///
39 | [JsonProperty("explicit")]
40 | public bool Explicit { get; set; }
41 |
42 | ///
43 | /// Gets or sets the external urls.
44 | ///
45 | [JsonProperty("external_urls")]
46 | public Dictionary ExternalUrls { get; set; }
47 |
48 | ///
49 | /// Gets or sets the href.
50 | ///
51 | [JsonProperty("href")]
52 | public string Href { get; set; }
53 |
54 | ///
55 | /// Gets or sets the identifier.
56 | ///
57 | [JsonProperty("id")]
58 | public string Id { get; set; }
59 |
60 | ///
61 | /// Gets or sets the name.
62 | ///
63 | [JsonProperty("name")]
64 | public string Name { get; set; }
65 |
66 | ///
67 | /// Gets or sets the preview URL.
68 | ///
69 | [JsonProperty("preview_url")]
70 | public string PreviewUrl { get; set; }
71 |
72 | ///
73 | /// Gets or sets the track number.
74 | ///
75 | [JsonProperty("track_number")]
76 | public int TrackNumber { get; set; }
77 |
78 | ///
79 | /// Gets or sets the type.
80 | ///
81 | [JsonProperty("type")]
82 | public string Type { get; set; }
83 |
84 | ///
85 | /// Gets or sets the URI.
86 | ///
87 | [JsonProperty("uri")]
88 | public SpotifyUri Uri { get; set; }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Business/HelperExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Business
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using Model;
8 | using Model.Auth;
9 |
10 | ///
11 | /// The .
12 | ///
13 | internal static class HelperExtensions
14 | {
15 | ///
16 | /// Loads to list.
17 | ///
18 | /// The type of the paging object.
19 | /// The paging object.
20 | /// The token.
21 | /// The maximum items to return.
22 | /// The final list{T}
23 | public static async Task> LoadToList(this Paging paging, Token token, int maxItems = -1)
24 | {
25 | if (paging == null)
26 | {
27 | return new List();
28 | }
29 | var curPage = paging;
30 | var result = curPage.Items;
31 |
32 | while (curPage.Next != null)
33 | {
34 | var next = await ApiClient.GetAsync>(new Uri(curPage.Next), token);
35 |
36 | if (next.Response is Paging nextPage)
37 | {
38 | result.AddRange(nextPage.Items);
39 | curPage = nextPage;
40 | }
41 | }
42 |
43 | return result;
44 | }
45 |
46 | ///
47 | /// Chunk a list by .
48 | ///
49 | /// The type of the list.
50 | /// The source list.
51 | /// Size of the chunks.
52 | /// A List of lists containing the chunked lists.
53 | public static List> ChunkBy(this IEnumerable source, int chunkSize)
54 | {
55 | return source
56 | .Select((x, i) => new { Index = i, Value = x })
57 | .GroupBy(x => x.Index / chunkSize)
58 | .Select(x => x.Select(v => v.Value).ToList())
59 | .ToList();
60 | }
61 |
62 | ///
63 | /// Converts a list of strings to a single string with a separator.
64 | ///
65 | /// The list to convert.
66 | /// The separator to put between the list items.
67 | /// The created string.
68 | public static string AsSingleString(this List list, string separator = ",")
69 | {
70 | return string.Join(separator, list);
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/Test/Api/BaseApiTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace SpotifyWebApiTest.Api
6 | {
7 | using SpotifyWebApi.Api;
8 | using SpotifyWebApi.Model.Auth;
9 | using Xunit;
10 |
11 | ///
12 | /// A test for the .
13 | ///
14 | public class BaseApiTest : BaseApi
15 | {
16 | ///
17 | ///
18 | /// Initializes this test class.
19 | ///
20 | public BaseApiTest()
21 | : base(null)
22 | {
23 | }
24 |
25 | ///
26 | /// A test for the make uri method.
27 | ///
28 | [Fact(Skip = "Unsupported")]
29 | public void MakeUriTest()
30 | {
31 | var uri1 = MakeUri("test");
32 | Assert.Equal("https://api.spotify.com/v1/test", uri1.AbsoluteUri);
33 | }
34 |
35 | ///
36 | /// A test for the make uri method.
37 | ///
38 | /// The expected absolute uri.
39 | /// The relative uri.
40 | /// The query parameter
41 | /// The query value
42 | [Theory(Skip = "Unsupported")]
43 | [InlineData("https://api.spotify.com/v1/test", "test", "", "")]
44 | [InlineData("https://api.spotify.com/v1/test", "test", "q", "")]
45 | [InlineData("https://api.spotify.com/v1/test", "test", "", "v")]
46 | [InlineData("https://api.spotify.com/v1/test?q=v", "test", "q", "v")]
47 | public void MakeUriTests(string expected, string r, string q, string v)
48 | {
49 | var uri = MakeUri(r, (queryParameter: q, value: v));
50 | Assert.Equal(expected, uri.AbsoluteUri);
51 | }
52 |
53 | ///
54 | /// A test for the make uri method.
55 | ///
56 | /// The expected absolute uri.
57 | /// The relative uri.
58 | /// The query parameter
59 | /// The query value
60 | /// The query parameter
61 | /// The query value
62 | [Theory(Skip = "Unsupported")]
63 | [InlineData("https://api.spotify.com/v1/test", "test", "", "", "", "")]
64 | [InlineData("https://api.spotify.com/v1/test?q=v&q=v", "test", "q", "v", "q", "v")]
65 | [InlineData("https://api.spotify.com/v1/test", "test", "q", "", "", "v")]
66 | [InlineData("https://api.spotify.com/v1/test?q=v", "test", "q", "", "q", "v")]
67 | public void MakeUriTest2(string expected, string r, string q1, string v1, string q2, string v2)
68 | {
69 | var uri = MakeUri(r, (q1, v1), (q2, v2));
70 | Assert.Equal(expected, uri.AbsoluteUri);
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Api/Browse/IBrowseApi.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Api.Browse
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Threading.Tasks;
6 | using Model;
7 |
8 | ///
9 | /// The browse api interface.
10 | ///
11 | public interface IBrowseApi
12 | {
13 | ///
14 | /// Get a list of Spotify featured playlists (shown, for example, on a Spotify player’s ‘Browse’ tab).
15 | ///
16 | ///
17 | /// Optional. The desired language, consisting of a lowercase ISO 639-1 language code and an uppercase ISO 3166-1 alpha-2 country code, joined by an underscore.
18 | /// For example: es_MX, meaning “Spanish (Mexico)”. Provide this parameter if you want the results returned in a particular language (where available).
19 | /// Note that, if locale is not supplied, or if the specified language is not available, all strings will be returned in the Spotify default language (American English).
20 | /// The locale parameter, combined with the country parameter, may give odd results if not carefully matched.
21 | /// For example country=SE&locale=de_DE will return a list of categories relevant to Sweden but as German language strings.
22 | ///
23 | ///
24 | /// Optional. A country: an ISO 3166-1 alpha-2 country code. Provide this parameter if you want the list of returned items to be relevant to a particular country. If omitted, the returned items will be relevant to all countries.
25 | ///
26 | ///
27 | /// Optional. Use this parameter to specify the user’s local time to get results tailored for that specific date and time in the day. If not provided, the response defaults to the current UTC time. Example: “2014-10-23T09:00:00” for a user whose local time is 9AM. If there were no featured playlists (or there is no data) at the specified time, the response will revert to the current UTC time.
28 | ///
29 | /// Optional. The maximum results to return, or -1 to retrieve all items.
30 | ///
31 | /// Optional. The index of the first item to return. Default: 0 (the first object). Use with limit to get the next set of items.
32 | ///
33 | ///
34 | /// A and a list of objects.
35 | /// The conveys a message like "Monday morning music, coming right up!".
36 | ///
37 | #pragma warning disable SA1009 // Closing parenthesis must be spaced correctly
38 | Task<(string Message, IList Playlists)> GetFeaturedPlaylists(
39 | string locale = null,
40 | string country = null,
41 | DateTime? timeStamp = null,
42 | int maxResults = -1,
43 | int offset = 0);
44 | #pragma warning restore SA1009 // Closing parenthesis must be spaced correctly
45 | }
46 | }
--------------------------------------------------------------------------------
/ExampleConsoleApp/SpotifyAuthentication.cs:
--------------------------------------------------------------------------------
1 | namespace ExampleConsoleApp
2 | {
3 | using System;
4 | using System.Collections.Specialized;
5 | using System.Diagnostics;
6 | using System.Net;
7 | using System.Threading.Tasks;
8 | using Microsoft.Extensions.Configuration;
9 | using SpotifyWebApi.Auth;
10 | using SpotifyWebApi.Model.Auth;
11 | using SpotifyWebApi.Model.Enum;
12 |
13 | public class SpotifyAuthentication
14 | {
15 | private string clientSecret;
16 | private string clientId;
17 | private string redirectUri;
18 | private AuthParameters parameters;
19 |
20 | public SpotifyAuthentication(IConfiguration configuration)
21 | {
22 | this.clientId = configuration["Spotify:ClientId"];
23 | this.clientSecret = configuration["Spotify:ClientSecret"];
24 | this.redirectUri = configuration["Spotify:RedirectUri"];
25 |
26 | this.parameters = new AuthParameters
27 | {
28 | ClientId = this.clientId,
29 | ClientSecret = this.clientSecret,
30 | RedirectUri = this.redirectUri,
31 | Scopes = Scopes.All,
32 | ShowDialog = true
33 | };
34 | }
35 |
36 | public async Task GetToken()
37 | {
38 | var state = Guid.NewGuid().ToString(); // Save this state because you must check it later
39 |
40 | var url = AuthorizationCode.GetUrl(this.parameters, state);
41 |
42 | Console.WriteLine("Opening url...");
43 | Console.WriteLine(url);
44 |
45 | var ps = new ProcessStartInfo(url)
46 | {
47 | UseShellExecute = true,
48 | Verb = "open"
49 | };
50 | Process.Start(ps);
51 |
52 | var queryString = await this.StartServerAndRetrieveAuthCode();
53 |
54 | // The retrieved callback:
55 | var retrievedState = queryString["state"];
56 | var retrievedCode = queryString["code"];
57 | var retrievedError = queryString["error"];
58 |
59 | if (retrievedError != null)
60 | {
61 | throw new Exception(retrievedError);
62 | }
63 |
64 | if (state != retrievedState)
65 | {
66 | throw new Exception("State did not match!");
67 | }
68 |
69 | var token = await AuthorizationCode.ProcessCallbackAsync(this.parameters, retrievedCode);
70 |
71 | return token;
72 | }
73 |
74 | public async Task StartServerAndRetrieveAuthCode(string url = "http://localhost:8080/")
75 | {
76 | var listener = new HttpListener();
77 | listener.Prefixes.Add("http://localhost:8080/");
78 | listener.Start();
79 |
80 | var context = await listener.GetContextAsync();
81 |
82 | listener.Stop();
83 |
84 | return context.Request.QueryString;
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/Test/Api/AlbumTest.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApiTest.Api
2 | {
3 | using System;
4 | using System.Diagnostics;
5 | using System.Threading.Tasks;
6 | using SpotifyWebApi.Api.Album;
7 | using SpotifyWebApi.Model.Exception;
8 | using SpotifyWebApi.Model.Uri;
9 | using Xunit;
10 | using Xunit.Abstractions;
11 |
12 | ///
13 | /// The .
14 | ///
15 | public class AlbumTest : TestBase
16 | {
17 | ///
18 | public AlbumTest(TestData testData, ITestOutputHelper output) : base(testData, output)
19 | {
20 | }
21 |
22 | ///
23 | /// The album test.
24 | ///
25 | [Theory(Skip = "Unsupported")]
26 | [InlineData("spotify:album:44tJAQ21VUkgwjRDbNeJtB", "Funky Freddy")]
27 | [InlineData("spotify:album:1JG04tRkcORA9RP3p06oGp", "Palmas")]
28 | public async Task GetAlbumTest(string uri, string expectedName)
29 | {
30 | var album = await this.Api.Album.GetAlbum(uri);
31 | Assert.True(album.Name == expectedName);
32 | Assert.NotNull(album);
33 | }
34 |
35 | ///
36 | /// The albums test.
37 | ///
38 | [Fact(Skip = "Unsupported")]
39 | public async Task GetAlbumsTest()
40 | {
41 | var albums = await this.Api.Album.GetAlbums(
42 | SpotifyUri.MakeList(
43 | "spotify:album:44tJAQ21VUkgwjRDbNeJtB",
44 | "spotify:album:1JG04tRkcORA9RP3p06oGp"));
45 | Assert.Equal(2, albums.Count);
46 | Assert.True(albums[0].Name == "Funky Freddy");
47 | Assert.True(albums[1].Name == "Palmas");
48 | }
49 |
50 | ///
51 | /// The album tracks test.
52 | ///
53 | [Theory(Skip = "Unsupported")]
54 | [InlineData("spotify:album:44tJAQ21VUkgwjRDbNeJtB", 1)]
55 | [InlineData("spotify:album:1JG04tRkcORA9RP3p06oGp", 21)]
56 | public async Task GetAlbumTracksTest(string uri, int expectedTrackCount)
57 | {
58 | var tracks = await this.Api.Album.GetAlbumTracks(SpotifyUri.Make(uri));
59 | Assert.Equal(expectedTrackCount, tracks.Count);
60 | }
61 |
62 | ///
63 | /// Tests to see if the validation works.
64 | ///
65 | [Fact(Skip = "Unsupported")]
66 | public async Task GetAlbumTrackExceptionTest()
67 | {
68 | await Assert.ThrowsAsync(
69 | async () => await this.Api.Album.GetAlbum("spotify:album:fdsajkfdsjkha"));
70 | }
71 |
72 | ///
73 | /// Tests to see if the validation works.
74 | ///
75 | [Fact(Skip = "Unsupported")]
76 | public async Task UnauthorizedExceptionTest()
77 | {
78 | await Assert.ThrowsAsync(
79 | async () => await new AlbumApi(null).GetAlbum("spotify:album:fdsajkfdsjkha", ""));
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | [](https://www.nuget.org/packages/SpotifyWebApi-Core/)
3 | [](https://www.nuget.org/packages/SpotifyWebApi-Core/)
4 | [](https://github.com/pimmerks/SpotifyWebApi/blob/master/LICENSE)
5 |
6 |
7 | # SpotifyWebApi - Core
8 | A .net Core wrapper for the Spotify Web Api.
9 |
10 | # Nuget package
11 | Installing the package is easy.
12 |
13 | Using the package manager console:
14 | > `PM> Install-Package SpotifyWebApi-Core`
15 |
16 |
17 | Using the dotnet CLI:
18 | > `> dotnet add package SpotifyWebApi-Core`
19 |
20 | ## Getting an authentication token
21 |
22 | ### Client credentials:
23 |
24 | ```csharp
25 | var token = ClientCredentials.GetToken(new AuthParameters
26 | {
27 | ClientId = "clientId",
28 | ClientSecret = "clientSecret",
29 | Scopes = Scope.All,
30 | });
31 | ```
32 | Note: A client credentials token cannot access any personal data.
33 | The `Token` class has a usefull property to check this: `token.CanAccessPersonalData`
34 |
35 | ### Authorization code:
36 | Start the authorization code process by retrieving the authentication url:
37 | ```csharp
38 | var state = Guid.NewGuid().ToString(); // Save this state because you must check it later
39 |
40 | var parameters = new AuthParameters
41 | {
42 | ClientId = "clientId",
43 | ClientSecret = "clientSecret",
44 | RedirectUri = "https://.../callback",
45 | Scopes = Scope.All,
46 | ShowDialog = true
47 | };
48 |
49 | var url = AuthorizationCode.GetUrl(parameters, state);
50 | ```
51 | At this point you should start a webserver listening on the `RedirectUri` and the the client/user should login to Spotify.
52 | The webserver should expect the following query parameters: `?code=code&state=state&error=error`
53 | ```csharp
54 | // The retreived callback:
55 | var retrievedState = "retrievedState";
56 | var retrievedCode = "code";
57 | var retreivedError = "";
58 |
59 | if (state != retrievedState)
60 | {
61 | throw new Exception("State did not match!");
62 | }
63 |
64 | var token = AuthorizationCode.ProcessCallback(parameters, retrievedCode, retreivedError);
65 |
66 | // Use the api with access to personal data.
67 | var api = new SpotifyWebApi(token);
68 | var me = await api.UserProfile.GetMe();
69 | ```
70 |
71 | A token received with the `AuthorizationCode` can also be refreshed:
72 | ```csharp
73 | // Refresh a token when its expired
74 | if (token.IsExpired)
75 | {
76 | token = AuthorizationCode.RefreshToken(parameters, token);
77 | }
78 | ```
79 |
80 | ## Using the api
81 | After a token has been retrieved, we can use the api:
82 |
83 | Getting a playlist and the playlist tracks:
84 | ```csharp
85 | ISpotifyWebApi api = new SpotifyWebApi(token);
86 |
87 | var playlist = await spotify.Playlist.GetPlaylist(id);
88 | var tracks = await spotify.Playlist.GetPlaylistTracks(id);
89 | ```
90 |
91 | ## TODO:
92 | - [ ] Add documentation
93 | - [ ] Add api examples
94 | - [ ] Implement more endpoints
95 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Api/Album/AlbumApi.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Api.Album
2 | {
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Business;
7 | using Model;
8 | using Model.Auth;
9 | using Model.List;
10 | using Model.Uri;
11 |
12 | ///
13 | ///
14 | /// The .
15 | ///
16 | public class AlbumApi : BaseApi, IAlbumApi
17 | {
18 | ///
19 | /// Initializes a new instance of the class.
20 | ///
21 | /// A valid .
22 | public AlbumApi(Token token)
23 | : base(token)
24 | {
25 | }
26 |
27 | ///
28 | public async Task GetAlbum(SpotifyUri albumUri, string market)
29 | {
30 | var r = await ApiClient.GetAsync(
31 | MakeUri(
32 | $"albums/{albumUri.Id}",
33 | ("market", market)),
34 | this.Token);
35 |
36 | if (r.Response is FullAlbum album)
37 | {
38 | return album;
39 | }
40 | return new FullAlbum();
41 | }
42 |
43 | ///
44 | public async Task> GetAlbums(IList albumUris, string market)
45 | {
46 | // Because we support more then 50 albums uris as input.
47 | // but the spotify api only supports a maximum of 50,
48 | // lets fix that by creating multiple lists of 50.
49 | var lists = albumUris.ChunkBy(50);
50 |
51 | var res = new List();
52 |
53 | foreach (var l in lists)
54 | {
55 | var s = string.Join(",", l.Select(x => x.Id).ToArray());
56 |
57 | var r = await ApiClient.GetAsync(
58 | MakeUri(
59 | $"albums",
60 | ("ids", s),
61 | ("market", market)),
62 | this.Token);
63 |
64 | if (r.Response is MultipleAlbums albums)
65 | {
66 | res.AddRange(albums.Albums);
67 | }
68 | }
69 |
70 | return res;
71 | }
72 |
73 | ///
74 | public async Task> GetAlbumTracks(SpotifyUri albumUri, string market)
75 | {
76 | var r = await ApiClient.GetAsync>(
77 | MakeUri(
78 | $"albums/{albumUri.Id}/tracks",
79 | ("limit", "50"),
80 | ("offset", "0"), // TODO: Offset
81 | ("market", market)),
82 | this.Token);
83 |
84 | if (r.Response is Paging tracks)
85 | {
86 | return await tracks.LoadToList(this.Token);
87 | }
88 | return new List();
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/FullPlaylist.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using System.Collections.Generic;
4 | using Newtonsoft.Json;
5 | using Uri;
6 |
7 | ///
8 | /// The class.
9 | ///
10 | public class FullPlaylist
11 | {
12 | ///
13 | /// Gets or sets a value indicating whether this is collaborative.
14 | ///
15 | [JsonProperty("collaborative")]
16 | public bool Collaborative { get; set; }
17 |
18 | ///
19 | /// Gets or sets the description.
20 | ///
21 | [JsonProperty("description")]
22 | public string Description { get; set; }
23 |
24 | ///
25 | /// Gets or sets the external urls.
26 | ///
27 | [JsonProperty("external_urls")]
28 | public Dictionary ExternalUrls { get; set; }
29 |
30 | ///
31 | /// Gets or sets the followers.
32 | ///
33 | [JsonProperty("followers")]
34 | public Followers Followers { get; set; }
35 |
36 | ///
37 | /// Gets or sets the href.
38 | ///
39 | [JsonProperty("href")]
40 | public string Href { get; set; }
41 |
42 | ///
43 | /// Gets or sets the identifier.
44 | ///
45 | [JsonProperty("id")]
46 | public string Id { get; set; }
47 |
48 | ///
49 | /// Gets or sets the images.
50 | ///
51 | [JsonProperty("images")]
52 | public List Images { get; set; }
53 |
54 | ///
55 | /// Gets or sets the name.
56 | ///
57 | [JsonProperty("name")]
58 | public string Name { get; set; }
59 |
60 | ///
61 | /// Gets or sets the owner.
62 | ///
63 | [JsonProperty("owner")]
64 | public PublicUser Owner { get; set; }
65 |
66 | ///
67 | /// Gets or sets a value indicating whether this is public.
68 | ///
69 | [JsonProperty("public")]
70 | public bool? Public { get; set; }
71 |
72 | ///
73 | /// Gets or sets the snapshot identifier.
74 | ///
75 | [JsonProperty("snapshot_id")]
76 | public string SnapshotId { get; set; }
77 |
78 | ///
79 | /// Gets or sets the tracks.
80 | ///
81 | [JsonProperty("tracks")]
82 | public Paging Tracks { get; set; }
83 |
84 | ///
85 | /// Gets or sets the type.
86 | ///
87 | [JsonProperty("type")]
88 | public string Type { get; set; }
89 |
90 | ///
91 | /// Gets or sets the URI.
92 | ///
93 | [JsonProperty("uri")]
94 | public SpotifyUri Uri { get; set; }
95 |
96 | ///
97 | /// Gets or sets the track list.
98 | ///
99 | public List TrackList { get; set; }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Api/Artist/IArtistApi.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Api.Artist
2 | {
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 | using Model;
6 | using Model.Enum;
7 | using Model.Uri;
8 |
9 | ///
10 | /// The artist api.
11 | ///
12 | public interface IArtistApi
13 | {
14 | ///
15 | /// Get Spotify catalog information for a single artist identified by their unique Spotify Uri.
16 | ///
17 | /// The for the artist.
18 | /// The retrieved Artist.
19 | Task GetArtist(SpotifyUri artistUri);
20 |
21 | ///
22 | /// Get Spotify catalog information for several artists based on their Spotify Uris.
23 | ///
24 | /// A list of the for the artists. Maximum: 50 IDs.
25 | /// The retrieved artists.
26 | Task> GetArtists(IList artistUris);
27 |
28 | ///
29 | /// Get Spotify catalog information about an artist’s albums. Optional parameters can be specified in the parameters to filter the response.
30 | ///
31 | /// The for the artist.
32 | /// Optional. A list of s that will be used to filter the response. If not supplied, all album types will be returned.
33 | /// Note multiple types can be selected like so: 'AlbumType.Album | AlbumType.AppearsOn'.
34 | /// Optional. An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking.
35 | /// Optional. The maximum results to return, or -1 to retrieve all items.
36 | /// Optional. The index of the first album to return. Default: 0 (i.e., the first album).
37 | /// The artists albums.
38 | Task> GetArtistAlbums(
39 | SpotifyUri artistUri,
40 | AlbumType albumTypes = AlbumType.Album | AlbumType.AppearsOn | AlbumType.Compilation | AlbumType.Single,
41 | string market = "",
42 | int maxResults = -1,
43 | int offset = 0);
44 |
45 | ///
46 | /// Get Spotify catalog information about an artist’s top tracks by country.
47 | ///
48 | /// The for the artist.
49 | /// An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking.
50 | /// The artists top track by country.
51 | Task> GetArtistsTopTracks(SpotifyUri artistUri, string market);
52 |
53 | ///
54 | /// Get Spotify catalog information about artists similar to a given artist. Similarity is based on analysis of the Spotify community’s listening history.
55 | ///
56 | /// The for the artist.
57 | /// The related artists for the specified .
58 | Task> GetArtistsRelatedArtists(SpotifyUri artistUri);
59 | }
60 | }
--------------------------------------------------------------------------------
/SpotifyWebApi/Api/BaseApi.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Api
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Dynamic;
6 | using System.Linq;
7 | using System.Threading.Tasks;
8 | using Business;
9 | using Model.Auth;
10 |
11 | ///
12 | /// The used for all the other APIs.
13 | ///
14 | public abstract class BaseApi
15 | {
16 | ///
17 | /// Gets the base spotify URI
18 | ///
19 | protected const string BaseUri = "https://api.spotify.com/v1/";
20 |
21 | ///
22 | /// Initializes a new instance of the class.
23 | ///
24 | /// A valid .
25 | protected BaseApi(Token token)
26 | {
27 | if (token == null)
28 | {
29 | return;
30 | }
31 |
32 | // Validate token
33 | Validation.ValidateToken(token);
34 | this.Token = token;
35 | }
36 |
37 | ///
38 | /// Gets the .
39 | ///
40 | protected Token Token { get; private set; }
41 |
42 | #region Static methods
43 |
44 | ///
45 | /// Makes a Spotify url from the and the provided .
46 | ///
47 | /// The relative URL.
48 | /// The full request uri.
49 | protected static Uri MakeUri(string relativeUrl)
50 | {
51 | if (relativeUrl.StartsWith("/")) { relativeUrl = relativeUrl.Substring(1); }
52 | return new Uri(BaseUri + relativeUrl);
53 | }
54 |
55 | ///
56 | /// Makes a Spotify uri from the and the provided .
57 | /// Also adding any query parameters.
58 | ///
59 | /// The relative URL.
60 | /// A list of query parameters.
61 | /// Note: When a parameter value is null or empty, the query will not contain the query parameter.
62 | /// The full request uri.
63 | protected static Uri MakeUri(string relativeUrl, params(string queryParameter, string value)[] parameters)
64 | {
65 | if (relativeUrl.StartsWith("/")) { relativeUrl = relativeUrl.Substring(1); }
66 |
67 | var p = parameters.Where(x => !string.IsNullOrEmpty(x.queryParameter) && !string.IsNullOrEmpty(x.value)).ToList();
68 |
69 | var queryParameters = string.Empty;
70 | if (p.Any())
71 | {
72 | queryParameters += "?" + string.Join("&", p.Select(x => $"{x.queryParameter}={x.value}"));
73 | }
74 |
75 | return new Uri(BaseUri + relativeUrl + queryParameters);
76 | }
77 |
78 | #endregion Static methods
79 |
80 | ///
81 | /// Updates the token when you refreshed it.
82 | ///
83 | /// The updated token.
84 | protected void UpdateToken(Token token)
85 | {
86 | // Validate token
87 | Validation.ValidateToken(token);
88 | this.Token = token;
89 | }
90 |
91 | // TODO: Add Api GET,POST,ETC methods here.
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/FullAlbum.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using System.Collections.Generic;
4 | using Newtonsoft.Json;
5 | using Uri;
6 |
7 | ///
8 | /// The class.
9 | ///
10 | public class FullAlbum
11 | {
12 | ///
13 | /// Gets or sets the type of the album.
14 | ///
15 | [JsonProperty("album_type")]
16 | public string AlbumType { get; set; }
17 |
18 | ///
19 | /// Gets or sets the artists.
20 | ///
21 | [JsonProperty("artists")]
22 | public List Artists { get; set; }
23 |
24 | ///
25 | /// Gets or sets the available markets.
26 | ///
27 | [JsonProperty("available_markets")]
28 | public List AvailableMarkets { get; set; }
29 |
30 | ///
31 | /// Gets or sets the copyrights.
32 | ///
33 | [JsonProperty("copyrights")]
34 | public List Copyrights { get; set; }
35 |
36 | ///
37 | /// Gets or sets the external ids.
38 | ///
39 | [JsonProperty("external_ids")]
40 | public Dictionary ExternalIds { get; set; }
41 |
42 | ///
43 | /// Gets or sets the external urls.
44 | ///
45 | [JsonProperty("external_url")]
46 | public Dictionary ExternalUrls { get; set; }
47 |
48 | ///
49 | /// Gets or sets the genres.
50 | ///
51 | [JsonProperty("genres")]
52 | public List Genres { get; set; }
53 |
54 | ///
55 | /// Gets or sets the href.
56 | ///
57 | [JsonProperty("href")]
58 | public string Href { get; set; }
59 |
60 | ///
61 | /// Gets or sets the identifier.
62 | ///
63 | [JsonProperty("id")]
64 | public string Id { get; set; }
65 |
66 | ///
67 | /// Gets or sets the images.
68 | ///
69 | [JsonProperty("images")]
70 | public List Images { get; set; }
71 |
72 | ///
73 | /// Gets or sets the label.
74 | ///
75 | [JsonProperty("label")]
76 | public string Label { get; set; }
77 |
78 | ///
79 | /// Gets or sets the name.
80 | ///
81 | [JsonProperty("name")]
82 | public string Name { get; set; }
83 |
84 | ///
85 | /// Gets or sets the popularity.
86 | ///
87 | [JsonProperty("popularity")]
88 | public int Popularity { get; set; }
89 |
90 | ///
91 | /// Gets or sets the release date.
92 | ///
93 | [JsonProperty("release_date")]
94 | public string ReleaseDate { get; set; }
95 |
96 | ///
97 | /// Gets or sets the release date precision.
98 | ///
99 | [JsonProperty("release_date_precision")]
100 | public string ReleaseDatePrecision { get; set; }
101 |
102 | ///
103 | /// Gets or sets the tracks.
104 | ///
105 | [JsonProperty("tracks")]
106 | public Paging Tracks { get; set; }
107 |
108 | ///
109 | /// Gets or sets the type.
110 | ///
111 | [JsonProperty("type")]
112 | public string Type { get; set; }
113 |
114 | ///
115 | /// Gets or sets the URI.
116 | ///
117 | [JsonProperty("uri")]
118 | public SpotifyUri Uri { get; set; }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Api/Player/PlayerApi.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Api.Player
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Threading.Tasks;
6 | using Business;
7 | using Model;
8 | using Model.Auth;
9 | using Model.Enum;
10 | using Model.Uri;
11 |
12 | ///
13 | /// The .
14 | ///
15 | public class PlayerApi : BaseApi, IPlayerApi
16 | {
17 | ///
18 | /// Initializes a new instance of the class.
19 | ///
20 | /// A valid .
21 | public PlayerApi(Token token)
22 | : base(token)
23 | {
24 | }
25 |
26 | ///
27 | public async Task> GetAvailableDevices()
28 | {
29 | var r = await ApiClient.GetAsync(
30 | MakeUri("me/player/devices"), this.Token);
31 |
32 | if (r.Response is DeviceList res)
33 | {
34 | return res.Devices;
35 | }
36 | return new List();
37 | }
38 |
39 | ///
40 | public async Task GetCurrentlyPlayingContext(string market = "")
41 | {
42 | var r = await ApiClient.GetAsync(
43 | MakeUri(
44 | $"me/player",
45 | ("market", market)),
46 | this.Token);
47 |
48 | if (r.Response is CurrentlyPlayingContext res)
49 | {
50 | return res;
51 | }
52 | return new CurrentlyPlayingContext();
53 | }
54 |
55 | ///
56 | public async Task GetCurrentlyPlaying(string market = "")
57 | {
58 | var r = await ApiClient.GetAsync(
59 | MakeUri(
60 | $"me/player/currently-playing",
61 | ("market", market)),
62 | this.Token);
63 |
64 | if (r.Response is CurrentlyPlaying res)
65 | {
66 | return res;
67 | }
68 | return new CurrentlyPlaying();
69 | }
70 |
71 | ///
72 | public Task TransferPlayback(List devices, bool? play = null)
73 | {
74 | throw new NotImplementedException();
75 | }
76 |
77 | ///
78 | public Task StartPlayback(Device device = null, SpotifyUri contextUri = null, List uris = null)
79 | {
80 | throw new NotImplementedException();
81 | }
82 |
83 | ///
84 | public Task PausePlayback(Device device = null)
85 | {
86 | throw new NotImplementedException();
87 | }
88 |
89 | ///
90 | public Task Next(Device device = null)
91 | {
92 | throw new NotImplementedException();
93 | }
94 |
95 | ///
96 | public Task Previous(Device device = null)
97 | {
98 | throw new NotImplementedException();
99 | }
100 |
101 | ///
102 | public Task Seek(int positionMs, Device device = null)
103 | {
104 | throw new NotImplementedException();
105 | }
106 |
107 | ///
108 | public Task SetRepeat(RepeatState state, Device device = null)
109 | {
110 | throw new NotImplementedException();
111 | }
112 |
113 | ///
114 | public Task SetVolume(int volumePercent, Device device = null)
115 | {
116 | throw new NotImplementedException();
117 | }
118 |
119 | ///
120 | public Task SetShuffle(bool state, Device device = null)
121 | {
122 | throw new NotImplementedException();
123 | }
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Api/Playlist/PlaylistApi.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Api.Playlist
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Threading.Tasks;
6 | using Business;
7 | using Model;
8 | using Model.Auth;
9 | using Model.Uri;
10 |
11 | ///
12 | /// The .
13 | ///
14 | public class PlaylistApi : BaseApi, IPlaylistApi
15 | {
16 | ///
17 | /// Initializes a new instance of the class.
18 | ///
19 | /// A valid .
20 | public PlaylistApi(Token token)
21 | : base(token)
22 | {
23 | }
24 |
25 | ///
26 | public async Task> GetUsersPlaylist(SpotifyUri user, int maxResults, int offset = 0)
27 | {
28 | var r = await ApiClient.GetAsync>(
29 | MakeUri($"users/{user.Id}/playlists?limit=50&offset={offset}"), this.Token);
30 |
31 | if (r.Response is Paging res)
32 | {
33 | return await res.LoadToList(this.Token, maxResults);
34 | }
35 | return new List();
36 | }
37 |
38 | ///
39 | public async Task> GetMyPlaylists(int maxResults, int offset = 0)
40 | {
41 | var r = await ApiClient.GetAsync>(
42 | MakeUri($"me/playlists?limit=50&offset={offset}"), this.Token);
43 |
44 | if (r.Response is Paging res)
45 | {
46 | return await res.LoadToList(this.Token, maxResults);
47 | }
48 | return new List();
49 | }
50 |
51 | ///
52 | public async Task GetPlaylist(SpotifyUri playlistUri, string market)
53 | {
54 | var r = await ApiClient.GetAsync(
55 | MakeUri(
56 | $"playlists/{playlistUri.Id}",
57 | ("market", market)),
58 | this.Token);
59 |
60 | if (r.Response is FullPlaylist res)
61 | {
62 | return res;
63 | }
64 |
65 | return new FullPlaylist();
66 | }
67 |
68 | ///
69 | public async Task> GetPlaylistTracks(
70 | SpotifyUri playlistUri, int maxResults, int offset, string market)
71 | {
72 | var r = await ApiClient.GetAsync>(
73 | MakeUri(
74 | $"playlists/{playlistUri.Id}/tracks?limit=100&offset={offset}",
75 | ("market", market)),
76 | this.Token);
77 |
78 | if (r.Response is Paging res)
79 | {
80 | return await res.LoadToList(this.Token, maxResults);
81 | }
82 | return new List();
83 | }
84 |
85 | ///
86 | public async Task CreatePlaylist(
87 | SpotifyUri user, string name, bool @public, string description)
88 | {
89 | var r = await ApiClient.PostAsync(
90 | MakeUri($"users/{user.Id}/playlists"),
91 | new PlaylistCreate
92 | {
93 | Name = name,
94 | Public = @public,
95 | Description = description,
96 | }, this.Token);
97 |
98 | if (r.Response is FullPlaylist playlist)
99 | {
100 | return playlist;
101 | }
102 | return new FullPlaylist();
103 | }
104 |
105 | ///
106 | public Task AddTracksToPlaylist(SpotifyUri playlistUri, IList tracks, int? position = null)
107 | {
108 | throw new NotImplementedException();
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Api/Artist/ArtistApi.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Api.Artist
2 | {
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Business;
7 | using Model;
8 | using Model.Auth;
9 | using Model.Enum;
10 | using Model.Uri;
11 |
12 | ///
13 | ///
14 | /// The .
15 | ///
16 | public class ArtistApi : BaseApi, IArtistApi
17 | {
18 | ///
19 | /// Initializes a new instance of the class.
20 | ///
21 | /// A valid .
22 | public ArtistApi(Token token)
23 | : base(token)
24 | {
25 | }
26 |
27 | ///
28 | public async Task GetArtist(SpotifyUri artistUri)
29 | {
30 | var r = await ApiClient.GetAsync(
31 | MakeUri($"artists/{artistUri.Id}"),
32 | this.Token);
33 |
34 | if (r.Response is FullArtist res)
35 | {
36 | return res;
37 | }
38 | return new FullArtist();
39 | }
40 |
41 | ///
42 | public async Task> GetArtists(IList artistUris)
43 | {
44 | Validation.ValidateList(artistUris, 0, 50);
45 | var ids = artistUris.Select(x => x.Id).ToList().AsSingleString();
46 | var r = await ApiClient.GetAsync(
47 | MakeUri($"artists?ids={ids}"),
48 | this.Token);
49 |
50 | if (r.Response is List res)
51 | {
52 | return res;
53 | }
54 | return new List();
55 | }
56 |
57 | ///
58 | public async Task> GetArtistAlbums(SpotifyUri artistUri, AlbumType albumTypes, string market, int maxResults, int offset)
59 | {
60 | var albumTypeString = string.Empty;
61 | if (albumTypes.HasFlag(AlbumType.Album)) albumTypeString += "album,";
62 | if (albumTypes.HasFlag(AlbumType.AppearsOn)) albumTypeString += "appears_on,";
63 | if (albumTypes.HasFlag(AlbumType.Compilation)) albumTypeString += "compilation,";
64 | if (albumTypes.HasFlag(AlbumType.Single)) albumTypeString += "compilation,";
65 | albumTypeString = albumTypeString.Remove(albumTypeString.Length - 1);
66 |
67 | var r = await ApiClient.GetAsync>(
68 | MakeUri(
69 | $"artists/{artistUri.Id}/albums?{albumTypeString}",
70 | ("album_type", albumTypeString),
71 | ("limit", "50"),
72 | ("offset", offset.ToString()),
73 | ("market", market)),
74 | this.Token);
75 |
76 | if (r.Response is Paging res)
77 | {
78 | return await res.LoadToList(this.Token);
79 | }
80 | return new List();
81 | }
82 |
83 | ///
84 | public async Task> GetArtistsTopTracks(SpotifyUri artistUri, string market)
85 | {
86 | var r = await ApiClient.GetAsync>(
87 | MakeUri(
88 | $"artists/{artistUri.Id}/top-tracks",
89 | ("market", market)),
90 | this.Token);
91 |
92 | if (r.Response is List res)
93 | {
94 | return res;
95 | }
96 | return new List();
97 | }
98 |
99 | ///
100 | public async Task> GetArtistsRelatedArtists(SpotifyUri artistUri)
101 | {
102 | var r = await ApiClient.GetAsync>(
103 | MakeUri($"artists/{artistUri.Id}/related-artists"),
104 | this.Token);
105 |
106 | if (r.Response is List res)
107 | {
108 | return res;
109 | }
110 | return new List();
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Business/Validation.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Business
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Net;
6 | using System.Net.Http;
7 | using Model.Auth;
8 | using Model.Exception;
9 |
10 | ///
11 | /// A static class used for validation a variance of objects.
12 | ///
13 | internal static class Validation
14 | {
15 | ///
16 | /// Validates a list and throws a when failed.
17 | ///
18 | /// The list to validate
19 | /// The minimum number of items in the list.
20 | /// The maximum number of items in the list.
21 | /// Type of the list to validate.
22 | /// Throws a validation exception when the list is null or invalid.
23 | public static void ValidateList(ICollection list, int min = -1, int max = -1)
24 | {
25 | if (list == null) { throw new ValidationException("The list is null."); }
26 |
27 | var c = list.Count;
28 | if (c == 0) { throw new ValidationException("The list is empty."); }
29 | if (c < min) { throw new ValidationException("The list is too small."); }
30 | if (c > max) { throw new ValidationException("The list is too big."); }
31 | }
32 |
33 | ///
34 | /// Validates a integer and throws a when failed.
35 | ///
36 | /// The value to validate
37 | /// The minimum of the value.
38 | /// The maximum of the value.
39 | /// Throws a validation exception when the value is invalid.
40 | public static void ValidateInteger(int value, int min = int.MinValue, int max = int.MaxValue)
41 | {
42 | if (value < min) { throw new ValidationException("The value is too small."); }
43 | if (value > max) { throw new ValidationException("The value is too big."); }
44 | }
45 |
46 | ///
47 | /// Validates a .
48 | /// Note this function does not check for expired tokens!
49 | ///
50 | /// The token to validate.
51 | /// Throws a validation exception when the value is invalid.
52 | public static void ValidateToken(Token token)
53 | {
54 | if (token == null) { throw new ValidationException("The token is null."); }
55 |
56 | if (token.Type != "Bearer") throw new ValidationException("The token type is not \"Bearer\".");
57 |
58 | if (string.IsNullOrWhiteSpace(token.AccessToken))
59 | throw new ValidationException("The token's 'AccessToken' is empty or null");
60 |
61 | // if (string.IsNullOrWhiteSpace(token.RefreshToken))
62 | // throw new ValidationException("The token's 'RefreshToken' is empty or null");
63 | }
64 |
65 | ///
66 | /// Validates a and throws errors based on the code.
67 | ///
68 | /// The status code to validate.
69 | /// The response of the http request.
70 | public static void ValidateResponseCode(HttpStatusCode statusCode, string response)
71 | {
72 | switch (statusCode)
73 | {
74 | case HttpStatusCode.BadRequest:
75 | throw new BadRequestException(response);
76 | case HttpStatusCode.Unauthorized:
77 | throw new UnauthorizedAccessException(response);
78 | case HttpStatusCode.Forbidden:
79 | throw new ForbiddenException(response);
80 | case HttpStatusCode.NotFound:
81 | throw new NotFoundException(response);
82 | case HttpStatusCode.InternalServerError:
83 | throw new InternalServerErrorException(response);
84 | case HttpStatusCode.BadGateway:
85 | throw new BadGatewayException(response);
86 | case HttpStatusCode.ServiceUnavailable:
87 | throw new ServiceUnavailableException(response);
88 | }
89 |
90 | // This status code is not in the HttpStatusCode Enum
91 | if ((int)statusCode == 429)
92 | {
93 | throw new TooManyRequestsException(response);
94 | }
95 | }
96 | }
97 | }
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Auth/Token.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 | [assembly: InternalsVisibleTo("SpotifyWebApi.Auth")]
3 |
4 | namespace SpotifyWebApi.Model.Auth
5 | {
6 | using System;
7 | using Newtonsoft.Json;
8 | using Uri;
9 |
10 | ///
11 | /// The class.
12 | ///
13 | public class Token
14 | {
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | public Token()
19 | {
20 | }
21 |
22 | ///
23 | /// Gets or sets the access token.
24 | ///
25 | [JsonProperty("access_token")]
26 | public string AccessToken { get; set; }
27 |
28 | ///
29 | /// Gets or sets the type.
30 | ///
31 | [JsonProperty("token_type")]
32 | public string Type { get; set; }
33 |
34 | ///
35 | /// Gets or sets the scope.
36 | ///
37 | [JsonProperty("scope")]
38 | public string Scope { get; set; }
39 |
40 | ///
41 | /// Gets or sets the expires in.
42 | ///
43 | [JsonProperty("expires_in")]
44 | public int ExpiresIn { get; set; }
45 |
46 | ///
47 | /// Gets or sets the refresh token.
48 | ///
49 | [JsonProperty("refresh_token")]
50 | public string RefreshToken { get; set; }
51 |
52 | ///
53 | /// Gets the token generated.
54 | ///
55 | [JsonProperty("token_generated")]
56 | public DateTime TokenGenerated { get; set; } = DateTime.UtcNow;
57 |
58 | ///
59 | /// Gets a value indicating whether this instance is expired.
60 | ///
61 | [JsonIgnore]
62 | public bool IsExpired => DateTime.UtcNow > this.TokenGenerated.AddSeconds(this.ExpiresIn);
63 |
64 | ///
65 | /// Gets a value indicating wheter this token can be used to access personal data.
66 | ///
67 | [JsonProperty("can_access_personal_data")]
68 | public bool CanAccessPersonalData { get; internal set; } = true;
69 |
70 | ///
71 | /// Gets a value indicating the authentication type of this token.
72 | ///
73 | [JsonProperty("token_authentication_type")]
74 | public TokenAuthenticationType AuthenticationType { get; internal set; }
75 |
76 | ///
77 | /// Creates a token.
78 | ///
79 | /// The access token.
80 | /// The refresh token.
81 | /// The token type.
82 | /// The expires in value.
83 | /// The datetime the token was generated.
84 | /// The scope of the token.
85 | /// If the token can access personal data.
86 | /// The authentication type of the token.
87 | /// The newly made .
88 | public static Token Make(
89 | string accessToken,
90 | string refreshToken,
91 | string tokenType = "Bearer",
92 | int expiresIn = 3600,
93 | DateTime? tokenGenerated = null,
94 | string scope = null,
95 | bool canAccessPersonalData = true,
96 | TokenAuthenticationType authenticationType = TokenAuthenticationType.AuthorizationCode)
97 | {
98 | return new Token
99 | {
100 | AccessToken = accessToken,
101 | RefreshToken = refreshToken,
102 | Type = tokenType,
103 | ExpiresIn = expiresIn,
104 | TokenGenerated = tokenGenerated ?? DateTime.UtcNow,
105 | Scope = scope ?? string.Empty,
106 | CanAccessPersonalData = canAccessPersonalData,
107 | AuthenticationType = authenticationType
108 | };
109 | }
110 |
111 | ///
112 | /// Creates a header string from this instance.
113 | ///
114 | /// The web header string.
115 | public string ToHeaderString()
116 | {
117 | return this.Type + " " + this.AccessToken;
118 | }
119 |
120 | ///
121 | public override string ToString()
122 | {
123 | return $"AccessToken: {this.AccessToken}, RefreshToken: {this.RefreshToken}";
124 | }
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/FullTrack.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model
2 | {
3 | using System.Collections.Generic;
4 | using Newtonsoft.Json;
5 | using Uri;
6 |
7 | ///
8 | /// The class.
9 | ///
10 | public class FullTrack
11 | {
12 | ///
13 | /// Gets or sets the album.
14 | ///
15 | [JsonProperty("album")]
16 | public SimpleAlbum Album { get; set; }
17 |
18 | ///
19 | /// Gets or sets the artists.
20 | ///
21 | [JsonProperty("artists")]
22 | public List Artists { get; set; }
23 |
24 | ///
25 | /// Gets or sets the available markets.
26 | ///
27 | [JsonProperty("available_markets")]
28 | public List AvailableMarkets { get; set; }
29 |
30 | ///
31 | /// Gets or sets the disc number.
32 | ///
33 | [JsonProperty("disc_number")]
34 | public int DiscNumber { get; set; }
35 |
36 | ///
37 | /// Gets or sets the duration ms.
38 | ///
39 | [JsonProperty("duration_ms")]
40 | public int DurationMs { get; set; }
41 |
42 | ///
43 | /// Gets or sets the explicit.
44 | ///
45 | [JsonProperty("explicit")]
46 | public string Explicit { get; set; }
47 |
48 | ///
49 | /// Gets or sets the external ids.
50 | ///
51 | [JsonProperty("external_ids")]
52 | public Dictionary ExternalIds { get; set; }
53 |
54 | ///
55 | /// Gets or sets the external urls.
56 | ///
57 | [JsonProperty("external_urls")]
58 | public Dictionary ExternalUrls { get; set; }
59 |
60 | ///
61 | /// Gets or sets the href.
62 | ///
63 | [JsonProperty("href")]
64 | public string Href { get; set; }
65 |
66 | ///
67 | /// Gets or sets the identifier.
68 | ///
69 | [JsonProperty("id")]
70 | public string Id { get; set; }
71 |
72 | ///
73 | /// Gets or sets a value indicating whether this instance is playable.
74 | ///
75 | [JsonProperty("is_playable")]
76 | public bool IsPlayable { get; set; }
77 |
78 | ///
79 | /// Gets or sets the linked from.
80 | ///
81 | [JsonProperty("linked_from")]
82 | public LinkedFrom LinkedFrom { get; set; }
83 |
84 | ///
85 | /// Gets or sets the name.
86 | ///
87 | [JsonProperty("name")]
88 | public string Name { get; set; }
89 |
90 | ///
91 | /// Gets or sets the popularity.
92 | ///
93 | [JsonProperty("popularity")]
94 | public int Popularity { get; set; }
95 |
96 | ///
97 | /// Gets or sets the preview URL.
98 | ///
99 | [JsonProperty("preview_url")]
100 | public string PreviewUrl { get; set; }
101 |
102 | ///
103 | /// Gets or sets the track number.
104 | ///
105 | [JsonProperty("track_number")]
106 | public int TrackNumber { get; set; }
107 |
108 | ///
109 | /// Gets or sets the type.
110 | ///
111 | [JsonProperty("type")]
112 | public string Type { get; set; }
113 |
114 | ///
115 | /// Gets or sets the URI.
116 | ///
117 | [JsonProperty("uri")]
118 | public SpotifyUri Uri { get; set; }
119 |
120 | ///
121 | /// Returns a hash code for this instance.
122 | ///
123 | /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
124 | public override int GetHashCode()
125 | {
126 | if (this.Id != null)
127 | return this.Id.GetHashCode();
128 | else
129 | return 0;
130 | }
131 |
132 | ///
133 | /// Determines whether the specified is equal to this instance.
134 | ///
135 | /// The object to compare with the current object.
136 | /// true if the specified is equal to this instance; otherwise, false.
137 | public override bool Equals(object obj)
138 | {
139 | return this.Id.Equals(obj);
140 | }
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Api/Playlist/IPlaylistApi.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Api.Playlist
2 | {
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 | using Model;
6 | using Model.Enum;
7 | using Model.Uri;
8 |
9 | ///
10 | /// The playlist api.
11 | ///
12 | public interface IPlaylistApi
13 | {
14 | ///
15 | /// Get a list of the playlists owned or followed by a Spotify user.
16 | ///
17 | /// The of the user.
18 | /// Optional. The maximum results to return, or -1 to retrieve all items.
19 | /// Optional. The index of the first playlist to return.
20 | /// Default: 0 (the first object).
21 | /// Maximum offset: 100.000. Use with limit to get the next set of playlists.
22 | /// A list of s.
23 | Task> GetUsersPlaylist(SpotifyUri user, int maxResults = -1, int offset = 0);
24 |
25 | ///
26 | /// Get a list of the playlists owned or followed by the current Spotify user.
27 | ///
28 | /// Optional. The maximum results to return, or -1 to retrieve all items.
29 | /// Optional. The index of the first playlist to return.
30 | /// Default: 0 (the first object).
31 | /// Maximum offset: 100.000. Use with limit to get the next set of playlists.
32 | /// A list of s.
33 | Task> GetMyPlaylists(int maxResults = -1, int offset = 0);
34 |
35 | ///
36 | /// Get a playlist owned by a Spotify user.
37 | ///
38 | /// The for the playlist.
39 | /// Optional. An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking.
40 | /// A object.
41 | Task GetPlaylist(SpotifyUri playlistUri, string market = null);
42 |
43 | ///
44 | /// Get full details of the tracks of a playlist owned by a Spotify user.
45 | ///
46 | /// The for the playlist.
47 | /// Optional. The maximum results to return, or -1 to retrieve all items.
48 | /// Optional. The index of the first track to return. Default: 0 (the first object).
49 | /// Optional. An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking.
50 | /// A list of objects.
51 | Task> GetPlaylistTracks(
52 | SpotifyUri playlistUri, int maxResults = -1, int offset = 0, string market = null);
53 |
54 | ///
55 | /// Create a playlist for a Spotify user.
56 | ///
57 | /// The of the user.
58 | /// The name for the new playlist, for example "Your Coolest Playlist". This name does not need to be unique; a user may have several playlists with the same name.
59 | /// Optional. If true the playlist will be public, if false it will be private.
60 | /// Optional. Value for playlist description as displayed in Spotify Clients and in the Web API.
61 | /// The created .
62 | ///
63 | /// Note: that the playlist will be empty until you add tracks.
64 | /// Note: To be able to create private playlists, the user must have granted the scope.
65 | ///
66 | Task CreatePlaylist(
67 | SpotifyUri user, string name, bool @public = true, string description = "");
68 |
69 | ///
70 | /// Add one or more tracks to a user’s playlist.
71 | ///
72 | /// The for the playlist.
73 | /// A list of 's to add to the playlist.
74 | /// Optional. The position to insert the tracks, a zero-based index.
75 | /// Tha add tracks to playlist task.
76 | Task AddTracksToPlaylist(SpotifyUri playlistUri, IList tracks, int? position = null);
77 |
78 | // TODO: More functions:
79 | // https://developer.spotify.com/web-api/remove-tracks-playlist/
80 | // https://developer.spotify.com/web-api/reorder-playlists-tracks/
81 | // https://developer.spotify.com/web-api/replace-playlists-tracks/
82 | // https://developer.spotify.com/web-api/change-playlist-details/
83 | }
84 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 | build/
25 |
26 | # Visual Studio 2015 cache/options directory
27 | .vs/
28 | # Uncomment if you have tasks that create the project's static files in wwwroot
29 | #wwwroot/
30 |
31 | # MSTest test Results
32 | [Tt]est[Rr]esult*/
33 | [Bb]uild[Ll]og.*
34 |
35 | # NUNIT
36 | *.VisualState.xml
37 | TestResult.xml
38 |
39 | # Build Results of an ATL Project
40 | [Dd]ebugPS/
41 | [Rr]eleasePS/
42 | dlldata.c
43 |
44 | # DNX
45 | project.lock.json
46 | project.fragment.lock.json
47 | artifacts/
48 |
49 | *_i.c
50 | *_p.c
51 | *_i.h
52 | *.ilk
53 | *.meta
54 | *.obj
55 | *.pch
56 | *.pdb
57 | *.pgc
58 | *.pgd
59 | *.rsp
60 | *.sbr
61 | *.tlb
62 | *.tli
63 | *.tlh
64 | *.tmp
65 | *.tmp_proj
66 | *.log
67 | *.vspscc
68 | *.vssscc
69 | .builds
70 | *.pidb
71 | *.svclog
72 | *.scc
73 |
74 | # Chutzpah Test files
75 | _Chutzpah*
76 |
77 | # Visual C++ cache files
78 | ipch/
79 | *.aps
80 | *.ncb
81 | *.opendb
82 | *.opensdf
83 | *.sdf
84 | *.cachefile
85 | *.VC.db
86 | *.VC.VC.opendb
87 |
88 | # Visual Studio profiler
89 | *.psess
90 | *.vsp
91 | *.vspx
92 | *.sap
93 |
94 | # TFS 2012 Local Workspace
95 | $tf/
96 |
97 | # Guidance Automation Toolkit
98 | *.gpState
99 |
100 | # ReSharper is a .NET coding add-in
101 | _ReSharper*/
102 | *.[Rr]e[Ss]harper
103 | *.DotSettings.user
104 |
105 | # JustCode is a .NET coding add-in
106 | .JustCode
107 |
108 | # TeamCity is a build add-in
109 | _TeamCity*
110 |
111 | # DotCover is a Code Coverage Tool
112 | *.dotCover
113 |
114 | # NCrunch
115 | _NCrunch_*
116 | .*crunch*.local.xml
117 | nCrunchTemp_*
118 |
119 | # MightyMoose
120 | *.mm.*
121 | AutoTest.Net/
122 |
123 | # Web workbench (sass)
124 | .sass-cache/
125 |
126 | # Installshield output folder
127 | [Ee]xpress/
128 |
129 | # DocProject is a documentation generator add-in
130 | DocProject/buildhelp/
131 | DocProject/Help/*.HxT
132 | DocProject/Help/*.HxC
133 | DocProject/Help/*.hhc
134 | DocProject/Help/*.hhk
135 | DocProject/Help/*.hhp
136 | DocProject/Help/Html2
137 | DocProject/Help/html
138 |
139 | # Click-Once directory
140 | publish/
141 |
142 | # Publish Web Output
143 | *.[Pp]ublish.xml
144 | *.azurePubxml
145 | # TODO: Comment the next line if you want to checkin your web deploy settings
146 | # but database connection strings (with potential passwords) will be unencrypted
147 | #*.pubxml
148 | *.publishproj
149 |
150 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
151 | # checkin your Azure Web App publish settings, but sensitive information contained
152 | # in these scripts will be unencrypted
153 | PublishScripts/
154 |
155 | # NuGet Packages
156 | *.nupkg
157 | # The packages folder can be ignored because of Package Restore
158 | **/packages/*
159 | # except build/, which is used as an MSBuild target.
160 | !**/packages/build/
161 | # Uncomment if necessary however generally it will be regenerated when needed
162 | #!**/packages/repositories.config
163 | # NuGet v3's project.json files produces more ignoreable files
164 | *.nuget.props
165 | *.nuget.targets
166 |
167 | # Microsoft Azure Build Output
168 | csx/
169 | *.build.csdef
170 |
171 | # Microsoft Azure Emulator
172 | ecf/
173 | rcf/
174 |
175 | # Windows Store app package directories and files
176 | AppPackages/
177 | BundleArtifacts/
178 | Package.StoreAssociation.xml
179 | _pkginfo.txt
180 |
181 | # Visual Studio cache files
182 | # files ending in .cache can be ignored
183 | *.[Cc]ache
184 | # but keep track of directories ending in .cache
185 | !*.[Cc]ache/
186 |
187 | # Others
188 | ClientBin/
189 | ~$*
190 | *~
191 | *.dbmdl
192 | *.dbproj.schemaview
193 | *.jfm
194 | *.pfx
195 | *.publishsettings
196 | node_modules/
197 | orleans.codegen.cs
198 |
199 | # Since there are multiple workflows, uncomment next line to ignore bower_components
200 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
201 | #bower_components/
202 |
203 | # RIA/Silverlight projects
204 | Generated_Code/
205 |
206 | # Backup & report files from converting an old project file
207 | # to a newer Visual Studio version. Backup files are not needed,
208 | # because we have git ;-)
209 | _UpgradeReport_Files/
210 | Backup*/
211 | UpgradeLog*.XML
212 | UpgradeLog*.htm
213 |
214 | # SQL Server files
215 | *.mdf
216 | *.ldf
217 |
218 | # Business Intelligence projects
219 | *.rdl.data
220 | *.bim.layout
221 | *.bim_*.settings
222 |
223 | # Microsoft Fakes
224 | FakesAssemblies/
225 |
226 | # GhostDoc plugin setting file
227 | *.GhostDoc.xml
228 |
229 | # Node.js Tools for Visual Studio
230 | .ntvs_analysis.dat
231 |
232 | # Visual Studio 6 build log
233 | *.plg
234 |
235 | # Visual Studio 6 workspace options file
236 | *.opt
237 |
238 | # Visual Studio LightSwitch build output
239 | **/*.HTMLClient/GeneratedArtifacts
240 | **/*.DesktopClient/GeneratedArtifacts
241 | **/*.DesktopClient/ModelManifest.xml
242 | **/*.Server/GeneratedArtifacts
243 | **/*.Server/ModelManifest.xml
244 | _Pvt_Extensions
245 |
246 | # Paket dependency manager
247 | .paket/paket.exe
248 | paket-files/
249 |
250 | # FAKE - F# Make
251 | .fake/
252 |
253 | # JetBrains Rider
254 | .idea/
255 | *.sln.iml
256 |
257 | # CodeRush
258 | .cr/
259 |
260 | # Python Tools for Visual Studio (PTVS)
261 | __pycache__/
262 | *.pyc
263 |
264 | # Custom project ignore
265 | Examples/ExampleNet47/App.config
266 | coverage.json
267 | SpotifyWebApi/FodyWeavers.xsd
268 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Business/ApiClient.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Business
2 | {
3 | using System;
4 | using System.Net.Http;
5 | using System.Net.Http.Headers;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using Model;
9 | using Model.Auth;
10 | using Newtonsoft.Json;
11 | using Newtonsoft.Json.Converters;
12 |
13 | ///
14 | /// The class used for communicating with a REST service.
15 | ///
16 | internal static class ApiClient
17 | {
18 | ///
19 | /// Gets from an uri asynchronously.
20 | ///
21 | /// The expected return object.
22 | /// The request URI.
23 | /// Optional. A valid .
24 | /// The response of the HTTP GET.
25 | public static async Task GetAsync(Uri uri, Token token)
26 | {
27 | using var client = MakeHttpClient(token);
28 | using var response = await client.GetAsync(uri);
29 | var responseString = await response.Content.ReadAsStringAsync();
30 |
31 | Validation.ValidateResponseCode(response.StatusCode, responseString);
32 |
33 | return WebResponse.Make(DeserializeObject(responseString), response.StatusCode);
34 | }
35 |
36 | ///
37 | /// Posts to an uri asynchronously.
38 | ///
39 | /// The expected return object.
40 | /// The request URI.
41 | /// The body of the request.
42 | /// Optional. A valid .
43 | /// The response of the HTTP POST.
44 | public static async Task PostAsync(Uri uri, object body, Token token = null)
45 | {
46 | using var client = MakeHttpClient(token);
47 | using var content = new StringContent(SerializeObject(body), Encoding.UTF8, "application/json");
48 |
49 | using var response = await client.PostAsync(uri, content);
50 | var responseString = await response.Content.ReadAsStringAsync();
51 |
52 | Validation.ValidateResponseCode(response.StatusCode, responseString);
53 |
54 | return WebResponse.Make(DeserializeObject(responseString), response.StatusCode);
55 | }
56 |
57 | ///
58 | /// Puts to an uri asynchronously.
59 | ///
60 | /// The expected return object.
61 | /// The request URI.
62 | /// The body of the request.
63 | /// Optional. A valid .
64 | /// The response of the HTTP PUT.
65 | public static async Task PutAsync(Uri uri, object body, Token token = null)
66 | {
67 | using var client = MakeHttpClient(token);
68 | using var content = new StringContent(SerializeObject(body), Encoding.UTF8, "application/json");
69 |
70 | using var response = await client.PutAsync(uri, content);
71 | var responseString = await response.Content.ReadAsStringAsync();
72 |
73 | Validation.ValidateResponseCode(response.StatusCode, responseString);
74 |
75 | return WebResponse.Make(DeserializeObject(responseString), response.StatusCode);
76 | }
77 |
78 | ///
79 | /// Deletes from an uri asynchronously.
80 | ///
81 | /// The expected return object.
82 | /// The request URI.
83 | /// Optional. A valid .
84 | /// The response of the HTTP DELETE.
85 | public static async Task DeleteAsync(Uri uri, Token token = null)
86 | {
87 | using var client = MakeHttpClient(token);
88 | using var response = await client.DeleteAsync(uri);
89 | var responseString = await response.Content.ReadAsStringAsync();
90 |
91 | Validation.ValidateResponseCode(response.StatusCode, responseString);
92 |
93 | return WebResponse.Make(DeserializeObject(responseString), response.StatusCode);
94 | }
95 |
96 | ///
97 | /// Makes the HTTP client.
98 | ///
99 | /// Optional. A valid .
100 | /// A newly created containing the authentication provided by the token.
101 | private static HttpClient MakeHttpClient(Token token = null)
102 | {
103 | var client = new HttpClient();
104 | client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/x-www-form-urlencoded"));
105 |
106 | if (token != null)
107 | client.DefaultRequestHeaders.Authorization = AuthenticationHeaderValue.Parse(token.ToHeaderString());
108 |
109 | return client;
110 | }
111 |
112 | ///
113 | /// Custom deserialization with StringEnumConverter.
114 | ///
115 | /// The type of the expected object.
116 | /// The json to deserialize.
117 | /// The deserialized object.
118 | private static T DeserializeObject(string json)
119 | {
120 | return JsonConvert.DeserializeObject(json, new StringEnumConverter(true));
121 | }
122 |
123 | ///
124 | /// Custom serialization with StringEnumConverter.
125 | ///
126 | /// The object to serialize.
127 | /// The serialized JSON.
128 | private static string SerializeObject(object obj)
129 | {
130 | return JsonConvert.SerializeObject(obj, new StringEnumConverter(true));
131 | }
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Enum/Scopes.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model.Enum
2 | {
3 | ///
4 | /// Spotify scopes, for more information visit https://developer.spotify.com/documentation/general/guides/scopes/
5 | ///
6 | public static class Scopes
7 | {
8 | ///
9 | /// The default scope separator.
10 | ///
11 | public const string ScopeSeparator = " ";
12 |
13 | #region Images
14 |
15 | ///
16 | /// Write access to user-provided images.
17 | ///
18 | public const string UgcImageUpload = "ugc-image-upload";
19 |
20 | ///
21 | /// All scopes in the image category.
22 | ///
23 | public const string AllImages = UgcImageUpload;
24 |
25 | #endregion
26 |
27 | #region Spotify connect
28 |
29 | ///
30 | /// UserReadPlaybackState
31 | ///
32 | public const string UserReadPlaybackState = "user-read-playback-state";
33 |
34 | ///
35 | /// UserModifyPlaybackState
36 | ///
37 | public const string UserModifyPlaybackState = "user-modify-playback-state";
38 |
39 | ///
40 | /// UserReadCurrentlyPlaying
41 | ///
42 | public const string UserReadCurrentlyPlaying = "user-read-currently-playing";
43 |
44 | ///
45 | /// All scopes from the Spotify Connect category.
46 | ///
47 | public const string AllSpotifyConnect =
48 | UserReadPlaybackState + Sep + UserModifyPlaybackState + Sep + UserReadCurrentlyPlaying;
49 |
50 | #endregion
51 |
52 | #region Playback
53 |
54 | ///
55 | /// Streaming
56 | ///
57 | public const string Streaming = "streaming";
58 |
59 | ///
60 | /// AppRemoteControl
61 | ///
62 | public const string AppRemoteControl = "app-remote-control";
63 |
64 | ///
65 | /// All scopes from the Playback category.
66 | ///
67 | public const string AllPlayback = Streaming + Sep + AppRemoteControl;
68 |
69 | #endregion
70 |
71 | #region Users
72 |
73 | ///
74 | /// UserReadEmail
75 | ///
76 | public const string UserReadEmail = "user-read-email";
77 |
78 | ///
79 | /// UserReadPrivate
80 | ///
81 | public const string UserReadPrivate = "user-read-private";
82 |
83 | ///
84 | /// All scopes from the Users category.
85 | ///
86 | public const string AllUser = UserReadEmail + Sep + UserReadPrivate;
87 |
88 | #endregion
89 |
90 | #region Playlists
91 |
92 | ///
93 | /// PlaylistReadCollaborative
94 | ///
95 | public const string PlaylistReadCollaborative = "playlist-read-collaborative";
96 |
97 | ///
98 | /// PlaylistModifyPublic
99 | ///
100 | public const string PlaylistModifyPublic = "playlist-modify-public";
101 |
102 | ///
103 | /// PlaylistReadPrivate
104 | ///
105 | public const string PlaylistReadPrivate = "playlist-read-private";
106 |
107 | ///
108 | /// PlaylistModifyPrivate
109 | ///
110 | public const string PlaylistModifyPrivate = "playlist-modify-private";
111 |
112 | ///
113 | /// All scopes from the Playlist category.
114 | ///
115 | public const string AllPlaylist = PlaylistReadCollaborative + Sep + PlaylistModifyPublic + Sep +
116 | PlaylistReadPrivate + Sep + PlaylistModifyPrivate;
117 | #endregion
118 |
119 | #region Library
120 |
121 | ///
122 | /// UserLibraryModify
123 | ///
124 | public const string UserLibraryModify = "user-library-modify";
125 |
126 | ///
127 | /// UserLibraryRead
128 | ///
129 | public const string UserLibraryRead = "user-library-read";
130 |
131 | ///
132 | /// All scopes from the Library category.
133 | ///
134 | public const string AllLibrary = UserLibraryModify + Sep + UserLibraryRead;
135 |
136 | #endregion
137 |
138 | #region Listening history
139 |
140 | ///
141 | /// UserTopRead
142 | ///
143 | public const string UserTopRead = "user-top-read";
144 |
145 | ///
146 | /// UserReadRecentlyPlayed
147 | ///
148 | public const string UserReadRecentlyPlayed = "user-read-recently-played";
149 |
150 | ///
151 | /// All scopes from the Listening history category.
152 | ///
153 | public const string AllListeningHistory = UserTopRead + Sep + UserReadRecentlyPlayed;
154 | #endregion
155 |
156 | #region Follow
157 |
158 | ///
159 | /// UserFollowRead
160 | ///
161 | public const string UserFollowRead = "user-follow-read";
162 |
163 | ///
164 | /// UserFollowModify
165 | ///
166 | public const string UserFollowModify = "user-follow-modify";
167 |
168 | ///
169 | /// All scopes from the Follow category.
170 | ///
171 | public const string AllFollow = UserFollowRead + Sep + UserFollowModify;
172 |
173 | #endregion
174 |
175 | ///
176 | /// All scopes.
177 | ///
178 | public const string All = AllImages + Sep + AllSpotifyConnect + Sep + AllPlayback + Sep + AllUser + Sep +
179 | AllPlaylist + Sep + AllLibrary + Sep + AllListeningHistory + Sep + AllFollow;
180 |
181 | ///
182 | /// Scope separator for ease of use.
183 | ///
184 | private const string Sep = ScopeSeparator;
185 | }
186 | }
--------------------------------------------------------------------------------
/SpotifyWebApi/Api/Player/IPlayerApi.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Api.Player
2 | {
3 | using System.Collections.Generic;
4 | using System.Threading.Tasks;
5 | using Model;
6 | using Model.Enum;
7 | using Model.Uri;
8 |
9 | ///
10 | /// The player api.
11 | ///
12 | /// These endpoints are in Beta.
13 | public interface IPlayerApi
14 | {
15 | ///
16 | /// Get information about a user’s available devices.
17 | ///
18 | /// A list of available devices.
19 | Task> GetAvailableDevices();
20 |
21 | ///
22 | /// Get information about the user’s current playback state, including track, track progress, and active device.
23 | ///
24 | /// Optional. An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking.
25 | /// The users instance.
26 | Task GetCurrentlyPlayingContext(string market = "");
27 |
28 | ///
29 | /// Get the object currently being played on the user’s Spotify account.
30 | ///
31 | /// Optional. An ISO 3166-1 alpha-2 country code. Provide this parameter if you want to apply Track Relinking.
32 | /// The users object.
33 | Task GetCurrentlyPlaying(string market = "");
34 |
35 | ///
36 | /// Transfer playback to a new device and determine if it should start playing.
37 | ///
38 | /// Required. A list containing the devices on which playback should be started/transferred.
39 | /// NOTE: Although an list is accepted, only a single is currently supported.
40 | /// Optional.
41 | /// True: ensure playback happens on new device.
42 | /// False or not provided: keep the current playback state.
43 | /// A representing the asynchronous operation.
44 | Task TransferPlayback(List devices, bool? play = null);
45 |
46 | ///
47 | /// Start a new context or resume current playback on the user’s active device.
48 | /// TODO: Add offset parameter.
49 | ///
50 | /// Optional. The device this command is targeting. If not supplied, the user's currently active device is the target.
51 | /// Optional. Spotify URI of the context to play. Valid contexts are albums, artists & playlists.
52 | /// Optional. A list of the Spotify track URIs to play.
53 | /// A representing the asynchronous operation.
54 | Task StartPlayback(Device device = null, SpotifyUri contextUri = null, List uris = null);
55 |
56 | ///
57 | /// Pause playback on the user’s account.
58 | ///
59 | /// Optional. The device this command is targeting. If not supplied, the user's currently active device is the target.
60 | /// A representing the asynchronous operation.
61 | Task PausePlayback(Device device = null);
62 |
63 | ///
64 | /// Skips to next track in the user’s queue.
65 | ///
66 | /// Optional. The device this command is targeting. If not supplied, the user's currently active device is the target.
67 | /// A representing the asynchronous operation.
68 | Task Next(Device device = null);
69 |
70 | ///
71 | /// Skips to previous track in the user’s queue.
72 | /// Note that this will ALWAYS skip to the previous track, regardless of the current track’s progress.
73 | /// Returning to the start of the current track should be performed using the function.
74 | ///
75 | /// Optional. The device this command is targeting. If not supplied, the user's currently active device is the target.
76 | /// A representing the asynchronous operation.
77 | Task Previous(Device device = null);
78 |
79 | ///
80 | /// Seeks to the given position in the user’s currently playing track.
81 | ///
82 | /// The position in milliseconds to seek to. 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.
83 | /// Optional. The device this command is targeting. If not supplied, the user's currently active device is the target.
84 | /// A representing the asynchronous operation.
85 | Task Seek(int positionMs, Device device = null);
86 |
87 | ///
88 | /// Set the repeat mode for the user’s playback. Options are repeat-track, repeat-context, and off.
89 | ///
90 | /// The state of repeat.
91 | /// Optional. The device this command is targeting. If not supplied, the user's currently active device is the target.
92 | /// A representing the asynchronous operation.
93 | Task SetRepeat(RepeatState state, Device device = null);
94 |
95 | ///
96 | /// Set the volume for the user’s current playback device.
97 | ///
98 | /// The volume to set. Must be a value from 0 to 100 inclusive.
99 | /// Optional. The device this command is targeting. If not supplied, the user's currently active device is the target.
100 | /// A representing the asynchronous operation.
101 | Task SetVolume(int volumePercent, Device device = null);
102 |
103 | ///
104 | /// Toggle shuffle on or off for user’s playback.
105 | ///
106 | /// True: Shuffle user's playback. False: Do not shuffle user's playback
107 | /// Optional. The device this command is targeting. If not supplied, the user's currently active device is the target.
108 | /// A representing the asynchronous operation.
109 | Task SetShuffle(bool state, Device device = null);
110 | }
111 | }
--------------------------------------------------------------------------------
/SpotifyWebApi/Model/Uri/SpotifyUri.cs:
--------------------------------------------------------------------------------
1 | namespace SpotifyWebApi.Model.Uri
2 | {
3 | using System;
4 | using System.Collections;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Runtime.Serialization;
8 | using Exception;
9 |
10 | ///
11 | /// The class.
12 | ///
13 | [DataContract]
14 | public class SpotifyUri
15 | {
16 | #region Constructor
17 |
18 | ///
19 | /// Initializes a new instance of the class.
20 | ///
21 | /// The URI.
22 | ///
23 | /// Uri was not correct!
24 | /// or
25 | /// Uri was not a spotify uri!
26 | ///
27 | private SpotifyUri(string uri)
28 | {
29 | this.FullUri = uri;
30 |
31 | var split = uri.Split(':');
32 | this.Domain = split[0];
33 |
34 | if (this.Domain.Equals("spotify"))
35 | {
36 | if (split.Length == 5)
37 | {
38 | this.Type = UriType.Playlist;
39 | }
40 | else
41 | {
42 | try
43 | {
44 | this.Type = (UriType)Enum.Parse(typeof(UriType), split[1], true);
45 | }
46 | catch (Exception)
47 | {
48 | throw new InvalidUriException("Uri was not correct!");
49 | }
50 | }
51 |
52 | switch (this.Type)
53 | {
54 | case UriType.User:
55 | this.Id = split[2];
56 | break;
57 | case UriType.Track:
58 | this.Id = split[2];
59 | break;
60 | case UriType.Artist:
61 | this.Id = split[2];
62 | break;
63 | case UriType.Album:
64 | this.Id = split[2];
65 | break;
66 | case UriType.Playlist:
67 | if (split.Length == 5)
68 | {
69 | this.Id = split[4];
70 | }
71 | else
72 | {
73 | this.Id = split[2];
74 | }
75 | break;
76 | case UriType.Local:
77 | break;
78 | }
79 | }
80 | else
81 | {
82 | throw new InvalidUriException($"The provided uri is not a spotify uri (uri: {uri}).");
83 | }
84 | }
85 |
86 | #endregion Constructor
87 |
88 | #region Properties
89 |
90 | ///
91 | /// Gets the domain.
92 | ///
93 | [DataMember]
94 | public string Domain { get; private set; }
95 |
96 | ///
97 | /// Gets the type.
98 | ///
99 | [DataMember]
100 | public UriType Type { get; private set; }
101 |
102 | ///
103 | /// Gets the user identifier.
104 | ///
105 | [DataMember]
106 | [Obsolete("The userId property isn't needed anymore for creating a Playlist Uri.")]
107 | public string UserId { get; private set; }
108 |
109 | ///
110 | /// Gets the identifier.
111 | ///
112 | [DataMember]
113 | public string Id { get; private set; }
114 |
115 | ///
116 | /// Gets the full URI.
117 | ///
118 | [DataMember]
119 | public string FullUri { get; private set; }
120 |
121 | #endregion Properties
122 |
123 | #region Conversion
124 |
125 | ///
126 | /// Implicit operator to convert a string to a .
127 | ///
128 | /// The uri to convert.
129 | public static implicit operator SpotifyUri(string uri)
130 | {
131 | return SpotifyUri.Make(uri);
132 | }
133 |
134 | #endregion Conversion
135 |
136 | #region Methods
137 |
138 | ///
139 | /// Creates a from the given id and type.
140 | ///
141 | /// The id.
142 | /// The .
143 | /// A new instance of .
144 | public static SpotifyUri Make(string id, UriType type)
145 | {
146 | if (string.IsNullOrEmpty(id)) throw new ArgumentException("id is null or empty.");
147 |
148 | switch (type)
149 | {
150 | case UriType.User:
151 | return new SpotifyUri($"spotify:user:{id}");
152 | case UriType.Track:
153 | return new SpotifyUri($"spotify:track:{id}");
154 | case UriType.Artist:
155 | return new SpotifyUri($"spotify:artist:{id}");
156 | case UriType.Album:
157 | return new SpotifyUri($"spotify:album:{id}");
158 | case UriType.Playlist:
159 | return new SpotifyUri($"spotify:playlist:{id}");
160 | case UriType.Local:
161 | throw new NotSupportedException("UriType Local is not supported.");
162 | default:
163 | throw new ArgumentOutOfRangeException(nameof(type), type, null);
164 | }
165 | }
166 |
167 | ///
168 | /// Creates a playlist from the given uri.
169 | ///
170 | /// The user id.
171 | /// The playlist id.
172 | /// A new instance of .
173 | /// Note: this will always be of .
174 | [Obsolete("The userId property isn't needed anymore for creating a Playlist Uri. Users should now just use `Make(string id, UriType type)` or Make(string uri).")]
175 | public static SpotifyUri Make(string userId, string playlistId)
176 | {
177 | if (string.IsNullOrEmpty(userId)) throw new ArgumentException("userId is null or empty.");
178 | if (string.IsNullOrEmpty(playlistId)) throw new ArgumentException("playlistId is null or empty.");
179 |
180 | return new SpotifyUri($"spotify:playlist:{playlistId}");
181 | }
182 |
183 | ///
184 | /// Creates a from the given uri.
185 | ///
186 | /// The spotify uri.
187 | /// A new instance of .
188 | public static SpotifyUri Make(string uri)
189 | {
190 | if (string.IsNullOrEmpty(uri)) throw new ArgumentException("uri is null or empty.");
191 | return new SpotifyUri(uri);
192 | }
193 |
194 | ///
195 | /// Creates a list of s for the given uris.
196 | ///
197 | /// A list of uris.
198 | /// A list of .
199 | public static IList MakeList(params string[] uri)
200 | {
201 | return uri.Select(SpotifyUri.Make).ToList();
202 | }
203 |
204 | ///
205 | public override string ToString() => this.FullUri;
206 |
207 | ///
208 | /// This method is called after the object is completely deserialized. Use it instead of the constructror.
209 | ///
210 | /// The streaming context.
211 | [OnDeserialized]
212 | private void OnDeserialized(StreamingContext context)
213 | {
214 | var i = new SpotifyUri(this.FullUri);
215 | this.Domain = i.Domain;
216 | this.FullUri = i.FullUri;
217 | this.Id = i.Id;
218 | this.Type = i.Type;
219 | #pragma warning disable
220 | this.UserId = i.UserId;
221 | #pragma warning restore
222 | }
223 |
224 | #endregion Methods
225 | }
226 | }
--------------------------------------------------------------------------------