Moved track.updateNowPlaying to a command

Also
- Fix for track.scrobble test failing half the time
- Changed signature of user.getRecentTracks method to make since parameter optional, added note about different behaviour with 0 or 1 as page number
- Changed constructors for Scrobble
- Fixed DateTime issue in test serialise method
This commit is contained in:
Rikki Tooley 2015-01-03 23:32:19 +00:00
parent 85474f2ea2
commit adf6d7316b
13 changed files with 192 additions and 75 deletions

View File

@ -18,7 +18,12 @@ public class TrackScrobbleCommandTests : CommandIntegrationTestsBase
public async Task ScrobblesSingle()
{
var trackPlayed = DateTime.UtcNow.AddMinutes(-1);
var testScrobble = new Scrobble("Hot Chip", "The Warning", "Over and Over", trackPlayed, "Hot Chip", false);
var testScrobble = new Scrobble("Hot Chip", "The Warning", "Over and Over")
{
AlbumArtist = ARTIST_NAME,
TimePlayed = trackPlayed,
ChosenByUser = false
};
var trackApi = new TrackApi(Auth);
var response = await trackApi.ScrobbleAsync(testScrobble);
@ -26,7 +31,7 @@ public async Task ScrobblesSingle()
Assert.IsTrue(response.Success);
var userApi = new UserApi(Auth);
var tracks = await userApi.GetRecentScrobbles(Auth.UserSession.Username, trackPlayed.AddSeconds(-10), 0, 1);
var tracks = await userApi.GetRecentScrobbles(Auth.UserSession.Username, null, 0, 1);
var expectedTrack = new LastTrack
{
@ -40,7 +45,7 @@ public async Task ScrobblesSingle()
"http://userserve-ak.last.fm/serve/64s/50921593.png",
"http://userserve-ak.last.fm/serve/126/50921593.png",
"http://userserve-ak.last.fm/serve/300x300/50921593.png"),
TimePlayed = trackPlayed.AddMilliseconds(-trackPlayed.Millisecond)
TimePlayed = trackPlayed.RoundToNearestSecond()
};
var expectedJson = expectedTrack.TestSerialise();

View File

@ -0,0 +1,58 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using IF.Lastfm.Core.Api;
using IF.Lastfm.Core.Api.Commands.TrackApi;
using IF.Lastfm.Core.Objects;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace IF.Lastfm.Core.Tests.Integration.Commands
{
[TestClass]
public class TrackUpdateNowPlayingCommandTests : CommandIntegrationTestsBase
{
private const string ARTIST_NAME = "Crystal Castles";
private const string ALBUM_NAME = "Crystal Castles ( II )";
private const string TRACK_NAME = "Not in Love";
[TestMethod]
public async Task UpdatesNowPlaying()
{
var trackPlayed = DateTime.UtcNow.AddMinutes(-1);
var testScrobble = new Scrobble(ARTIST_NAME, ALBUM_NAME, TRACK_NAME)
{
TimePlayed = trackPlayed,
Duration = new TimeSpan(0, 3, 49),
AlbumArtist = ARTIST_NAME
};
var trackApi = new TrackApi(Auth);
var response = await trackApi.UpdateNowPlayingAsync(testScrobble);
Assert.IsTrue(response.Success);
var userApi = new UserApi(Auth);
var tracks = await userApi.GetRecentScrobbles(Auth.UserSession.Username, null, 1, 1);
var expectedTrack = new LastTrack
{
Name = TRACK_NAME,
ArtistName = ARTIST_NAME,
AlbumName = ALBUM_NAME,
Mbid = "1b9ee1d8-c5a7-44d9-813e-85beb0d59f1b",
ArtistMbid = "b1570544-93ab-4b2b-8398-131735394202",
Url = new Uri("http://www.last.fm/music/Crystal+Castles/_/Not+in+Love"),
Images = new LastImageSet("http://userserve-ak.last.fm/serve/34s/61473043.png",
"http://userserve-ak.last.fm/serve/64s/61473043.png",
"http://userserve-ak.last.fm/serve/126/61473043.png",
"http://userserve-ak.last.fm/serve/300x300/61473043.png"),
IsNowPlaying = true
};
var expectedJson = expectedTrack.TestSerialise();
var actualJson = tracks.Content.FirstOrDefault().TestSerialise();
Assert.AreEqual(expectedJson, actualJson, expectedJson.DifferencesTo(actualJson));
}
}
}

View File

@ -52,6 +52,7 @@
<ItemGroup>
<Compile Include="Commands\CommandIntegrationTestsBase.cs" />
<Compile Include="Commands\TrackScrobbleCommandTests.cs" />
<Compile Include="Commands\TrackUpdateNowPlayingCommandTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>

View File

@ -18,7 +18,7 @@ public class UserGetRecentTracksCommandTests : CommandTestsBase
[TestInitialize]
public void Initialise()
{
_command = new UserGetRecentTracksCommand(MAuth.Object, "rj", DateTime.MinValue)
_command = new UserGetRecentTracksCommand(MAuth.Object, "rj")
{
Count = 1
};

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Newtonsoft.Json;
@ -7,13 +8,13 @@ namespace IF.Lastfm.Core.Tests
{
public static class TestHelper
{
private static JsonSerializerSettings _testSerialiserSettings;
private static readonly JsonSerializerSettings _testSerialiserSettings;
static TestHelper()
{
_testSerialiserSettings = new JsonSerializerSettings
{
DateFormatString = "yyyy-MM-dd HH:mm:ss.fff zzz",
DateFormatString = "yyyy-MM-dd HH:mm:ss.fff",
NullValueHandling = NullValueHandling.Ignore
};
}
@ -73,5 +74,14 @@ public static IEnumerable<T> WrapEnumerable<T>(this T t)
{
return new[] {t};
}
public static DateTime RoundToNearestSecond(this DateTime dt)
{
var ms = dt.Millisecond;
return ms < 500
? dt.AddMilliseconds(-ms)
: dt.AddMilliseconds(1000 - ms);
}
}
}

View File

@ -16,11 +16,11 @@ internal class TrackScrobbleCommand : PostAsyncCommandBase<LastResponse>
public string AlbumArtist { get; set; }
public DateTime TimePlayed { get; set; }
public DateTime? TimePlayed { get; set; }
public bool ChosenByUser { get; set; }
public TrackScrobbleCommand(ILastAuth auth, string artist, string album, string track, string albumArtist, DateTime timeplayed)
public TrackScrobbleCommand(ILastAuth auth, string artist, string album, string track, string albumArtist, DateTime? timeplayed)
: base(auth)
{
Method = "track.scrobble";
@ -45,7 +45,11 @@ public override void SetParameters()
Parameters.Add("track", Track);
Parameters.Add("albumArtist", AlbumArtist);
Parameters.Add("chosenByUser", Convert.ToInt32(ChosenByUser).ToString());
Parameters.Add("timestamp", TimePlayed.ToUnixTimestamp().ToString());
if (TimePlayed.HasValue)
{
Parameters.Add("timestamp", TimePlayed.Value.ToUnixTimestamp().ToString());
}
}
public async override Task<LastResponse> HandleResponse(HttpResponseMessage response)

View File

@ -0,0 +1,69 @@
using IF.Lastfm.Core.Api.Enums;
using IF.Lastfm.Core.Api.Helpers;
using System;
using System.Net.Http;
using System.Threading.Tasks;
namespace IF.Lastfm.Core.Api.Commands.TrackApi
{
internal class TrackUpdateNowPlayingCommand : PostAsyncCommandBase<LastResponse>
{
public string Artist { get; set; }
public string Album { get; set; }
public string Track { get; set; }
public string AlbumArtist { get; set; }
public bool ChosenByUser { get; set; }
public TimeSpan? Duration { get; set; }
public TrackUpdateNowPlayingCommand(ILastAuth auth, string artist, string album, string track)
: base(auth)
{
Method = "track.updateNowPlaying";
Artist = artist;
Album = album;
Track = track;
}
public TrackUpdateNowPlayingCommand(ILastAuth auth, Scrobble scrobble)
: this(auth, scrobble.Artist, scrobble.Album, scrobble.Track)
{
ChosenByUser = scrobble.ChosenByUser;
Duration = scrobble.Duration;
}
public override void SetParameters()
{
Parameters.Add("artist", Artist);
Parameters.Add("album", Album);
Parameters.Add("track", Track);
Parameters.Add("albumArtist", AlbumArtist);
Parameters.Add("chosenByUser", Convert.ToInt32(ChosenByUser).ToString());
if (Duration.HasValue)
{
Parameters.Add("duration", Duration.Value.TotalSeconds.ToString());
}
}
public async override Task<LastResponse> HandleResponse(HttpResponseMessage response)
{
var json = await response.Content.ReadAsStringAsync();
LastFmApiError error;
if (LastFm.IsResponseValid(json, out error) && response.IsSuccessStatusCode)
{
return LastResponse.CreateSuccessResponse();
}
else
{
return LastResponse.CreateErrorResponse<LastResponse>(error);
}
}
}
}

View File

@ -15,20 +15,23 @@ internal class UserGetRecentTracksCommand : GetAsyncCommandBase<PageResponse<Las
{
public string Username { get; private set; }
public DateTime From { get; private set; }
public DateTime? From { get; set; }
public UserGetRecentTracksCommand(ILastAuth auth, string username, DateTime from) : base(auth)
public UserGetRecentTracksCommand(ILastAuth auth, string username) : base(auth)
{
Method = "user.getRecentTracks";
Username = username;
From = from;
}
public override void SetParameters()
{
Parameters.Add("user", Username);
Parameters.Add("from", From.ToUnixTimestamp().ToString());
if (From.HasValue)
{
Parameters.Add("from", From.Value.ToUnixTimestamp().ToString());
}
AddPagingParameters();
DisableCaching();

View File

@ -19,10 +19,7 @@ Task<PageResponse<LastAlbum>> GetTopAlbums(string username,
int startIndex = 0,
int endIndex = LastFm.DefaultPageLength);
Task<PageResponse<LastTrack>> GetRecentScrobbles(string username,
DateTime since,
int startIndex = 0,
int endIndex = LastFm.DefaultPageLength);
Task<PageResponse<LastTrack>> GetRecentScrobbles(string username, DateTime? since = null, int pagenumber = 0, int count = LastFm.DefaultPageLength);
Task<PageResponse<LastStation>> GetRecentStations(string username,
int pagenumber,

View File

@ -7,37 +7,26 @@ public class Scrobble
#region Properties
public string Artist { get; private set; }
public string AlbumArtist { get; private set; }
public string AlbumArtist { get; set; }
public string Album { get; private set; }
public string Track { get; private set; }
public DateTime TimePlayed { get; private set; }
public bool ChosenByUser { get; private set; }
public TimeSpan Duration { get; private set; }
public DateTime? TimePlayed { get; set; }
public bool ChosenByUser { get; set; }
public TimeSpan? Duration { get; set; }
#endregion
public Scrobble(string artist, string album, string track,
string albumartist = "", bool chosenByUser = true)
public Scrobble(string artist, string album, string track)
{
Artist = artist;
Album = album;
Track = track;
AlbumArtist = string.IsNullOrWhiteSpace(albumartist) ? artist : albumartist;
ChosenByUser = chosenByUser;
}
public Scrobble(string artist, string album, string track, DateTime timeplayed,
string albumartist = "", bool chosenByUser = true)
: this(artist, album, track, albumartist, chosenByUser)
{
TimePlayed = timeplayed;
}
public Scrobble(string artist, string album, string track, DateTime timeplayed, TimeSpan duration,
string albumartist = "", bool chosenByUser = true) : this(artist, album, track, timeplayed, albumartist, chosenByUser)
{
Duration = duration;
}
}
}

View File

@ -23,39 +23,10 @@ public Task<LastResponse> ScrobbleAsync(Scrobble scrobble)
return command.ExecuteAsync();
}
public async Task<LastResponse> UpdateNowPlayingAsync(Scrobble scrobble)
public Task<LastResponse> UpdateNowPlayingAsync(Scrobble scrobble)
{
const string apiMethod = "track.updateNowPlaying";
var methodParameters = new Dictionary<string, string>
{
{"duration", scrobble.Duration.TotalSeconds == 0 ? "" : ((int)scrobble.Duration.TotalSeconds).ToString()},
{"artist", scrobble.Artist},
{"album", scrobble.Album},
{"track", scrobble.Track},
{"albumArtist", scrobble.AlbumArtist}
};
var apisig = Auth.GenerateMethodSignature(apiMethod, methodParameters);
var postContent = LastFm.CreatePostBody(apiMethod,
Auth.ApiKey,
apisig,
methodParameters);
var httpClient = new HttpClient();
HttpResponseMessage response = await httpClient.PostAsync(LastFm.ApiRoot, postContent);
string json = await response.Content.ReadAsStringAsync();
LastFmApiError error;
if (LastFm.IsResponseValid(json, out error) && response.IsSuccessStatusCode)
{
return LastResponse.CreateSuccessResponse();
}
else
{
return LastResponse.CreateErrorResponse<LastResponse>(error);
}
var command = new TrackUpdateNowPlayingCommand(Auth, scrobble);
return command.ExecuteAsync();
}
public async Task<PageResponse<LastShout>> GetShoutsForTrackAsync(string trackname, string artistname, bool autocorrect = false, int page = 0, int count = LastFm.DefaultPageLength)

View File

@ -37,12 +37,21 @@ public async Task<PageResponse<LastAlbum>> GetTopAlbums(string username, LastSta
return await command.ExecuteAsync();
}
public async Task<PageResponse<LastTrack>> GetRecentScrobbles(string username, DateTime since, int pagenumber = 0, int count = LastFm.DefaultPageLength)
/// <summary>
/// Gets a list of recent scrobbled tracks for this user in reverse date order.
/// </summary>
/// <param name="username">Username to get scrobbles for.</param>
/// <param name="since">Lower threshold for scrobbles. Will not return scrobbles from before this time.</param>
/// <param name="pagenumber">Page numbering starts from 1. If set to 0, will not include the "now playing" track</param>
/// <param name="count">Amount of scrobbles to return for this page.</param>
/// <returns>Enumerable of LastTrack</returns>
public async Task<PageResponse<LastTrack>> GetRecentScrobbles(string username, DateTime? since = null, int pagenumber = 0, int count = LastFm.DefaultPageLength)
{
var command = new UserGetRecentTracksCommand(Auth, username, since)
var command = new UserGetRecentTracksCommand(Auth, username)
{
Page = pagenumber,
Count = count
Count = count,
From = since
};
return await command.ExecuteAsync();

View File

@ -43,6 +43,7 @@
<Compile Include="Api\Commands\AlbumApi\GetAlbumTopTagsCommand.cs" />
<Compile Include="Api\Commands\LibraryApi\LibraryGetTracksCommand.cs" />
<Compile Include="Api\Commands\TrackApi\TrackScrobbleCommand.cs" />
<Compile Include="Api\Commands\TrackApi\TrackUpdateNowPlayingCommand.cs" />
<Compile Include="Api\Commands\UnauthenticatedPostAsyncCommandBase.cs" />
<Compile Include="Api\Commands\UserApi\GetRecommendedArtistsCommand.cs" />
<Compile Include="Api\ILibraryApi.cs" />