Added support for Spotify's Web API

- New Namespaces
   -> SpotifyAPI.SpotifyLocalAPI
   -> SpotifyAPI.SpotifyWebAPI
   -> SpotifyAPI.SpotifyWebAPI.Models
- Wiki created, examples coming soon
- Added example for the new Web API
- README updated
This commit is contained in:
Johnny @PC 2014-07-20 22:42:46 +02:00
parent ba03b3cd90
commit 0b78f12df3
45 changed files with 1680 additions and 200 deletions

160
README.md
View File

@ -10,162 +10,4 @@ Following 3 files will be needed for all features:
+ nircmd.dll (Used to Mute & UnMute Spotify) + nircmd.dll (Used to Mute & UnMute Spotify)
Screenshot of the Example: Screenshot of the Example:
![alt text](http://i.imgur.com/R9Xsma0.png "Example Screen") ![alt text](http://i.imgur.com/R9Xsma0.png "Example Screen")
Update:
===
This API will also support the "new" Spotify Web API soon, following things will be possible:
(Ticked = implemented and ready to push,Not ticked = Work in Progress)
- [ ] Get an Album
- [ ] Get Several Albums
- [ ] Get an Album'S Tracks
- [ ] Get an Artist
- [ ] Get Several Artists
- [ ] Get an Artist's Albums
- [ ] Get an Artist's Top Tracks
- [ ] Get an Artist'S Related Artists
- [ ] Get a Track
- [ ] Get several Tracks
- [ ] Search for an Item
- [x] Get a User's Profile
- [x] Get Current Users Profile
- [x] Get a List of a User's Profile
- [x] Get a Playlist
- [x] Get a Playlist's Tracks
- [ ] Create a Playlist
- [ ] Add Tracks to a Playlist
With this Update, there will be 2 new/modified namespaces:
> SpotifyAPI.SpotifyLocalAPI (Old local API)
> SpotifyAPI.SpotifyWebAPI (New web API)
___
Usage:
==============
### SpotifyAPI
#####Boolean Connect()
> Connects the SpotifyAPI to the Spotify Client (Needs to be called before making calls, Spotify has to run)
> Returns true if it was successful
#####void Update()
> Updates Information about Tracks etc.
#####void RunSpotify()
> Runs Spotify (Client has to run for API Calls)
#####void RunSpotifyWebHelper()
> Runs SpotifyWebHelper (Client has to run for API Calls)
#####static Boolean IsSpotifyRunning()
> Returns true, if Spotify is running
#####static Boolean IsSpotifyWebHelperRunning()
> Returns true, if SpotifyWebHelper is running
#####static Boolean IsValidSpotifyURL(String SpotifyURL)
> Returns true, if the provided Spotify URL is working (Not working yet)
#####[SpotifyMusicHandler](https://github.com/JohnnyCrazy/SpotifyAPI-NET#spotifymusichandler) GetMusicHandler()
> Returns the MusicHandler
#####[SpotifyEventHandler](https://github.com/JohnnyCrazy/SpotifyAPI-NET#spotifyeventhandler) GetEventHandler()
> Returns the EventHandler
### SpotifyMusicHandler
#####void Play()
> Play "button"
#####void Pause()
> Pause "button"
#####void Skip()
> Skip Track
#####void Previous()
> Previous Track
#####void PlayURL(String SpotifyURI)
> Plays the provided URI
#####double GetVolume()
> Returns the current volume (0.00 - 1.00)
#####Boolean IsAdRunning()
> Returns true, if an AD is running
#####double GetTrackPostion()
> Returns the current position of the Track
#####void Mute()
> Mutes Spotify (Requires nircmd.dll)
#####void UnMute()
> Unmutes Spotify (Requires nircmd.dll
#####Boolean IsPlaying()
> Returns true, if Spotify is playing atm
#####[Track](https://github.com/JohnnyCrazy/SpotifyAPI-NET#track) GetCurrentTrack()
> Returns the current Track
#####StatusResponse GetStatusResponse()
> Returns the StatusResponse, which contains all Information gathered by the Call (Should not be used at all)
### SpotifyEventHandler
#####Event OnTrackChange
> Triggered, when the Track gets changed
#####Event OnPlayStateChange
> Triggered, when Spotify's Play/Pause-State changes
#####Event OnVolumeChange
> Triggered, when the volume gets changed
#####Event TrackTimeChangeEventHandler
> Triggered, when the current trackposition changes
#####void ListenForEvents(Boolean listen)
> Should it listen for events?
#####void SetSynchronizingObject(ISynchronizeInvoke obj)
> Sets the synced object, so no Invoke is required (Events doesnt get called from the Main-Thread)
### Track
#####String GetTrackName()
> Returns Track-name
#####String GetArtistName()
> Returns Artist-name
#####String GetAlbumName()
> Returns Album-name
#####int GetLength()
> Returns the Track lenght
#####String GetAlbumURI()
> Returns the URI for the album
#####String GetTrackURI()
> Returns the URI for the Track
#####String GetArtistURI()
> Returns the URI for the Artist
#####String GetAlbumArtURL(AlbumArtSize size)
> Returns the URL of the Albumart based on the choosen size
#####Bitmap GetAlbumArt(AlbumArtSize size)
> Returns a Bitmap of the Albumart based on the choosen size
#####Bitmap GetAlbumArtAsync(AlbumArtSize size)
> Returns a Bitmap of the Albumart based on the choosen size asynchronously

View File

@ -1,10 +1,12 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013 # Visual Studio 2013
VisualStudioVersion = 12.0.21005.1 VisualStudioVersion = 12.0.30324.0
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpotifyAPI", "SpotifyAPI\SpotifyAPI.csproj", "{EBBE35E2-7B91-4D7D-B8FC-3A0472F5119D}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpotifyAPI", "SpotifyAPI\SpotifyAPI.csproj", "{EBBE35E2-7B91-4D7D-B8FC-3A0472F5119D}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpotifyWebAPIExample", "SpotifyWebAPIExample\SpotifyWebAPIExample.csproj", "{004B45C3-BB98-4E62-AD11-D80BA64FEB8E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpotifyAPI_Example", "SpotifyAPI_Example\SpotifyAPI_Example.csproj", "{C12D46F9-BB35-46D6-B821-522B8F9C3CBE}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpotifyAPI_Example", "SpotifyAPI_Example\SpotifyAPI_Example.csproj", "{C12D46F9-BB35-46D6-B821-522B8F9C3CBE}"
EndProject EndProject
Global Global
@ -17,6 +19,10 @@ Global
{EBBE35E2-7B91-4D7D-B8FC-3A0472F5119D}.Debug|Any CPU.Build.0 = Debug|Any CPU {EBBE35E2-7B91-4D7D-B8FC-3A0472F5119D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EBBE35E2-7B91-4D7D-B8FC-3A0472F5119D}.Release|Any CPU.ActiveCfg = Release|Any CPU {EBBE35E2-7B91-4D7D-B8FC-3A0472F5119D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EBBE35E2-7B91-4D7D-B8FC-3A0472F5119D}.Release|Any CPU.Build.0 = Release|Any CPU {EBBE35E2-7B91-4D7D-B8FC-3A0472F5119D}.Release|Any CPU.Build.0 = Release|Any CPU
{004B45C3-BB98-4E62-AD11-D80BA64FEB8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{004B45C3-BB98-4E62-AD11-D80BA64FEB8E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{004B45C3-BB98-4E62-AD11-D80BA64FEB8E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{004B45C3-BB98-4E62-AD11-D80BA64FEB8E}.Release|Any CPU.Build.0 = Release|Any CPU
{C12D46F9-BB35-46D6-B821-522B8F9C3CBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C12D46F9-BB35-46D6-B821-522B8F9C3CBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C12D46F9-BB35-46D6-B821-522B8F9C3CBE}.Debug|Any CPU.Build.0 = Debug|Any CPU {C12D46F9-BB35-46D6-B821-522B8F9C3CBE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C12D46F9-BB35-46D6-B821-522B8F9C3CBE}.Release|Any CPU.ActiveCfg = Release|Any CPU {C12D46F9-BB35-46D6-B821-522B8F9C3CBE}.Release|Any CPU.ActiveCfg = Release|Any CPU

View File

@ -5,11 +5,11 @@ using System.Runtime.InteropServices;
// Allgemeine Informationen über eine Assembly werden über die folgenden // Allgemeine Informationen über eine Assembly werden über die folgenden
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, // Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
// die mit einer Assembly verknüpft sind. // die mit einer Assembly verknüpft sind.
[assembly: AssemblyTitle("SpotifyAPI")] [assembly: AssemblyTitle("SpotifyLocalAPIClass")]
[assembly: AssemblyDescription("")] [assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")] [assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SpotifyAPI")] [assembly: AssemblyProduct("SpotifyLocalAPIClass")]
[assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
namespace SpotifyAPIv1 namespace SpotifyAPI.SpotifyLocalAPI
{ {
/// <summary> /// <summary>
/// JSON Response, used internaly /// JSON Response, used internaly

View File

@ -1,7 +1,7 @@
using System; using System;
using System.Text; using System.Text;
namespace SpotifyAPIv1 namespace SpotifyAPI.SpotifyLocalAPI
{ {
/// <summary> /// <summary>
/// Enum for the AlbumArt /// Enum for the AlbumArt

View File

@ -1,7 +1,7 @@
using System; using System;
using System.Text; using System.Text;
namespace SpotifyAPIv1 namespace SpotifyAPI.SpotifyLocalAPI
{ {
/// <summary> /// <summary>
/// Event gets triggered, when the Track is changed /// Event gets triggered, when the Track is changed

View File

@ -5,7 +5,7 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Net; using System.Net;
namespace SpotifyAPIv1 namespace SpotifyAPI.SpotifyLocalAPI
{ {
class ExtendedWebClient : WebClient class ExtendedWebClient : WebClient
{ {

View File

@ -7,7 +7,7 @@ using System.Threading.Tasks;
using System.Threading; using System.Threading;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace SpotifyAPIv1 namespace SpotifyAPI.SpotifyLocalAPI
{ {
class RemoteHandler class RemoteHandler
{ {
@ -119,7 +119,7 @@ namespace SpotifyAPIv1
try try
{ {
//Need to find a better solution //Need to find a better solution
if (SpotifyAPI.IsSpotifyRunning()) if (SpotifyLocalAPIClass.IsSpotifyRunning())
response = "[ " + wc.DownloadString(a) + " ]"; response = "[ " + wc.DownloadString(a) + " ]";
} }
catch (Exception z) catch (Exception z)

View File

@ -4,14 +4,14 @@ using Newtonsoft.Json;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Diagnostics; using System.Diagnostics;
namespace SpotifyAPIv1 namespace SpotifyAPI.SpotifyLocalAPI
{ {
public class SpotifyAPI public class SpotifyLocalAPIClass
{ {
SpotifyMusicHandler mh; SpotifyMusicHandler mh;
RemoteHandler rh; RemoteHandler rh;
SpotifyEventHandler eh; SpotifyEventHandler eh;
public SpotifyAPI() public SpotifyLocalAPIClass()
{ {
rh = RemoteHandler.GetInstance(); rh = RemoteHandler.GetInstance();
mh = new SpotifyMusicHandler(); mh = new SpotifyMusicHandler();
@ -21,6 +21,7 @@ namespace SpotifyAPIv1
/// <summary> /// <summary>
/// Connects with Spotify. Needs to be called before all other SpotifyAPI functions /// Connects with Spotify. Needs to be called before all other SpotifyAPI functions
/// </summary> /// </summary>
/// <returns>Returns true, if it was successful, false if not</returns>
public Boolean Connect() public Boolean Connect()
{ {
return rh.Init(); return rh.Init();
@ -95,7 +96,7 @@ namespace SpotifyAPIv1
/// </summary> /// </summary>
public void Update() public void Update()
{ {
if (!SpotifyAPI.IsSpotifyWebHelperRunning() || !SpotifyAPI.IsSpotifyRunning()) if (!SpotifyLocalAPIClass.IsSpotifyWebHelperRunning() || !SpotifyLocalAPIClass.IsSpotifyRunning())
return; return;
mh.Update(rh.Update()); mh.Update(rh.Update());
} }

View File

@ -2,15 +2,15 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using SpotifyAPIv1; using SpotifyAPI.SpotifyLocalAPI;
namespace SpotifyAPIv1 namespace SpotifyAPI.SpotifyLocalAPI
{ {
public class SpotifyEventHandler public class SpotifyEventHandler
{ {
private Boolean listen = false; private Boolean listen = false;
private System.Timers.Timer timer; private System.Timers.Timer timer;
private SpotifyAPI api; private SpotifyLocalAPIClass api;
private SpotifyMusicHandler mh; private SpotifyMusicHandler mh;
private StatusResponse response; private StatusResponse response;
@ -24,7 +24,7 @@ namespace SpotifyAPIv1
public event VolumeChangeEventHandler OnVolumeChange; public event VolumeChangeEventHandler OnVolumeChange;
public event TrackTimeChangeEventHandler OnTrackTimeChange; public event TrackTimeChangeEventHandler OnTrackTimeChange;
public SpotifyEventHandler(SpotifyAPI api, SpotifyMusicHandler mh) public SpotifyEventHandler(SpotifyLocalAPIClass api, SpotifyMusicHandler mh)
{ {
timer = new System.Timers.Timer(); timer = new System.Timers.Timer();
timer.Interval = 50; timer.Interval = 50;

View File

@ -6,7 +6,7 @@ using System.Runtime.InteropServices;
using System.Windows.Forms; using System.Windows.Forms;
using System.IO; using System.IO;
namespace SpotifyAPIv1 namespace SpotifyAPI.SpotifyLocalAPI
{ {
public class SpotifyMusicHandler public class SpotifyMusicHandler
{ {
@ -56,7 +56,7 @@ namespace SpotifyAPIv1
/// <summary> /// <summary>
/// Plays a Spotify URI /// Plays a Spotify URI
/// </summary> /// </summary>
/// <param name="uri">The Spotify URI. Can be checked with <seealso cref="SpotifyAPI.IsValidSpotifyURI"/></param> /// <param name="uri">The Spotify URI. Can be checked with <seealso cref="SpotifyLocalAPIClass.IsValidSpotifyURI"/></param>
public void PlayURL(String uri) public void PlayURL(String uri)
{ {
rh.SendPlayRequest(uri); rh.SendPlayRequest(uri);

View File

@ -3,7 +3,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace SpotifyAPIv1 namespace SpotifyAPI.SpotifyLocalAPI
{ {
public class StatusResponse public class StatusResponse
{ {

View File

@ -6,7 +6,7 @@ using System.Drawing;
using System.Net; using System.Net;
using System.IO; using System.IO;
namespace SpotifyAPIv1 namespace SpotifyAPI.SpotifyLocalAPI
{ {
public class Track public class Track
{ {

View File

@ -7,7 +7,7 @@
<ProjectGuid>{EBBE35E2-7B91-4D7D-B8FC-3A0472F5119D}</ProjectGuid> <ProjectGuid>{EBBE35E2-7B91-4D7D-B8FC-3A0472F5119D}</ProjectGuid>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SpotifyAPIv1</RootNamespace> <RootNamespace>SpotifyAPI.SpotifyLocalAPI</RootNamespace>
<AssemblyName>SpotifyAPI</AssemblyName> <AssemblyName>SpotifyAPI</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
@ -38,6 +38,7 @@
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Drawing" /> <Reference Include="System.Drawing" />
<Reference Include="System.Web" />
<Reference Include="System.Windows.Forms" /> <Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Data.DataSetExtensions" />
@ -46,23 +47,49 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="CFID.cs" /> <Compile Include="SpoitfyLocalAPI\CFID.cs" />
<Compile Include="Enum.cs" /> <Compile Include="SpoitfyLocalAPI\Enum.cs" />
<Compile Include="ExtendedWebClient.cs"> <Compile Include="SpoitfyLocalAPI\ExtendedWebClient.cs">
<SubType>Component</SubType> <SubType>Component</SubType>
</Compile> </Compile>
<Compile Include="SpotifyEventHandler.cs" /> <Compile Include="SpoitfyLocalAPI\SpotifyEventHandler.cs" />
<Compile Include="Events.cs" /> <Compile Include="SpoitfyLocalAPI\Events.cs" />
<Compile Include="SpotifyMusicHandler.cs" /> <Compile Include="SpoitfyLocalAPI\SpotifyMusicHandler.cs" />
<Compile Include="RemoteHandler.cs" /> <Compile Include="SpoitfyLocalAPI\RemoteHandler.cs" />
<Compile Include="SpotifyAPI.cs" /> <Compile Include="SpoitfyLocalAPI\SpotifyAPI.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="StatusResponse.cs" /> <Compile Include="SpoitfyLocalAPI\StatusResponse.cs" />
<Compile Include="Track.cs" /> <Compile Include="SpoitfyLocalAPI\Track.cs" />
<Compile Include="SpotifyWebAPI\AlbumType.cs" />
<Compile Include="SpotifyWebAPI\AutorizationCodeAuth.cs" />
<Compile Include="SpotifyWebAPI\ClientCredentialsAuth.cs" />
<Compile Include="SpotifyWebAPI\ImplicitGrantAuth.cs" />
<Compile Include="SpotifyWebAPI\Models\BasicModel.cs" />
<Compile Include="SpotifyWebAPI\Models\FullAlbum.cs" />
<Compile Include="SpotifyWebAPI\Models\FullArtist.cs" />
<Compile Include="SpotifyWebAPI\Models\FullTrack.cs" />
<Compile Include="SpotifyWebAPI\Models\SearchItem.cs" />
<Compile Include="SpotifyWebAPI\Models\PrivateProfile.cs" />
<Compile Include="SpotifyWebAPI\Models\GeneralModels.cs" />
<Compile Include="SpotifyWebAPI\Models\FullPlaylist.cs" />
<Compile Include="SpotifyWebAPI\Models\PublicProfile.cs" />
<Compile Include="SpotifyWebAPI\Models\SimpleAlbum.cs" />
<Compile Include="SpotifyWebAPI\Models\SimpleArtist.cs" />
<Compile Include="SpotifyWebAPI\Models\SimpleTrack.cs" />
<Compile Include="SpotifyWebAPI\Models\Token.cs" />
<Compile Include="SpotifyWebAPI\Models\SimplePlaylist.cs" />
<Compile Include="SpotifyWebAPI\Models\Paging.cs" />
<Compile Include="SpotifyWebAPI\Scope.cs" />
<Compile Include="SpotifyWebAPI\SearchType.cs" />
<Compile Include="SpotifyWebAPI\SimpleHttpServer.cs" />
<Compile Include="SpotifyWebAPI\SpotifyWebAPIClass.cs" />
<Compile Include="SpotifyWebAPI\StringAttribute.cs" />
<Compile Include="SpotifyWebAPI\Util.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="app.config" /> <None Include="app.config" />
</ItemGroup> </ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SpotifyAPI.SpotifyWebAPI
{
[Flags]
public enum AlbumType
{
[StringAttribute("album")]
ALBUM = 1,
[StringAttribute("single")]
SINGLE = 2,
[StringAttribute("compilation")]
COMPILATION = 4,
[StringAttribute("appears_on")]
APPEARS_ON = 8,
[StringAttribute("album,single,compilation,appears_on")]
ALL = 16
}
}

View File

@ -0,0 +1,124 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Threading.Tasks;
using System.Threading;
using System.Diagnostics;
using System.Collections.Specialized;
using Newtonsoft.Json;
using SpotifyAPI.SpotifyWebAPI.Models;
using System.IO;
namespace SpotifyAPI.SpotifyWebAPI
{
public class AutorizationCodeAuth
{
public String ClientId { get; set; }
public String RedirectUri { get; set; }
public String State { get; set; }
public Scope Scope { get; set; }
public Boolean ShowDialog { get; set; }
Thread httpThread;
SimpleHttpServer httpServer;
public delegate void OnResponseReceived(AutorizationCodeAuthResponse response);
public event OnResponseReceived OnResponseReceivedEvent;
public void DoAuth()
{
String uri = GetUri();
Process.Start(uri);
}
/// <summary>
/// Also don't use this, you would need to provide your clientSecretKey
/// </summary>
/// <param name="refreshToken"></param>
/// <param name="clientId"></param>
/// <param name="clientSecret"></param>
public Token RefreshToken(String refreshToken,String clientSecret)
{
using(WebClient wc = new WebClient())
{
wc.Proxy = null;
wc.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(ClientId + ":" + clientSecret)));
NameValueCollection col = new NameValueCollection();
col.Add("grant_type", "refresh_token");
col.Add("refresh_token", refreshToken);
String response = "";
try
{
byte[] data = wc.UploadValues("https://accounts.spotify.com/api/token", "POST", col);
response = Encoding.UTF8.GetString(data);
}catch(WebException e)
{
response = new StreamReader(e.Response.GetResponseStream()).ReadToEnd();
}
return JsonConvert.DeserializeObject<Token>(response);
}
}
private String GetUri()
{
StringBuilder builder = new StringBuilder("https://accounts.spotify.com/authorize/?");
builder.Append("client_id=" + ClientId);
builder.Append("&response_type=code");
builder.Append("&redirect_uri=" + RedirectUri);
builder.Append("&state=" + State);
builder.Append("&scope=" + Scope.GetScopeValue(" "));
builder.Append("&show_dialog=" + ShowDialog.ToString());
return builder.ToString();
}
public void StartHttpServer()
{
httpServer = new SimpleHttpServer(80, SetResponse,AuthType.AUTHORIZATION);
httpThread = new Thread(httpServer.listen); ;
httpThread.Start();
}
public void SetResponse(String code,String state,String error)
{
if (OnResponseReceivedEvent != null)
OnResponseReceivedEvent(new AutorizationCodeAuthResponse() { Code = code, State = state, Error = error });
}
public void StopHttpServer()
{
httpServer = null;
}
/// <summary>
/// Don't use this!!! Use a PHP-Script or sth...
/// </summary>
public Token ExchangeAuthCode(String code,String clientSecret)
{
using(WebClient wc = new WebClient())
{
wc.Proxy = null;
NameValueCollection col = new NameValueCollection();
col.Add("grant_type","authorization_code");
col.Add("code",code);
col.Add("redirect_uri", RedirectUri);
col.Add("client_id", ClientId);
col.Add("client_secret", clientSecret);
String response = "";
try
{
byte[] data = wc.UploadValues("https://accounts.spotify.com/api/token", "POST", col);
response = Encoding.UTF8.GetString(data);
}catch(WebException e)
{
response = new StreamReader(e.Response.GetResponseStream()).ReadToEnd();
}
return JsonConvert.DeserializeObject<Token>(response);
}
}
}
public struct AutorizationCodeAuthResponse
{
public String Code { get; set; }
public String State { get; set; }
public String Error { get; set; }
}
}

View File

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net;
using System.Collections.Specialized;
using Newtonsoft.Json;
using SpotifyAPI.SpotifyWebAPI.Models;
using System.IO;
namespace SpotifyAPI.SpotifyWebAPI
{
public class ClientCredentialsAuth
{
public Scope Scope { get; set; }
public String ClientId { get; set; }
public String ClientSecret { get; set; }
public Token DoAuth()
{
using(WebClient wc = new WebClient())
{
wc.Proxy = null;
wc.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(ClientId + ":" + ClientSecret)));
NameValueCollection col = new NameValueCollection();
col.Add("grant_type","client_credentials");
col.Add("scope", Scope.GetScopeValue(" "));
byte[] data = null;
try
{
data = wc.UploadValues("https://accounts.spotify.com/api/token", "POST", col);
}catch(WebException e)
{
String test = new StreamReader(e.Response.GetResponseStream()).ReadToEnd();
}
return JsonConvert.DeserializeObject<Token>(Encoding.UTF8.GetString(data));
}
}
}
}

View File

@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO;
using SpotifyAPI.SpotifyWebAPI.Models;
using Newtonsoft.Json;
using System.Diagnostics;
namespace SpotifyAPI.SpotifyWebAPI
{
public class ImplicitGrantAuth
{
public String ClientId { get; set; }
public String RedirectUri { get; set; }
public String State { get; set; }
public Scope Scope { get; set; }
public Boolean ShowDialog { get; set; }
Thread httpThread;
SimpleHttpServer httpServer;
public delegate void OnResponseReceived(Token token,String state,String error);
public event OnResponseReceived OnResponseReceivedEvent;
public void DoAuth()
{
String uri = GetUri();
Process.Start(uri);
}
private String GetUri()
{
StringBuilder builder = new StringBuilder("https://accounts.spotify.com/authorize/?");
builder.Append("client_id=" + ClientId);
builder.Append("&response_type=token");
builder.Append("&redirect_uri=" + RedirectUri);
builder.Append("&state=" + State);
builder.Append("&scope=" + Scope.GetScopeValue(" "));
builder.Append("&show_dialog=" + ShowDialog.ToString());
return builder.ToString();
}
public void StartHttpServer()
{
httpServer = new SimpleHttpServer(80, SetResponse, AuthType.IMPLICIT);
httpThread = new Thread(httpServer.listen); ;
httpThread.Start();
}
public void SetResponse(String accessToken, String tokenType, int expiresIn,String state, String error)
{
if (OnResponseReceivedEvent != null)
OnResponseReceivedEvent(new Token()
{
AccessToken = accessToken,
TokenType = tokenType,
ExpiresIn = expiresIn
},state,error);
}
public void StopHttpServer()
{
try
{
httpThread.Abort();
}catch(ThreadAbortException e)
{
}
httpServer = null;
}
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace SpotifyAPI.SpotifyWebAPI.Models
{
public abstract class BasicModel
{
[JsonProperty("error")]
public Error Error { get; set; }
public Boolean HasError()
{
return Error != null;
}
}
}

View File

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace SpotifyAPI.SpotifyWebAPI.Models
{
public class FullAlbum : BasicModel
{
[JsonProperty("album_type")]
public String AlbumType { get; set; }
[JsonProperty("artists")]
public List<SimpleArtist> Artists { get; set; }
[JsonProperty("available_markets")]
public List<String> AvailableMarkets { get; set; }
[JsonProperty("external_ids")]
public Dictionary<String, String> ExternalIds { get; set; }
[JsonProperty("external_urls")]
public Dictionary<String, String> ExternalUrls { get; set; }
[JsonProperty("genres")]
public List<String> Genres { get; set; }
[JsonProperty("href")]
public String Href { get; set; }
[JsonProperty("id")]
public String Id { get; set; }
[JsonProperty("images")]
public List<Image> Images { get; set; }
[JsonProperty("name")]
public String Name { get; set; }
[JsonProperty("popularity")]
public int Popularity { get; set; }
[JsonProperty("release_date")]
public DateTime ReleaseDate { get; set; }
[JsonProperty("release_date_precision")]
public String ReleaseDatePrecision { get; set; }
[JsonProperty("tracks")]
public Paging<SimpleTrack> Tracks { get; set; }
[JsonProperty("type")]
public String Type { get; set; }
[JsonProperty("uri")]
public String Uri { get; set; }
}
}

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace SpotifyAPI.SpotifyWebAPI.Models
{
public class FullArtist : BasicModel
{
[JsonProperty("external_urls")]
public Dictionary<String, String> ExternalUrls { get; set; }
[JsonProperty("genres")]
public List<String> Genres { get; set; }
[JsonProperty("href")]
public String Href { get; set; }
[JsonProperty("id")]
public String Id { get; set; }
[JsonProperty("images")]
public List<Image> Images { get; set; }
[JsonProperty("name")]
public String Name { get; set; }
[JsonProperty("popularity")]
public int Popularity { get; set; }
[JsonProperty("type")]
public String Type { get; set; }
[JsonProperty("uri")]
public String Uri { get; set; }
}
}

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace SpotifyAPI.SpotifyWebAPI.Models
{
public class FullPlaylist : BasicModel
{
[JsonProperty("collaborative")]
public Boolean Collaborative { get; set; }
[JsonProperty("description")]
public String Description { get; set; }
[JsonProperty("external_urls")]
public Dictionary<string, string> ExternalUrls { get; set; }
[JsonProperty("followers")]
public Followers Followers { get; set; }
[JsonProperty("href")]
public String Href { get; set; }
[JsonProperty("id")]
public String Id { get; set; }
[JsonProperty("images")]
public List<Image> Images { get; set; }
[JsonProperty("name")]
public String Name { get; set; }
[JsonProperty("owner")]
public PublicProfile Owner { get; set; }
[JsonProperty("public")]
public Boolean Public { get; set; }
[JsonProperty("tracks")]
public Paging<PlaylistTrack> Tracks { get; set; }
[JsonProperty("type")]
public String Type { get; set; }
[JsonProperty("uri")]
public String Uri { get; set; }
}
}

View File

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace SpotifyAPI.SpotifyWebAPI.Models
{
public class FullTrack : BasicModel
{
/// <summary>
/// Simple-Album object of the track @<see cref="Paging"/>
/// </summary>
[JsonProperty("album")]
public SimpleAlbum Album { get; set; }
[JsonProperty("artist")]
public SimpleArtist Artist { get; set; }
[JsonProperty("available_markets")]
public List<String> AvailableMarkets { get; set; }
[JsonProperty("disc_number")]
public int DiscNumber { get; set; }
[JsonProperty("duration_ms")]
public int DurationMs { get; set; }
[JsonProperty("explicit")]
public Boolean Explicit { get; set; }
[JsonProperty("external_ids")]
public Dictionary<String, String> ExternalIds { get; set; }
[JsonProperty("external_urls")]
public Dictionary<String, String> ExternUrls { get; set; }
[JsonProperty("href")]
public String Href { get; set; }
[JsonProperty("id")]
public String Id { get; set; }
[JsonProperty("name")]
public String Name { get; set; }
[JsonProperty("popularity")]
public int Popularity { get; set; }
[JsonProperty("preview_url")]
public String PreviewUrl { get; set; }
[JsonProperty("track_number")]
public int TrackNumber { get; set; }
[JsonProperty("type")]
public String Type { get; set; }
[JsonProperty("uri")]
public String Uri { get; set; }
}
}

View File

@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace SpotifyAPI.SpotifyWebAPI.Models
{
public class Image
{
[JsonProperty("url")]
public String Url { get; set; }
[JsonProperty("width")]
public int Width { get; set; }
[JsonProperty("height")]
public int Height { get; set; }
}
public class Error
{
[JsonProperty("status")]
public int Status { get; set; }
[JsonProperty("message")]
public String Message { get; set; }
}
public class PlaylistTrackCollection
{
[JsonProperty("href")]
public String Href { get; set; }
[JsonProperty("total")]
public int Total { get; set; }
}
public class Followers
{
[JsonProperty("href")]
public String Href { get; set; }
[JsonProperty("total")]
public int Total { get; set; }
}
public class PlaylistTrack
{
[JsonProperty("added_at")]
public DateTime AddedAt { get; set; }
[JsonProperty("added_by")]
public PublicProfile AddedBy { get; set; }
[JsonProperty("track")]
public FullTrack Track { get; set; }
}
internal class CreatePlaylistArgs
{
[JsonProperty("name")]
public String Name { get; set; }
[JsonProperty("public")]
public Boolean Public { get; set; }
}
public class SeveralTracks
{
[JsonProperty("tracks")]
public List<FullTrack> Tracks { get; set; }
}
public class SeveralArtists
{
[JsonProperty("artists")]
public List<FullArtist> Artists { get; set; }
}
public class SeveralAlbums
{
[JsonProperty("albums")]
public List<FullAlbum> Albums { get; set; }
}
}

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace SpotifyAPI.SpotifyWebAPI.Models
{
public class Paging<T> : BasicModel
{
[JsonProperty("href")]
public String Href { get; set; }
[JsonProperty("items")]
public List<T> Items { get; set; }
[JsonProperty("limit")]
public int Limit { get; set; }
[JsonProperty("next")]
public String Next { get; set; }
[JsonProperty("offset")]
public int Offset { get; set; }
[JsonProperty("previous")]
public String Previous { get; set; }
[JsonProperty("total")]
public int Total { get; set; }
}
}

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace SpotifyAPI.SpotifyWebAPI.Models
{
public class PrivateProfile : BasicModel
{
[JsonProperty("country")]
public String Country { get; set; }
[JsonProperty("display_name")]
public String DisplayName { get; set; }
[JsonProperty("external_urls")]
public Dictionary<string, string> ExternalUrls { get; set; }
[JsonProperty("href")]
public String Href { get; set; }
[JsonProperty("id")]
public String Id { get; set; }
[JsonProperty("images")]
public List<Image> Images { get; set; }
[JsonProperty("product")]
public String Product { get; set; }
[JsonProperty("type")]
public String Type { get; set; }
[JsonProperty("uri")]
public String Uri { get; set; }
}
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace SpotifyAPI.SpotifyWebAPI.Models
{
public class PublicProfile : BasicModel
{
[JsonProperty("external_urls")]
public Dictionary<string, string> ExternalUrls { get; set; }
[JsonProperty("href")]
public String Href { get; set; }
[JsonProperty("id")]
public String Id { get; set; }
[JsonProperty("type")]
public String Type { get; set; }
[JsonProperty("uri")]
public String Uri { get; set; }
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace SpotifyAPI.SpotifyWebAPI.Models
{
public class SearchItem : BasicModel
{
[JsonProperty("artists")]
public Paging<SimpleArtist> Artists { get; set; }
[JsonProperty("albums")]
public Paging<SimpleAlbum> Albums { get; set; }
[JsonProperty("tracks")]
public Paging<FullTrack> Tracks { get; set; }
}
}

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace SpotifyAPI.SpotifyWebAPI.Models
{
public class SimpleAlbum : BasicModel
{
[JsonProperty("album_type")]
public String AlbumType { get; set; }
[JsonProperty("available_markets")]
public List<String> AvailableMarkets { get; set; }
[JsonProperty("external_urls")]
public Dictionary<String, String> ExternalUrls { get; set; }
[JsonProperty("href")]
public String Href { get; set; }
[JsonProperty("id")]
public String Id { get; set; }
[JsonProperty("images")]
public List<Image> Images { get; set; }
[JsonProperty("name")]
public String Name { get; set; }
[JsonProperty("type")]
public String Type { get; set; }
[JsonProperty("uri")]
public String Uri { get; set; }
}
}

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace SpotifyAPI.SpotifyWebAPI.Models
{
public class SimpleArtist : BasicModel
{
[JsonProperty("external_urls")]
public Dictionary<String, String> ExternalUrls { get; set; }
[JsonProperty("href")]
public String Href { get; set; }
[JsonProperty("id")]
public String Id { get; set; }
[JsonProperty("name")]
public String Name { get; set; }
[JsonProperty("type")]
public String Type { get; set; }
[JsonProperty("uri")]
public String Uri { get; set; }
}
}

View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace SpotifyAPI.SpotifyWebAPI.Models
{
public class SimplePlaylist : BasicModel
{
[JsonProperty("collaborative")]
public Boolean Collaborative { get; set; }
[JsonProperty("external_urls")]
public Dictionary<string, string> ExternalUrls { get; set; }
[JsonProperty("href")]
public String Href { get; set; }
[JsonProperty("id")]
public String Id { get; set; }
[JsonProperty("name")]
public String Name { get; set; }
[JsonProperty("owner")]
public PublicProfile Owner { get; set; }
[JsonProperty("public")]
public Boolean Public { get; set; }
[JsonProperty("tracks")]
public PlaylistTrackCollection Tracks { get; set; }
[JsonProperty("type")]
public String Type { get; set; }
[JsonProperty("uri")]
public String Uri { get; set; }
}
}

View File

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace SpotifyAPI.SpotifyWebAPI.Models
{
public class SimpleTrack : BasicModel
{
[JsonProperty("artist")]
public SimpleArtist Artist { get; set; }
[JsonProperty("disc_number")]
public int DiscNumber { get; set; }
[JsonProperty("duration_ms")]
public int DurationMs { get; set; }
[JsonProperty("explicit")]
public Boolean Explicit { get; set; }
[JsonProperty("external_urls")]
public Dictionary<String, String> ExternUrls { get; set; }
[JsonProperty("href")]
public String Href { get; set; }
[JsonProperty("id")]
public String Id { get; set; }
[JsonProperty("name")]
public String Name { get; set; }
[JsonProperty("preview_url")]
public String PreviewUrl { get; set; }
[JsonProperty("track_number")]
public int TrackNumber { get; set; }
[JsonProperty("type")]
public String Type { get; set; }
[JsonProperty("uri")]
public String Uri { get; set; }
}
}

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace SpotifyAPI.SpotifyWebAPI.Models
{
public class Token
{
[JsonProperty("access_token")]
public String AccessToken { get; set; }
[JsonProperty("token_type")]
public String TokenType { get; set; }
[JsonProperty("expires_in")]
public int ExpiresIn { get; set; }
[JsonProperty("refresh_token")]
public String RefreshToken { get; set; }
[JsonProperty("error")]
public String Error { get; set; }
[JsonProperty("error_description")]
public String ErrorDescription { get; set; }
public DateTime CreateDate { get; set; }
public Token()
{
CreateDate = DateTime.Now;
}
public Boolean IsExpired()
{
return CreateDate.Add(TimeSpan.FromSeconds(ExpiresIn)) >= DateTime.Now;
}
}
}

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SpotifyAPI.SpotifyWebAPI
{
[Flags]
public enum Scope
{
[StringAttribute("")]
NONE = 1,
[StringAttribute("playlist-modify")]
PLAYLIST_MODIFY = 2,
[StringAttribute("playlist-modify-private")]
PLAYLIST_MODIFY_PRIVATE = 4,
[StringAttribute("playlist-read-private")]
PLAYLIST_READ_PRIVATE = 8,
[StringAttribute("streaming")]
STREAMING = 16,
[StringAttribute("user-read-private")]
USER_READ_PRIVATE = 32,
[StringAttribute("user-read-email")]
USER_READ_EMAIL = 64
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SpotifyAPI.SpotifyWebAPI
{
[Flags]
public enum SearchType
{
[StringAttribute("artist")]
ARTIST = 1,
[StringAttribute("album")]
ALBUM = 2,
[StringAttribute("track")]
TRACK = 4,
[StringAttribute("track,album,artist")]
ALL = 8
}
}

View File

@ -0,0 +1,274 @@
using System;
using System.Collections;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections.Specialized;
using System.Web;
// offered to the public domain for any use with no restriction
// and also with no warranty of any kind, please enjoy. - David Jeske.
// simple HTTP explanation
// http://www.jmarshall.com/easy/http/
namespace SpotifyAPI.SpotifyWebAPI
{
public class HttpProcessor {
public TcpClient socket;
public HttpServer srv;
private Stream inputStream;
public StreamWriter outputStream;
public String http_method;
public String http_url;
public String http_protocol_versionstring;
public Hashtable httpHeaders = new Hashtable();
private static int MAX_POST_SIZE = 10 * 1024 * 1024; // 10MB
public HttpProcessor(TcpClient s, HttpServer srv) {
this.socket = s;
this.srv = srv;
}
private string streamReadLine(Stream inputStream) {
int next_char;
string data = "";
while (true) {
next_char = inputStream.ReadByte();
if (next_char == '\n') { break; }
if (next_char == '\r') { continue; }
if (next_char == -1) { Thread.Sleep(1); continue; };
data += Convert.ToChar(next_char);
}
return data;
}
public void process() {
// we can't use a StreamReader for input, because it buffers up extra data on us inside it's
// "processed" view of the world, and we want the data raw after the headers
inputStream = new BufferedStream(socket.GetStream());
// we probably shouldn't be using a streamwriter for all output from handlers either
outputStream = new StreamWriter(new BufferedStream(socket.GetStream()));
try {
parseRequest();
readHeaders();
if (http_method.Equals("GET")) {
handleGETRequest();
} else if (http_method.Equals("POST")) {
handlePOSTRequest();
}
} catch (Exception e) {
Console.WriteLine("Exception: " + e.ToString());
writeFailure();
}
outputStream.Flush();
// bs.Flush(); // flush any remaining output
inputStream = null; outputStream = null; // bs = null;
socket.Close();
}
public void parseRequest() {
String request = streamReadLine(inputStream);
string[] tokens = request.Split(' ');
if (tokens.Length < 2) {
throw new Exception("invalid http request line");
}
http_method = tokens[0].ToUpper();
http_url = tokens[1];
}
public void readHeaders() {
String line;
while ((line = streamReadLine(inputStream)) != null) {
if (line.Equals("")) {
return;
}
int separator = line.IndexOf(':');
if (separator == -1) {
throw new Exception("invalid http header line: " + line);
}
String name = line.Substring(0, separator);
int pos = separator + 1;
while ((pos < line.Length) && (line[pos] == ' ')) {
pos++; // strip any spaces
}
string value = line.Substring(pos, line.Length - pos);
httpHeaders[name] = value;
}
}
public void handleGETRequest() {
srv.handleGETRequest(this);
}
private const int BUF_SIZE = 4096;
public void handlePOSTRequest() {
// this post data processing just reads everything into a memory stream.
// this is fine for smallish things, but for large stuff we should really
// hand an input stream to the request processor. However, the input stream
// we hand him needs to let him see the "end of the stream" at this content
// length, because otherwise he won't know when he's seen it all!
int content_len = 0;
MemoryStream ms = new MemoryStream();
if (this.httpHeaders.ContainsKey("Content-Length")) {
content_len = Convert.ToInt32(this.httpHeaders["Content-Length"]);
if (content_len > MAX_POST_SIZE) {
throw new Exception(
String.Format("POST Content-Length({0}) too big for this simple server",
content_len));
}
byte[] buf = new byte[BUF_SIZE];
int to_read = content_len;
while (to_read > 0) {
int numread = this.inputStream.Read(buf, 0, Math.Min(BUF_SIZE, to_read));
if (numread == 0) {
if (to_read == 0) {
break;
} else {
throw new Exception("client disconnected during post");
}
}
to_read -= numread;
ms.Write(buf, 0, numread);
}
ms.Seek(0, SeekOrigin.Begin);
}
srv.handlePOSTRequest(this, new StreamReader(ms));
}
public void writeSuccess(string content_type="text/html") {
outputStream.WriteLine("HTTP/1.0 200 OK");
outputStream.WriteLine("Content-Type: " + content_type);
outputStream.WriteLine("Connection: close");
outputStream.WriteLine("");
}
public void writeFailure() {
outputStream.WriteLine("HTTP/1.0 404 File not found");
outputStream.WriteLine("Connection: close");
outputStream.WriteLine("");
}
}
public abstract class HttpServer {
protected int port;
TcpListener listener;
bool is_active = true;
public HttpServer(int port) {
this.port = port;
}
public void listen()
{
listener = new TcpListener(port);
listener.Start();
while (is_active) {
TcpClient s = listener.AcceptTcpClient();
HttpProcessor processor = new HttpProcessor(s, this);
Thread thread = new Thread(new ThreadStart(processor.process));
thread.Start();
Thread.Sleep(1);
}
}
public abstract void handleGETRequest(HttpProcessor p);
public abstract void handlePOSTRequest(HttpProcessor p, StreamReader inputData);
}
public class SimpleHttpServer : HttpServer {
Action<String, String, String> funcOne;
Action<String, String, int, String, String> funcTwo;
AuthType type;
public SimpleHttpServer(int port, Action<String, String, String> func,AuthType type) : base(port)
{
this.funcOne = func;
this.type = type;
}
public SimpleHttpServer(int port, Action<String, String, int, String, String> func, AuthType type) : base(port)
{
this.funcTwo = func;
this.type = type;
}
public override void handleGETRequest (HttpProcessor p)
{
p.writeSuccess();
if (p.http_url == "/favicon.ico")
return;
Thread t = null;
if(type == AuthType.AUTHORIZATION)
{
String url = p.http_url;
url = url.Substring(2, url.Length - 2);
NameValueCollection col = HttpUtility.ParseQueryString(url);
if (col.Keys.Get(0) != "code")
{
p.outputStream.WriteLine("<html><body><h1>Spotify Auth canceled!</h1></body></html>");
t = new Thread(new ParameterizedThreadStart((o) => { funcOne(null, col.Get(1), col.Get(0)); }));
}
else
{
p.outputStream.WriteLine("<html><body><h1>Spotify Auth successful!</h1></body></html>");
t = new Thread(new ParameterizedThreadStart((o) => { funcOne(col.Get(0), col.Get(1), null); }));
}
}
else
{
if(p.http_url == "/")
{
p.outputStream.WriteLine("<html><body>" +
"<script>" +
"" +
"var hashes = window.location.hash;" +
"hashes = hashes.replace('#','&');" +
"window.location = hashes" +
"</script>" +
"<h1>Spotify Auth successful!<br>Please copy the URL and paste it into the application</h1></body></html>");
return;
}
String url = p.http_url;
url = url.Substring(2, url.Length - 2);
NameValueCollection col = HttpUtility.ParseQueryString(url);
if (col.Keys.Get(0) != "access_token")
{
p.outputStream.WriteLine("<html><body><h1>Spotify Auth canceled!</h1></body></html>");
t = new Thread(new ParameterizedThreadStart((o) => { funcTwo(null, null,0,col.Get(1),col.Get(0)); }));
}
else
{
p.outputStream.WriteLine("<html><body><h1>Spotify Auth successful!</h1></body></html>");
t = new Thread(new ParameterizedThreadStart((o) => { funcTwo(col.Get(0), col.Get(1), Convert.ToInt32(col.Get(2)),col.Get(3),null); }));
}
}
t.Start();
}
public override void handlePOSTRequest(HttpProcessor p, StreamReader inputData)
{
p.writeSuccess();
}
}
public enum AuthType
{
IMPLICIT,AUTHORIZATION
}
}

View File

@ -0,0 +1,175 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using SpotifyAPI.SpotifyWebAPI;
using SpotifyAPI.SpotifyWebAPI.Models;
using Newtonsoft.Json;
using System.Collections.Specialized;
using System.IO;
namespace SpotifyAPI.SpotifyWebAPI
{
public class SpotifyWebAPIClass
{
public String TokenType { get; set; }
public String AccessToken { get; set; }
/// <summary>
/// Set to false, if you want anonymous calls without auth
/// </summary>
public Boolean UseAuth { get; set; }
WebClient webclient;
JsonSerializerSettings settings;
public SpotifyWebAPIClass()
{
UseAuth = true;
webclient = new WebClient();
webclient.Proxy = null;
settings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
}
public PrivateProfile GetPrivateProfile()
{
return DownloadString<PrivateProfile>("https://api.spotify.com/v1/me");
}
public PublicProfile GetPublicProfile(String userId = "")
{
if(userId.Length == 0)
return DownloadString<PublicProfile>("https://api.spotify.com/v1/me");
else
return DownloadString<PublicProfile>("https://api.spotify.com/v1/users/" + userId);
}
public Paging<SimplePlaylist> GetUserPlaylists(String userId)
{
return DownloadString<Paging<SimplePlaylist>>("https://api.spotify.com/v1/users/" + userId + "/playlists");
}
public FullPlaylist GetPlaylist(String userId,String playlistId)
{
return DownloadString<FullPlaylist>("https://api.spotify.com/v1/users/" + userId + "/playlists/" + playlistId);
}
public Paging<PlaylistTrack> GetPlaylistTracks(String userId,String playlistId)
{
return DownloadString<Paging<PlaylistTrack>>("https://api.spotify.com/v1/users/" + userId + "/playlists/" + playlistId + "/tracks");
}
public FullPlaylist CreatePlaylist(String userId,String playlistName,Boolean isPublic = true)
{
CreatePlaylistArgs args = new CreatePlaylistArgs()
{
Name = playlistName,
Public = isPublic
};
return UploadData<FullPlaylist>("https://api.spotify.com/v1/users/" + userId + "/playlists",JsonConvert.SerializeObject(args));
}
public Error AddTracks(String userId,String playlistId,List<String> uris,int position = int.MaxValue)
{
if(position == int.MaxValue)
return UploadData<Error>("https://api.spotify.com/v1/users/" + userId + "/playlists/" + playlistId + "/tracks", JsonConvert.SerializeObject(uris));
else
{
String tracks = string.Join(",", uris);
return UploadData<Error>("https://api.spotify.com/v1/users/" + userId + "/playlists/" + playlistId + "/tracks?position=" + position
+ "&ids=" + tracks
, JsonConvert.SerializeObject(uris));
}
}
public SearchItem SearchItems(String q,SearchType type,int limit = 20,int offset = 0)
{
limit = Math.Min(50, limit);
StringBuilder builder = new StringBuilder("https://api.spotify.com/v1/search");
builder.Append("?q=" + q);
builder.Append("&type=" + type.GetSearchValue(","));
builder.Append("&limit=" + limit);
builder.Append("&offset=" + offset);
return DownloadString<SearchItem>(builder.ToString());
}
public SeveralTracks GetSeveralTracks(List<String> ids)
{
return DownloadString<SeveralTracks>("https://api.spotify.com/v1/tracks?ids=" + string.Join(",",ids));
}
public SeveralAlbums GetSeveralAlbums(List<String> ids)
{
return DownloadString<SeveralAlbums>("https://api.spotify.com/v1/albums?ids=" + string.Join(",", ids));
}
public SeveralArtists GetSeveralArtists(List<String> ids)
{
return DownloadString<SeveralArtists>("https://api.spotify.com/v1/artists?ids=" + string.Join(",", ids));
}
public FullTrack GetTrack(String id)
{
return DownloadString<FullTrack>("https://api.spotify.com/v1/tracks/" + id);
}
public SeveralArtists GetRelatedArtists(String id)
{
return DownloadString<SeveralArtists>("https://api.spotify.com/v1/artists/" + id + "/related-artists");
}
public SeveralTracks GetArtistsTopTracks(String id, String country)
{
return DownloadString<SeveralTracks>("https://api.spotify.com/v1/artists/" + id + "/top-tracks?country=" + country);
}
public Paging<SimpleAlbum> GetArtistsAlbums(String id,AlbumType type = AlbumType.ALL,String country = "",int limit = 20,int offset = 0)
{
limit = Math.Min(50, limit);
StringBuilder builder = new StringBuilder("https://api.spotify.com/v1/artists/" + id + "/albums");
builder.Append("?type=" + type.GetAlbumValue(","));
builder.Append("&limit=" + limit);
builder.Append("&offset=" + offset);
return DownloadString<Paging<SimpleAlbum>>(builder.ToString());
}
public FullArtist GetArtist(String id)
{
return DownloadString<FullArtist>("https://api.spotify.com/v1/artists/" + id);
}
public Paging<SimpleTrack> GetAlbumTracks(String id,int limit = 20,int offset = 0)
{
limit = Math.Min(50, limit);
StringBuilder builder = new StringBuilder("https://api.spotify.com/v1/albums/" + id + "/tracks");
builder.Append("?limit=" + limit);
builder.Append("&offset=" + offset);
return DownloadString<Paging<SimpleTrack>>(builder.ToString());
}
public FullAlbum GetAlbum(String id )
{
return DownloadString<FullAlbum>("https://api.spotify.com/v1/albums/" + id);
}
public T UploadData<T>(String url,String uploadData)
{
if (!UseAuth)
throw new Exception("UseAuth required for 'UploadData'");
webclient.Headers.Add("Authorization", TokenType + " " + AccessToken);
webclient.Headers.Add("Content-Type","application/json");
String response = "";
try
{
byte[] data = webclient.UploadData(url,Encoding.UTF8.GetBytes(uploadData));
response = Encoding.UTF8.GetString(data);
}
catch (WebException e)
{
response = new StreamReader(e.Response.GetResponseStream()).ReadToEnd();
}
return JsonConvert.DeserializeObject<T>(response, settings);
}
public T DownloadString<T>(String url)
{
if(UseAuth)
webclient.Headers.Add("Authorization", TokenType + " " + AccessToken);
String response = "";
try
{
byte [] data = webclient.DownloadData(url);
response = Encoding.UTF8.GetString(data);
}catch(WebException e)
{
response = new StreamReader(e.Response.GetResponseStream()).ReadToEnd();
}
return JsonConvert.DeserializeObject<T>(response, settings);
}
public void Dispose()
{
webclient.Dispose();
}
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
namespace SpotifyAPI.SpotifyWebAPI
{
public class StringAttribute : Attribute
{
public String Text {get;set;}
public StringAttribute(String text)
{
this.Text = text;
}
}
}

View File

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using SpotifyAPI.SpotifyWebAPI.Models;
namespace SpotifyAPI.SpotifyWebAPI
{
public static class Util
{
public static string GetScopeValue(this Scope en,String separator)
{
IEnumerable<StringAttribute> attributes =
Enum.GetValues(typeof(Scope))
.Cast<Scope>()
.Where(v => en.HasFlag(v))
.Select(v => typeof(Scope).GetField(v.ToString()))
.Select(f => f.GetCustomAttributes(typeof(StringAttribute), false)[0])
.Cast<StringAttribute>();
List<String> list = new List<String>();
attributes.ToList().ForEach((element) => list.Add(element.Text));
return string.Join(" ", list);
}
public static string GetSearchValue(this SearchType en, String separator)
{
IEnumerable<StringAttribute> attributes =
Enum.GetValues(typeof(SearchType))
.Cast<SearchType>()
.Where(v => en.HasFlag(v))
.Select(v => typeof(SearchType).GetField(v.ToString()))
.Select(f => f.GetCustomAttributes(typeof(StringAttribute), false)[0])
.Cast<StringAttribute>();
List<String> list = new List<String>();
attributes.ToList().ForEach((element) => list.Add(element.Text));
return string.Join(" ", list);
}
public static string GetAlbumValue(this AlbumType en, String separator)
{
IEnumerable<StringAttribute> attributes =
Enum.GetValues(typeof(AlbumType))
.Cast<AlbumType>()
.Where(v => en.HasFlag(v))
.Select(v => typeof(AlbumType).GetField(v.ToString()))
.Select(f => f.GetCustomAttributes(typeof(StringAttribute), false)[0])
.Cast<StringAttribute>();
List<String> list = new List<String>();
attributes.ToList().ForEach((element) => list.Add(element.Text));
return string.Join(" ", list);
}
}
}

View File

@ -336,7 +336,7 @@
this.MaximumSize = new System.Drawing.Size(1018, 702); this.MaximumSize = new System.Drawing.Size(1018, 702);
this.MinimumSize = new System.Drawing.Size(1018, 702); this.MinimumSize = new System.Drawing.Size(1018, 702);
this.Name = "Form1"; this.Name = "Form1";
this.Text = "SpotifyAPI Example"; this.Text = "SpotifyLocalAPIClass Example";
this.Load += new System.EventHandler(this.Form1_Load); this.Load += new System.EventHandler(this.Form1_Load);
this.groupBox1.ResumeLayout(false); this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout(); this.groupBox1.PerformLayout();

View File

@ -8,29 +8,29 @@ using System.Diagnostics;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
using SpotifyAPIv1; using SpotifyAPI.SpotifyLocalAPI;
using System.Threading; using System.Threading;
using SpotifyEventHandler = SpotifyAPIv1.SpotifyEventHandler; using SpotifyEventHandler = SpotifyAPI.SpotifyLocalAPI.SpotifyEventHandler;
namespace SpotifyAPI_Example namespace SpotifyAPI_Example
{ {
public partial class Form1 : Form public partial class Form1 : Form
{ {
SpotifyAPI spotify; SpotifyLocalAPIClass spotify;
SpotifyMusicHandler mh; SpotifyMusicHandler mh;
SpotifyEventHandler eh; SpotifyEventHandler eh;
public Form1() public Form1()
{ {
InitializeComponent(); InitializeComponent();
spotify = new SpotifyAPI(); spotify = new SpotifyLocalAPIClass();
if (!SpotifyAPI.IsSpotifyRunning()) if (!SpotifyLocalAPIClass.IsSpotifyRunning())
{ {
spotify.RunSpotify(); spotify.RunSpotify();
Thread.Sleep(5000); Thread.Sleep(5000);
} }
if (!SpotifyAPI.IsSpotifyWebHelperRunning()) if (!SpotifyLocalAPIClass.IsSpotifyWebHelperRunning())
{ {
spotify.RunSpotifyWebHelper(); spotify.RunSpotifyWebHelper();
Thread.Sleep(4000); Thread.Sleep(4000);
@ -41,7 +41,7 @@ namespace SpotifyAPI_Example
Boolean retry = true; Boolean retry = true;
while(retry) while(retry)
{ {
if (MessageBox.Show("SpotifyAPI could'nt load!", "Error", MessageBoxButtons.RetryCancel) == System.Windows.Forms.DialogResult.Retry) if (MessageBox.Show("SpotifyLocalAPIClass could'nt load!", "Error", MessageBoxButtons.RetryCancel) == System.Windows.Forms.DialogResult.Retry)
{ {
if(spotify.Connect()) if(spotify.Connect())
retry = false; retry = false;

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>

View File

@ -0,0 +1,145 @@
using System;
using System.Windows;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using SpotifyAPI.SpotifyWebAPI;
using SpotifyAPI.SpotifyWebAPI.Models;
namespace SpotifyWebAPIExample
{
class Program
{
static ImplicitGrantAuth auth;
static void Main(string[] args)
{
Console.WriteLine("### SpotifyWebAPI .NET Test App");
Console.WriteLine("Starting auth process...");
//Create the auth object
auth = new ImplicitGrantAuth()
{
//Your client Id
ClientId = "26d287105e31491889f3cd293d85bfea",
//Set this to localhost if you want to use the built-in HTTP Server
RedirectUri = "http://localhost",
//How many permissions we need?
Scope = Scope.USER_READ_PRIVATE | Scope.USER_READ_EMAIL | Scope.PLAYLIST_READ_PRIVATE
};
//Start the internal http server
auth.StartHttpServer();
//When we got our response
auth.OnResponseReceivedEvent += auth_OnResponseReceivedEvent;
//Start
auth.DoAuth();
}
static void auth_OnResponseReceivedEvent(Token token, string state, string error)
{
//stop the http server
auth.StopHttpServer();
if(error != null)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Error: " + error);
return;
}
DisplayMenu(new SpotifyWebAPIClass()
{
AccessToken = token.AccessToken,
TokenType = token.TokenType,
UseAuth = true
});
}
public static void DisplayMenu(SpotifyWebAPIClass spotify)
{
Console.WriteLine("Choose one of the following Tests:");
Console.WriteLine("1 - Display Profile information");
Console.WriteLine("2 - Display all of your playlists");
Console.WriteLine("3 - List all of your playlist-tracks");
Console.Write("Number: ");
String number = Console.ReadLine();
switch (number)
{
default:
DisplayMenu(spotify);
break;
case "1":
DisplayProfile(spotify);
break;
case "2":
DisplayPlaylists(spotify);
break;
case "3":
DisplayPlaylistTracks(spotify);
break;
}
}
public static void DisplayProfile(SpotifyWebAPIClass spotify)
{
Console.WriteLine("");
Console.WriteLine("");
Console.WriteLine("");
PrivateProfile profile = spotify.GetPrivateProfile();
Console.WriteLine("Your Display name: " + profile.DisplayName);
Console.WriteLine("Your Country: " + profile.Country);
Console.WriteLine("Your ID: " + profile.Id);
Console.WriteLine("Account product: " + profile.Product);
Console.WriteLine("Your images:");
foreach (Image image in profile.Images)
Console.WriteLine("- " + image.Url);
Console.WriteLine("");
Console.WriteLine("");
Console.WriteLine("");
DisplayMenu(spotify);
}
private static void DisplayPlaylists(SpotifyWebAPIClass spotify)
{
Console.WriteLine("");
Console.WriteLine("");
Console.WriteLine("");
Paging<SimplePlaylist> playlists = spotify.GetUserPlaylists(spotify.GetPublicProfile().Id);
Console.WriteLine("Printing playlists...");
Console.WriteLine("");
foreach (SimplePlaylist playlist in playlists.Items)
Console.WriteLine(playlist.Name + " (" + playlist.Id + ")");
while(playlists.Next != null)
{
playlists = spotify.DownloadString<Paging<SimplePlaylist>>(playlists.Next);
foreach (SimplePlaylist playlist in playlists.Items)
Console.WriteLine(playlist.Name + " (" + playlist.Id + ")");
}
Console.WriteLine("");
Console.WriteLine("");
Console.WriteLine("");
DisplayMenu(spotify);
}
private static void DisplayPlaylistTracks(SpotifyWebAPIClass spotify)
{
Console.WriteLine("");
Console.WriteLine("");
Console.Write("Playlist ID (must be one of yours): ");
String id = Console.ReadLine();
Paging<PlaylistTrack> col = spotify.GetPlaylistTracks(spotify.GetPrivateProfile().Id, id);
if(col.HasError())
{
Console.WriteLine("ERROR: " + col.Error.Message);
DisplayMenu(spotify);
return;
}
foreach(PlaylistTrack track in col.Items)
Console.WriteLine(track.Track.Name + " (" + track.Track.Id + ")");
while (col.Next != null)
{
col = spotify.DownloadString<Paging<PlaylistTrack>>(col.Next);
foreach (PlaylistTrack track in col.Items)
Console.WriteLine(track.Track.Name + " (" + track.Track.Id + ")");
}
DisplayMenu(spotify);
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// Allgemeine Informationen über eine Assembly werden über die folgenden
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
// die mit einer Assembly verknüpft sind.
[assembly: AssemblyTitle("SpotifyWebAPIExample")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SpotifyWebAPIExample")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar
// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von
// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest.
[assembly: ComVisible(false)]
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
[assembly: Guid("a09c6b3c-dd43-4423-9daa-4b69f031e695")]
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
//
// Hauptversion
// Nebenversion
// Buildnummer
// Revision
//
// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern
// übernehmen, indem Sie "*" eingeben:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{004B45C3-BB98-4E62-AD11-D80BA64FEB8E}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SpotifyWebAPIExample</RootNamespace>
<AssemblyName>SpotifyWebAPIExample</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SpotifyAPI\SpotifyAPI.csproj">
<Project>{ebbe35e2-7b91-4d7d-b8fc-3a0472f5119d}</Project>
<Name>SpotifyAPI</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>