From 3184fc617d5cda62b6f7b78fcd473845248559e6 Mon Sep 17 00:00:00 2001 From: Rikki Tooley Date: Tue, 11 Jun 2013 17:40:22 +0100 Subject: [PATCH] Album.getInfo, starting to get a nice layout to the api. --- IF.Lastfm.Console/Program.cs | 23 +++- IF.Lastfm.Core.Tests/Api/MockAlbumApi.cs | 19 +++ .../IF.Lastfm.Core.Tests.csproj | 32 ++++- IF.Lastfm.Core.Tests/LastFmTests.cs | 4 +- IF.Lastfm.Core.Tests/Objects/AlbumTests.cs | 45 +++++++ IF.Lastfm.Core.Tests/ResourceManager.cs | 21 +++ .../Resources/AlbumGetInfo.json | 1 + IF.Lastfm.Core.Tests/TestData.Designer.cs | 73 +++++++++++ IF.Lastfm.Core.Tests/TestData.resx | 124 ++++++++++++++++++ IF.Lastfm.Core.Tests/app.config | 16 +-- IF.Lastfm.Core.Tests/packages.config | 2 +- IF.Lastfm.Core/Api/AlbumApi.cs | 60 +++++++++ IF.Lastfm.Core/Api/Auth.cs | 21 +-- IF.Lastfm.Core/Api/IAlbumApi.cs | 13 ++ IF.Lastfm.Core/Api/IAuth.cs | 6 +- IF.Lastfm.Core/IF.Lastfm.Core.csproj | 5 + IF.Lastfm.Core/LastFm.cs | 8 +- IF.Lastfm.Core/Objects/Album.cs | 55 ++++++++ IF.Lastfm.Core/Objects/Tag.cs | 6 + IF.Lastfm.Core/Objects/Track.cs | 6 + IF.Lastfm.Core/Objects/UserSession.cs | 2 +- IF.Lastfm.sln | 1 - 22 files changed, 503 insertions(+), 40 deletions(-) create mode 100644 IF.Lastfm.Core.Tests/Api/MockAlbumApi.cs create mode 100644 IF.Lastfm.Core.Tests/Objects/AlbumTests.cs create mode 100644 IF.Lastfm.Core.Tests/ResourceManager.cs create mode 100644 IF.Lastfm.Core.Tests/Resources/AlbumGetInfo.json create mode 100644 IF.Lastfm.Core.Tests/TestData.Designer.cs create mode 100644 IF.Lastfm.Core.Tests/TestData.resx create mode 100644 IF.Lastfm.Core/Api/AlbumApi.cs create mode 100644 IF.Lastfm.Core/Api/IAlbumApi.cs create mode 100644 IF.Lastfm.Core/Objects/Album.cs create mode 100644 IF.Lastfm.Core/Objects/Tag.cs create mode 100644 IF.Lastfm.Core/Objects/Track.cs diff --git a/IF.Lastfm.Console/Program.cs b/IF.Lastfm.Console/Program.cs index 24a0c57..a966077 100644 --- a/IF.Lastfm.Console/Program.cs +++ b/IF.Lastfm.Console/Program.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Text; +using System.Threading.Tasks; using IF.Lastfm.Core; using IF.Lastfm.Core.Api; @@ -9,14 +11,27 @@ namespace IF.Lastfm.Console { class Program { - private const string ApiKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"; - private const string ApiSecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"; + private const string ApiKey = "xxx"; + private const string ApiSecret = "xxx"; static void Main(string[] args) { - var lastfm = new Auth(ApiKey, ApiSecret); + Run().Wait(); + } - lastfm.GetSessionTokenAsync("xxxxxxxxxxxx", "xxxxxxxxxxxx").Wait(); + public static async Task Run() + { + var auth = new Auth(ApiKey, ApiSecret); + await auth.GetSessionTokenAsync("xxx", "xxx"); + + var albumApi = new AlbumApi(auth); + + var album = await albumApi.GetAlbumInfoAsync("Grimes", "Visions", false); + + var req = WebRequest.Create(""); + var w = await req.GetRequestStreamAsync(); + + System.Console.ReadLine(); } } } diff --git a/IF.Lastfm.Core.Tests/Api/MockAlbumApi.cs b/IF.Lastfm.Core.Tests/Api/MockAlbumApi.cs new file mode 100644 index 0000000..c8c443c --- /dev/null +++ b/IF.Lastfm.Core.Tests/Api/MockAlbumApi.cs @@ -0,0 +1,19 @@ +using IF.Lastfm.Core.Api; +using Moq; + +namespace IF.Lastfm.Core.Tests.Api +{ + public class MockAlbumApi + { + public AlbumApi Object { get; private set; } + + public Mock Auth { get; private set; } + + public MockAlbumApi(Mock auth) + { + Auth = auth; + + Object = new AlbumApi(Auth.Object); + } + } +} \ No newline at end of file diff --git a/IF.Lastfm.Core.Tests/IF.Lastfm.Core.Tests.csproj b/IF.Lastfm.Core.Tests/IF.Lastfm.Core.Tests.csproj index ec1a8b8..fb2e5b8 100644 --- a/IF.Lastfm.Core.Tests/IF.Lastfm.Core.Tests.csproj +++ b/IF.Lastfm.Core.Tests/IF.Lastfm.Core.Tests.csproj @@ -40,19 +40,22 @@ false - - ..\packages\Microsoft.Bcl.Async.1.0.16\lib\net40\Microsoft.Threading.Tasks.dll + + False + ..\packages\Microsoft.Bcl.Async.1.0.16\lib\net45\Microsoft.Threading.Tasks.dll - - ..\packages\Microsoft.Bcl.Async.1.0.16\lib\net40\Microsoft.Threading.Tasks.Extensions.dll - - - ..\packages\Microsoft.Bcl.Async.1.0.16\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll + + False + ..\packages\Microsoft.Bcl.Async.1.0.16\lib\net45\Microsoft.Threading.Tasks.Extensions.dll ..\packages\Moq.4.0.10827\lib\NET40\Moq.dll True + + False + ..\packages\Newtonsoft.Json.5.0.6\lib\portable-net40+sl4+wp7+win8\Newtonsoft.Json.dll + 3.5 @@ -92,13 +95,22 @@ + + + + + True + True + TestData.resx + + @@ -106,6 +118,12 @@ IF.Lastfm.Core + + + ResXFileCodeGenerator + TestData.Designer.cs + + diff --git a/IF.Lastfm.Core.Tests/LastFmTests.cs b/IF.Lastfm.Core.Tests/LastFmTests.cs index 75f4930..614433a 100644 --- a/IF.Lastfm.Core.Tests/LastFmTests.cs +++ b/IF.Lastfm.Core.Tests/LastFmTests.cs @@ -11,11 +11,9 @@ public class LastFmTests [TestMethod] public void ApiUrlFormatReturnsCorrectly() { - var lastfm = new MockLastFm(); - const string expected = "https://ws.audioscrobbler.com/2.0/?method=tobias.funke&api_key=suddenvalley&blue=performance&format=json&uncle=t-bag"; - var actual = lastfm.Object.FormatApiUrl("tobias.funke", "suddenvalley", new Dictionary + var actual = LastFm.FormatApiUrl("tobias.funke", "suddenvalley", new Dictionary { {"uncle", "t-bag"}, {"blue", "performance"} diff --git a/IF.Lastfm.Core.Tests/Objects/AlbumTests.cs b/IF.Lastfm.Core.Tests/Objects/AlbumTests.cs new file mode 100644 index 0000000..ad9098d --- /dev/null +++ b/IF.Lastfm.Core.Tests/Objects/AlbumTests.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Text; +using IF.Lastfm.Core.Api; +using IF.Lastfm.Core.Objects; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace IF.Lastfm.Core.Tests.Objects +{ + [TestClass] + public class AlbumTests + { + [TestMethod] + public void AlbumParsesValidJson() + { + var jo = ResourceManager.LoadResource(Encoding.UTF8.GetString(TestData.AlbumGetInfo)); + + var parsed = Album.ParseJToken(jo.SelectToken("album")); + + var expected = new Album() + { + ArtistId = "283786832", + ArtistName = "Grimes", + ListenerCount = 293542, + TotalPlayCount = 10540575, + Mbid = "2fd00edb-391a-41ec-8f2f-01e2c202d9eb", + Name = "Visions", + ReleaseDateUtc = new DateTime(2012, 02, 21, 0, 0, 0), + Url = new Uri("http://www.last.fm/music/Grimes/Visions", UriKind.Absolute), + TopTags = new List + { + // TODO + }, + Tracks = new List + { + } + }; + + Assert.AreEqual(parsed, expected); + } + } +} \ No newline at end of file diff --git a/IF.Lastfm.Core.Tests/ResourceManager.cs b/IF.Lastfm.Core.Tests/ResourceManager.cs new file mode 100644 index 0000000..b369afa --- /dev/null +++ b/IF.Lastfm.Core.Tests/ResourceManager.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace IF.Lastfm.Core.Tests +{ + public static class ResourceManager + { + public static JObject LoadResource(string json) + { + JsonReader reader = new JsonTextReader(new StringReader(json)); + reader.DateParseHandling = DateParseHandling.None; + return JObject.Load(reader); + } + } +} diff --git a/IF.Lastfm.Core.Tests/Resources/AlbumGetInfo.json b/IF.Lastfm.Core.Tests/Resources/AlbumGetInfo.json new file mode 100644 index 0000000..b63bb53 --- /dev/null +++ b/IF.Lastfm.Core.Tests/Resources/AlbumGetInfo.json @@ -0,0 +1 @@ +{"album":{"name":"Visions","artist":"Grimes","id":"283786832","mbid":"2fd00edb-391a-41ec-8f2f-01e2c202d9eb","url":"http:\/\/www.last.fm\/music\/Grimes\/Visions","releasedate":" 21 Feb 2012, 00:00","image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/73293934.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/73293934.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/174s\/73293934.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/73293934.png","size":"extralarge"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/_\/73293934\/Visions+grimes__648.png","size":"mega"}],"listeners":"293542","playcount":"10540575","tracks":{"track":[{"name":"Infinite Love Without Fulfilment","duration":"94","mbid":"","url":"http:\/\/www.last.fm\/music\/+noredirect\/Grimes\/_\/Infinite+Love+Without+Fulfilment","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Grimes","mbid":"7e5a2a59-6d9f-4a17-b7c2-e1eedb7bd222","url":"http:\/\/www.last.fm\/music\/Grimes"},"@attr":{"rank":"1"}},{"name":"Genesis","duration":"255","mbid":"5b4c54ed-b805-4f40-a0f0-d791d97708ed","url":"http:\/\/www.last.fm\/music\/Grimes\/_\/Genesis","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Grimes","mbid":"7e5a2a59-6d9f-4a17-b7c2-e1eedb7bd222","url":"http:\/\/www.last.fm\/music\/Grimes"},"@attr":{"rank":"2"}},{"name":"Oblivion","duration":"228","mbid":"ec496b0d-cac7-4f45-b2d7-68f3b6179b13","url":"http:\/\/www.last.fm\/music\/Grimes\/_\/Oblivion","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Grimes","mbid":"7e5a2a59-6d9f-4a17-b7c2-e1eedb7bd222","url":"http:\/\/www.last.fm\/music\/Grimes"},"@attr":{"rank":"3"}},{"name":"Eight","duration":"107","mbid":"4ffc8b67-7dc3-45f0-903b-92b07dbaba55","url":"http:\/\/www.last.fm\/music\/Grimes\/_\/Eight","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Grimes","mbid":"7e5a2a59-6d9f-4a17-b7c2-e1eedb7bd222","url":"http:\/\/www.last.fm\/music\/Grimes"},"@attr":{"rank":"4"}},{"name":"Circumambient","duration":"223","mbid":"287333c5-6851-4d9d-9aa7-4cf787fe7079","url":"http:\/\/www.last.fm\/music\/Grimes\/_\/Circumambient","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Grimes","mbid":"7e5a2a59-6d9f-4a17-b7c2-e1eedb7bd222","url":"http:\/\/www.last.fm\/music\/Grimes"},"@attr":{"rank":"5"}},{"name":"Vowels space and time","duration":"261","mbid":"","url":"http:\/\/www.last.fm\/music\/+noredirect\/Grimes\/_\/Vowels+space+and+time","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Grimes","mbid":"7e5a2a59-6d9f-4a17-b7c2-e1eedb7bd222","url":"http:\/\/www.last.fm\/music\/Grimes"},"@attr":{"rank":"6"}},{"name":"Visiting Statue","duration":"118","mbid":"d77f0e2e-ba44-47f9-b436-621017b2b1c8","url":"http:\/\/www.last.fm\/music\/Grimes\/_\/Visiting+Statue","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Grimes","mbid":"7e5a2a59-6d9f-4a17-b7c2-e1eedb7bd222","url":"http:\/\/www.last.fm\/music\/Grimes"},"@attr":{"rank":"7"}},{"name":"Be a Body","duration":"260","mbid":"99912b42-5305-489b-980c-00cd148556e8","url":"http:\/\/www.last.fm\/music\/+noredirect\/Grimes\/_\/Be+a+Body","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Grimes","mbid":"7e5a2a59-6d9f-4a17-b7c2-e1eedb7bd222","url":"http:\/\/www.last.fm\/music\/Grimes"},"@attr":{"rank":"8"}},{"name":"Colour Of Moonlight (Antiochus) (Ft. Doldrums)","duration":"239","mbid":"","url":"http:\/\/www.last.fm\/music\/Grimes\/_\/Colour+Of+Moonlight+(Antiochus)+(Ft.+Doldrums)","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Grimes","mbid":"7e5a2a59-6d9f-4a17-b7c2-e1eedb7bd222","url":"http:\/\/www.last.fm\/music\/Grimes"},"@attr":{"rank":"9"}},{"name":"Symphonia IX (My Wait Is U)","duration":"292","mbid":"7b8fb58b-833b-4edc-9829-280dbd296b60","url":"http:\/\/www.last.fm\/music\/Grimes\/_\/Symphonia+IX+(My+Wait+Is+U)","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Grimes","mbid":"7e5a2a59-6d9f-4a17-b7c2-e1eedb7bd222","url":"http:\/\/www.last.fm\/music\/Grimes"},"@attr":{"rank":"10"}},{"name":"Nightmusic (Ft. Majical Cloudz)","duration":"303","mbid":"","url":"http:\/\/www.last.fm\/music\/Grimes\/_\/Nightmusic+(Ft.+Majical+Cloudz)","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Grimes","mbid":"7e5a2a59-6d9f-4a17-b7c2-e1eedb7bd222","url":"http:\/\/www.last.fm\/music\/Grimes"},"@attr":{"rank":"11"}},{"name":"Skin","duration":"369","mbid":"96efc33c-09b9-4fcd-b8b6-7757ac3ee91e","url":"http:\/\/www.last.fm\/music\/Grimes\/_\/Skin","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Grimes","mbid":"7e5a2a59-6d9f-4a17-b7c2-e1eedb7bd222","url":"http:\/\/www.last.fm\/music\/Grimes"},"@attr":{"rank":"12"}},{"name":"Know the Way","duration":"105","mbid":"","url":"http:\/\/www.last.fm\/music\/Grimes\/_\/Know+the+Way","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Grimes","mbid":"7e5a2a59-6d9f-4a17-b7c2-e1eedb7bd222","url":"http:\/\/www.last.fm\/music\/Grimes"},"@attr":{"rank":"13"}}]},"toptags":{"tag":[{"name":"2012","url":"http:\/\/www.last.fm\/tag\/2012"},{"name":"best of 2012","url":"http:\/\/www.last.fm\/tag\/best%20of%202012"},{"name":"experimental","url":"http:\/\/www.last.fm\/tag\/experimental"},{"name":"dream pop","url":"http:\/\/www.last.fm\/tag\/dream%20pop"},{"name":"synth-pop","url":"http:\/\/www.last.fm\/tag\/synth-pop"}]}}} diff --git a/IF.Lastfm.Core.Tests/TestData.Designer.cs b/IF.Lastfm.Core.Tests/TestData.Designer.cs new file mode 100644 index 0000000..c57c874 --- /dev/null +++ b/IF.Lastfm.Core.Tests/TestData.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18033 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace IF.Lastfm.Core.Tests { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class TestData { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal TestData() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("IF.Lastfm.Core.Tests.TestData", typeof(TestData).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] AlbumGetInfo { + get { + object obj = ResourceManager.GetObject("AlbumGetInfo", resourceCulture); + return ((byte[])(obj)); + } + } + } +} diff --git a/IF.Lastfm.Core.Tests/TestData.resx b/IF.Lastfm.Core.Tests/TestData.resx new file mode 100644 index 0000000..063439c --- /dev/null +++ b/IF.Lastfm.Core.Tests/TestData.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + resources\albumgetinfo.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/IF.Lastfm.Core.Tests/app.config b/IF.Lastfm.Core.Tests/app.config index ccf6a03..ace610d 100644 --- a/IF.Lastfm.Core.Tests/app.config +++ b/IF.Lastfm.Core.Tests/app.config @@ -1,19 +1,19 @@ - + - - + + - - + + - - + + - + diff --git a/IF.Lastfm.Core.Tests/packages.config b/IF.Lastfm.Core.Tests/packages.config index d1df566..f2ba7f8 100644 --- a/IF.Lastfm.Core.Tests/packages.config +++ b/IF.Lastfm.Core.Tests/packages.config @@ -1,7 +1,7 @@  - + diff --git a/IF.Lastfm.Core/Api/AlbumApi.cs b/IF.Lastfm.Core/Api/AlbumApi.cs new file mode 100644 index 0000000..f3cfa22 --- /dev/null +++ b/IF.Lastfm.Core/Api/AlbumApi.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Threading.Tasks; +using IF.Lastfm.Core.Objects; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace IF.Lastfm.Core.Api +{ + public class AlbumApi : IAlbumApi + { + public IAuth Auth { get; private set; } + + public AlbumApi(IAuth auth) + { + Auth = auth; + } + + public async Task GetAlbumInfoAsync(string artistname, string albumname, bool autocorrect = false) + { + const string apiMethod = "album.getInfo"; + + var parameters = new Dictionary + { + {"artist", artistname}, + {"album", albumname}, + {"autocorrect", Convert.ToInt32(autocorrect).ToString()} + }; + + var apiUrl = LastFm.FormatApiUrl(apiMethod, Auth.ApiKey, parameters); + + var httpClient = new HttpClient(); + + var lastResponse = await httpClient.GetAsync(apiUrl); + + if (lastResponse.IsSuccessStatusCode) + { + var json = await lastResponse.Content.ReadAsStringAsync(); + + var jtoken = JsonConvert.DeserializeObject(json); + + var album = Album.ParseJToken(jtoken.SelectToken("album")); + + return album; + } + else + { + // ??? + + throw new NotImplementedException(); + } + } + + public async Task GetAlbumInfoWithMbidAsync(string mbid, bool autocorrect = false) + { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/IF.Lastfm.Core/Api/Auth.cs b/IF.Lastfm.Core/Api/Auth.cs index 0e8a626..087a291 100644 --- a/IF.Lastfm.Core/Api/Auth.cs +++ b/IF.Lastfm.Core/Api/Auth.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; +using IF.Lastfm.Core.Objects; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using xBrainLab.Security.Cryptography; @@ -12,25 +13,27 @@ public class Auth : IAuth private const string ApiSignatureSeedFormat = "api_key{0}method{1}password{2}username{3}{4}"; private const string ApiAuthMethod = "auth.getMobileSession"; - protected string ApiSecret { get; set; } - public string ApiKey { get; set; } + private readonly string _apiSecret; + + public bool HasAuthenticated { get { return User != null; } } + public string ApiKey { get; private set; } + public UserSession User { get; private set; } public Auth(string apikey, string secret) { ApiKey = apikey; - ApiSecret = secret; + _apiSecret = secret; } - public async Task GetSessionTokenAsync(string username, string password) + public async Task GetSessionTokenAsync(string username, string password) { const string apiMethod = "auth.getMobileSession"; - var apisigseed = string.Format(ApiSignatureSeedFormat, ApiKey, ApiAuthMethod, password, username, ApiSecret); + var apisigseed = string.Format(ApiSignatureSeedFormat, ApiKey, ApiAuthMethod, password, username, _apiSecret); var apisig = MD5.GetHashString(apisigseed); - var lastfm = new LastFm(); - var postContent = lastfm.CreatePostBody(apiMethod, ApiKey, apisig, new Dictionary + var postContent = LastFm.CreatePostBody(apiMethod, ApiKey, apisig, new Dictionary { {"password", password}, {"username", username} @@ -41,9 +44,7 @@ public async Task GetSessionTokenAsync(string username, string pass var json = await response.Content.ReadAsStringAsync(); var sessionObject = JsonConvert.DeserializeObject(json).GetValue("session"); - var session = JsonConvert.DeserializeObject(sessionObject.ToString()); - - return session; + User = JsonConvert.DeserializeObject(sessionObject.ToString()); } } } \ No newline at end of file diff --git a/IF.Lastfm.Core/Api/IAlbumApi.cs b/IF.Lastfm.Core/Api/IAlbumApi.cs new file mode 100644 index 0000000..dd254fe --- /dev/null +++ b/IF.Lastfm.Core/Api/IAlbumApi.cs @@ -0,0 +1,13 @@ +using System.Threading.Tasks; +using IF.Lastfm.Core.Objects; + +namespace IF.Lastfm.Core.Api +{ + public interface IAlbumApi + { + IAuth Auth { get; } + + Task GetAlbumInfoAsync(string artist, string album, bool autocorrect = false); + Task GetAlbumInfoWithMbidAsync(string mbid, bool autocorrect = false); + } +} \ No newline at end of file diff --git a/IF.Lastfm.Core/Api/IAuth.cs b/IF.Lastfm.Core/Api/IAuth.cs index 0522fa3..3093955 100644 --- a/IF.Lastfm.Core/Api/IAuth.cs +++ b/IF.Lastfm.Core/Api/IAuth.cs @@ -1,10 +1,13 @@ using System.Threading.Tasks; +using IF.Lastfm.Core.Objects; namespace IF.Lastfm.Core.Api { public interface IAuth { + bool HasAuthenticated { get; } string ApiKey { get; } + UserSession User { get; } /// /// Gets the session token which is used as authentication for any service calls. @@ -13,6 +16,7 @@ public interface IAuth /// Username /// User's password /// Session token used to authenticate calls to last.fm - Task GetSessionTokenAsync(string username, string password); + /// API: Auth.getMobileSession + Task GetSessionTokenAsync(string username, string password); } } \ No newline at end of file diff --git a/IF.Lastfm.Core/IF.Lastfm.Core.csproj b/IF.Lastfm.Core/IF.Lastfm.Core.csproj index 98794cd..a9cca61 100644 --- a/IF.Lastfm.Core/IF.Lastfm.Core.csproj +++ b/IF.Lastfm.Core/IF.Lastfm.Core.csproj @@ -39,11 +39,16 @@ + + + + + diff --git a/IF.Lastfm.Core/LastFm.cs b/IF.Lastfm.Core/LastFm.cs index 040105e..6141ed1 100644 --- a/IF.Lastfm.Core/LastFm.cs +++ b/IF.Lastfm.Core/LastFm.cs @@ -25,7 +25,7 @@ public class LastFm : ILastFm #region Api helper methods - public string FormatApiUrl(string method, string apikey, Dictionary parameters = null, bool secure = false) + public static string FormatApiUrl(string method, string apikey, Dictionary parameters = null, bool secure = false) { if (parameters == null) { @@ -34,7 +34,7 @@ public string FormatApiUrl(string method, string apikey, Dictionary kv.Key)); + var querystring = LastFm.FormatQueryParameters(parameters.OrderBy(kv => kv.Key)); var protocol = secure ? "https" @@ -43,7 +43,7 @@ public string FormatApiUrl(string method, string apikey, Dictionary> parameters) { var init = new Dictionary @@ -60,7 +60,7 @@ public FormUrlEncodedContent CreatePostBody(string method, string apikey, string } - public string FormatQueryParameters(IEnumerable> parameters) + public static string FormatQueryParameters(IEnumerable> parameters) { const string parameterFormat = "&{0}={1}"; diff --git a/IF.Lastfm.Core/Objects/Album.cs b/IF.Lastfm.Core/Objects/Album.cs new file mode 100644 index 0000000..f911b9f --- /dev/null +++ b/IF.Lastfm.Core/Objects/Album.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace IF.Lastfm.Core.Objects +{ + public class Album + { + #region Properties + + public string Name { get; set; } + public IEnumerable Tracks { get; set; } + + public string ArtistName { get; set; } + public string ArtistId { get; set; } + + public DateTime ReleaseDateUtc { get; set; } + + public int ListenerCount { get; set; } + public int TotalPlayCount { get; set; } + + public string Mbid { get; set; } + + public IEnumerable TopTags { get; set; } + + public Uri Url { get; set; } + + #endregion + + /// + /// TODO datetime parsing + /// TODO images + /// TODO tags + /// TODO tracks + /// + /// + /// + public static Album ParseJToken(JToken token) + { + var a = new Album(); + + a.ArtistName = token.Value("artist"); + a.ArtistId = token.Value("id"); + a.ListenerCount = token.Value("listeners"); + a.Mbid = token.Value("mbid"); + a.Name = token.Value("name"); + a.TotalPlayCount = token.Value("playcount"); + + a.Url = new Uri(token.Value("url"), UriKind.Absolute); + + return a; + } + } +} diff --git a/IF.Lastfm.Core/Objects/Tag.cs b/IF.Lastfm.Core/Objects/Tag.cs new file mode 100644 index 0000000..c794031 --- /dev/null +++ b/IF.Lastfm.Core/Objects/Tag.cs @@ -0,0 +1,6 @@ +namespace IF.Lastfm.Core.Objects +{ + public class Tag + { + } +} \ No newline at end of file diff --git a/IF.Lastfm.Core/Objects/Track.cs b/IF.Lastfm.Core/Objects/Track.cs new file mode 100644 index 0000000..a9eccf4 --- /dev/null +++ b/IF.Lastfm.Core/Objects/Track.cs @@ -0,0 +1,6 @@ +namespace IF.Lastfm.Core.Objects +{ + public class Track + { + } +} \ No newline at end of file diff --git a/IF.Lastfm.Core/Objects/UserSession.cs b/IF.Lastfm.Core/Objects/UserSession.cs index 322e7ba..fd3239e 100644 --- a/IF.Lastfm.Core/Objects/UserSession.cs +++ b/IF.Lastfm.Core/Objects/UserSession.cs @@ -1,7 +1,7 @@ using IF.Lastfm.Core.Json; using Newtonsoft.Json; -namespace IF.Lastfm.Core +namespace IF.Lastfm.Core.Objects { public class UserSession { diff --git a/IF.Lastfm.sln b/IF.Lastfm.sln index b89851e..338d531 100644 --- a/IF.Lastfm.sln +++ b/IF.Lastfm.sln @@ -11,7 +11,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{81B53C ProjectSection(SolutionItems) = preProject .nuget\NuGet.Config = .nuget\NuGet.Config .nuget\NuGet.exe = .nuget\NuGet.exe - .nuget\NuGet.targets = .nuget\NuGet.targets EndProjectSection EndProject Global