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)
Screenshot of the Example:
![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
![alt text](http://i.imgur.com/R9Xsma0.png "Example Screen")

View File

@ -1,10 +1,12 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.21005.1
VisualStudioVersion = 12.0.30324.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpotifyAPI", "SpotifyAPI\SpotifyAPI.csproj", "{EBBE35E2-7B91-4D7D-B8FC-3A0472F5119D}"
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}"
EndProject
Global
@ -17,6 +19,10 @@ Global
{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.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.Build.0 = Debug|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
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
// die mit einer Assembly verknüpft sind.
[assembly: AssemblyTitle("SpotifyAPI")]
[assembly: AssemblyTitle("SpotifyLocalAPIClass")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SpotifyAPI")]
[assembly: AssemblyProduct("SpotifyLocalAPIClass")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,7 +6,7 @@ using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.IO;
namespace SpotifyAPIv1
namespace SpotifyAPI.SpotifyLocalAPI
{
public class SpotifyMusicHandler
{
@ -56,7 +56,7 @@ namespace SpotifyAPIv1
/// <summary>
/// Plays a Spotify URI
/// </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)
{
rh.SendPlayRequest(uri);

View File

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

View File

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

View File

@ -7,7 +7,7 @@
<ProjectGuid>{EBBE35E2-7B91-4D7D-B8FC-3A0472F5119D}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SpotifyAPIv1</RootNamespace>
<RootNamespace>SpotifyAPI.SpotifyLocalAPI</RootNamespace>
<AssemblyName>SpotifyAPI</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
@ -38,6 +38,7 @@
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Web" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
@ -46,23 +47,49 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="CFID.cs" />
<Compile Include="Enum.cs" />
<Compile Include="ExtendedWebClient.cs">
<Compile Include="SpoitfyLocalAPI\CFID.cs" />
<Compile Include="SpoitfyLocalAPI\Enum.cs" />
<Compile Include="SpoitfyLocalAPI\ExtendedWebClient.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="SpotifyEventHandler.cs" />
<Compile Include="Events.cs" />
<Compile Include="SpotifyMusicHandler.cs" />
<Compile Include="RemoteHandler.cs" />
<Compile Include="SpotifyAPI.cs" />
<Compile Include="SpoitfyLocalAPI\SpotifyEventHandler.cs" />
<Compile Include="SpoitfyLocalAPI\Events.cs" />
<Compile Include="SpoitfyLocalAPI\SpotifyMusicHandler.cs" />
<Compile Include="SpoitfyLocalAPI\RemoteHandler.cs" />
<Compile Include="SpoitfyLocalAPI\SpotifyAPI.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="StatusResponse.cs" />
<Compile Include="Track.cs" />
<Compile Include="SpoitfyLocalAPI\StatusResponse.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>
<None Include="app.config" />
</ItemGroup>
<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.

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.MinimumSize = new System.Drawing.Size(1018, 702);
this.Name = "Form1";
this.Text = "SpotifyAPI Example";
this.Text = "SpotifyLocalAPIClass Example";
this.Load += new System.EventHandler(this.Form1_Load);
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();

View File

@ -8,29 +8,29 @@ using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using SpotifyAPIv1;
using SpotifyAPI.SpotifyLocalAPI;
using System.Threading;
using SpotifyEventHandler = SpotifyAPIv1.SpotifyEventHandler;
using SpotifyEventHandler = SpotifyAPI.SpotifyLocalAPI.SpotifyEventHandler;
namespace SpotifyAPI_Example
{
public partial class Form1 : Form
{
SpotifyAPI spotify;
SpotifyLocalAPIClass spotify;
SpotifyMusicHandler mh;
SpotifyEventHandler eh;
public Form1()
{
InitializeComponent();
spotify = new SpotifyAPI();
if (!SpotifyAPI.IsSpotifyRunning())
spotify = new SpotifyLocalAPIClass();
if (!SpotifyLocalAPIClass.IsSpotifyRunning())
{
spotify.RunSpotify();
Thread.Sleep(5000);
}
if (!SpotifyAPI.IsSpotifyWebHelperRunning())
if (!SpotifyLocalAPIClass.IsSpotifyWebHelperRunning())
{
spotify.RunSpotifyWebHelper();
Thread.Sleep(4000);
@ -41,7 +41,7 @@ namespace SpotifyAPI_Example
Boolean retry = true;
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())
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>