Permalink
Browse files

Adding initial Library api methods, and fixing bug with pagination wh…

…ere page number sent to Last.Fm was zero-indexed and must be 1-indexed
  • Loading branch information...
1 parent 2b9beec commit 64bdb02605aaa5073154110e0057cbd737c28572 @michaellavelle committed Apr 7, 2012
Showing with 584 additions and 23 deletions.
  1. +19 −0 src/main/java/org/springframework/social/lastfm/api/Album.java
  2. +21 −0 src/main/java/org/springframework/social/lastfm/api/AlbumTrack.java
  3. +2 −0 src/main/java/org/springframework/social/lastfm/api/LastFm.java
  4. +39 −0 src/main/java/org/springframework/social/lastfm/api/LibraryOperations.java
  5. +1 −1 src/main/java/org/springframework/social/lastfm/api/UserOperations.java
  6. +1 −1 src/main/java/org/springframework/social/lastfm/api/impl/AbstractLastFmOperations.java
  7. +11 −0 src/main/java/org/springframework/social/lastfm/api/impl/LastFmTemplate.java
  8. +139 −0 src/main/java/org/springframework/social/lastfm/api/impl/LibraryTemplate.java
  9. +2 −2 src/main/java/org/springframework/social/lastfm/api/impl/TrackTemplate.java
  10. +15 −16 src/main/java/org/springframework/social/lastfm/api/impl/UserTemplate.java
  11. +34 −0 src/main/java/org/springframework/social/lastfm/api/impl/json/AlbumMixin.java
  12. +39 −0 src/main/java/org/springframework/social/lastfm/api/impl/json/AlbumTrackMixin.java
  13. +34 −0 src/main/java/org/springframework/social/lastfm/api/impl/json/LastFmAlbumTracksResponse.java
  14. +8 −0 src/main/java/org/springframework/social/lastfm/api/impl/json/LastFmModule.java
  15. +52 −0 src/main/java/org/springframework/social/lastfm/api/impl/json/lists/AlbumTrackListContainer.java
  16. +52 −0 ...main/java/org/springframework/social/lastfm/api/impl/json/lists/LastFmAlbumTrackListResponse.java
  17. +112 −3 src/test/java/org/springframework/social/lastfm/api/UserTemplateTest.java
  18. +1 −0 src/test/resources/org/springframework/social/lastfm/api/testdata/empty-library-response.json
  19. +1 −0 src/test/resources/org/springframework/social/lastfm/api/testdata/library-single-track-response.json
  20. +1 −0 src/test/resources/org/springframework/social/lastfm/api/testdata/library-tracks.json
View
19 src/main/java/org/springframework/social/lastfm/api/Album.java
@@ -0,0 +1,19 @@
+package org.springframework.social.lastfm.api;
+
+public class Album {
+
+ private String name;
+
+ public Album(String name)
+ {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
View
21 src/main/java/org/springframework/social/lastfm/api/AlbumTrack.java
@@ -0,0 +1,21 @@
+package org.springframework.social.lastfm.api;
+
+public class AlbumTrack extends Track {
+
+ private Album album;
+
+ public Album getAlbum() {
+ return album;
+ }
+
+ public void setAlbum(Album album) {
+ this.album = album;
+ }
+
+ public AlbumTrack(String url, String name, String musicBrainsId,
+ Artist artist,Album album) {
+ super(url, name, musicBrainsId, artist);
+ this.album = album;
+ }
+
+}
View
2 src/main/java/org/springframework/social/lastfm/api/LastFm.java
@@ -29,4 +29,6 @@
public TrackOperations trackOperations();
+ public LibraryOperations libraryOperations();
+
}
View
39 src/main/java/org/springframework/social/lastfm/api/LibraryOperations.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.social.lastfm.api;
+
+import java.util.Date;
+import java.util.List;
+
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+
+/**
+ * @author Michael Lavelle
+ */
+public interface LibraryOperations {
+
+ public void addTrack(String artistName, String trackName);
+
+ public void removeTrack(String artistName, String trackName);
+
+
+ public Page<AlbumTrack> getTracks(String userName);
+
+ public Page<AlbumTrack> getTracks(String userName,Pageable pageable);
+
+
+}
View
2 src/main/java/org/springframework/social/lastfm/api/UserOperations.java
@@ -71,5 +71,5 @@
public Page<Artist> getRecommendedArtists();
public Page<Artist> getRecommendedArtists(Pageable pageable);
-
+
}
View
2 src/main/java/org/springframework/social/lastfm/api/impl/AbstractLastFmOperations.java
@@ -56,7 +56,7 @@ protected void setPageableParamsIfSpecified(Map<String,String> params,Pageable p
{
if (pageable != null)
{
- params.put("page",new Integer(pageable.getPageNumber()).toString());
+ params.put("page",new Integer(pageable.getPageNumber() + 1).toString());
params.put("limit", new Integer(pageable.getPageSize()).toString());
}
}
View
11 src/main/java/org/springframework/social/lastfm/api/impl/LastFmTemplate.java
@@ -25,6 +25,7 @@
import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter;
import org.springframework.social.NotAuthorizedException;
import org.springframework.social.lastfm.api.LastFm;
+import org.springframework.social.lastfm.api.LibraryOperations;
import org.springframework.social.lastfm.api.TrackOperations;
import org.springframework.social.lastfm.api.UserOperations;
import org.springframework.social.lastfm.api.impl.json.LastFmModule;
@@ -41,6 +42,7 @@
private UserOperations userOperations;
private TrackOperations trackOperations;
+ private LibraryOperations libraryOperations;
private ObjectMapper objectMapper;
@@ -60,6 +62,10 @@ private void initSubApis(LastFmAccessGrant lastFmAccessGrant,
trackOperations = new TrackTemplate(getRestTemplate(),
lastFmAccessGrant, apiKey, secret, isAuthorized());
+
+ libraryOperations = new LibraryTemplate(getRestTemplate(),
+ lastFmAccessGrant, apiKey, secret, isAuthorized());
+
}
@@ -128,5 +134,10 @@ public UserOperations userOperations() {
public TrackOperations trackOperations() {
return trackOperations;
}
+
+ @Override
+ public LibraryOperations libraryOperations() {
+ return libraryOperations;
+ }
}
View
139 src/main/java/org/springframework/social/lastfm/api/impl/LibraryTemplate.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.social.lastfm.api.impl;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.social.lastfm.api.AlbumTrack;
+import org.springframework.social.lastfm.api.Artist;
+import org.springframework.social.lastfm.api.LastFmProfile;
+import org.springframework.social.lastfm.api.LibraryOperations;
+import org.springframework.social.lastfm.api.Shout;
+import org.springframework.social.lastfm.api.SimpleTrack;
+import org.springframework.social.lastfm.api.Track;
+import org.springframework.social.lastfm.api.TrackDescriptor;
+import org.springframework.social.lastfm.api.UserOperations;
+import org.springframework.social.lastfm.api.impl.json.LastFmAlbumTracksResponse;
+import org.springframework.social.lastfm.api.impl.json.LastFmArtistsResponse;
+import org.springframework.social.lastfm.api.impl.json.LastFmUsersResponse;
+import org.springframework.social.lastfm.api.impl.json.LastFmProfileResponse;
+import org.springframework.social.lastfm.api.impl.json.LastFmSimpleTracksResponse;
+import org.springframework.social.lastfm.api.impl.json.LastFmShoutsResponse;
+import org.springframework.social.lastfm.api.impl.json.LastFmTracksResponse;
+import org.springframework.social.lastfm.api.impl.json.lists.LastFmAlbumTrackListResponse;
+import org.springframework.social.lastfm.api.impl.json.lists.LastFmArtistListResponse;
+import org.springframework.social.lastfm.api.impl.json.lists.LastFmShoutListResponse;
+import org.springframework.social.lastfm.api.impl.json.lists.LastFmSimpleTrackListResponse;
+import org.springframework.social.lastfm.api.impl.json.lists.LastFmTrackListResponse;
+import org.springframework.social.lastfm.api.impl.json.lists.LastFmUserListResponse;
+import org.springframework.social.lastfm.api.impl.json.lists.PageInfo;
+import org.springframework.social.lastfm.auth.LastFmAccessGrant;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author Michael Lavelle
+ */
+public class LibraryTemplate extends AbstractLastFmOperations implements
+ LibraryOperations {
+
+ public LibraryTemplate(RestTemplate restTemplate,
+ LastFmAccessGrant lastFmAccessGrant, String apiKey, String secret,
+ boolean isAuthorizedForUser) {
+ super(restTemplate, lastFmAccessGrant, apiKey, secret,
+ isAuthorizedForUser);
+ }
+
+
+ @Override
+ public Page<AlbumTrack> getTracks(String userName) {
+ return getTracks(userName,null);
+ }
+
+ @Override
+ public Page<AlbumTrack> getTracks(String userName,Pageable pageable) {
+
+ Map<String, String> additionalParams = new HashMap<String, String>();
+ additionalParams.put("user", userName);
+ setPageableParamsIfSpecified(additionalParams,pageable);
+
+
+ LastFmApiMethodParameters methodParameters = new LastFmApiMethodParameters(
+ "library.gettracks", apiKey, null, null, additionalParams);
+
+ LastFmAlbumTrackListResponse trackListResponse = restTemplate
+ .getForObject(buildLastFmApiUrl(methodParameters),
+ LastFmAlbumTracksResponse.class).getNestedResponse();
+
+ PageInfo pageInfo = trackListResponse.getPageInfo();
+
+
+ // Last.Fm will return the last page available if a page number is requested greater than or equal to the total pages
+ // Ensure that we override this behaviour and return an empty page for this case
+ if (pageable != null && pageable.getPageNumber() >= pageInfo.getTotalPages())
+ {
+ return new PageImpl<AlbumTrack>(new ArrayList<AlbumTrack>(),pageable,pageInfo.getTotal());
+ }
+
+ return new PageImpl<AlbumTrack>(trackListResponse.getTracks(),new PageRequest(pageInfo.getZeroIndexedPage(),pageInfo.getPerPage()),trackListResponse.getPageInfo().getTotal());
+
+ }
+
+
+
+ @Override
+ public void addTrack(String artistName, String trackName) {
+
+ requireAuthorization();
+
+ Map<String, String> additionalParams = new HashMap<String, String>();
+ additionalParams.put("track", trackName);
+ additionalParams.put("artist", artistName);
+
+ LastFmApiMethodParameters methodParameters = new LastFmApiMethodParameters(
+ "library.addtrack", apiKey, lastFmAccessGrant.getToken(), secret,
+ lastFmAccessGrant.getSessionKey(), additionalParams);
+
+ restTemplate.postForObject(baseApiUrl, methodParameters, String.class);
+
+ }
+
+ @Override
+ public void removeTrack(String artistName, String trackName) {
+
+ requireAuthorization();
+
+ Map<String, String> additionalParams = new HashMap<String, String>();
+ additionalParams.put("track", trackName);
+ additionalParams.put("artist", artistName);
+
+ LastFmApiMethodParameters methodParameters = new LastFmApiMethodParameters(
+ "library.removetrack", apiKey, lastFmAccessGrant.getToken(), secret,
+ lastFmAccessGrant.getSessionKey(), additionalParams);
+
+ restTemplate.postForObject(baseApiUrl, methodParameters, String.class);
+
+ }
+
+
+}
View
4 src/main/java/org/springframework/social/lastfm/api/impl/TrackTemplate.java
@@ -71,9 +71,9 @@ public TrackTemplate(RestTemplate restTemplate,
PageInfo pageInfo = trackMatchesResponse.getPageInfo();
- // Last.Fm will return the last page available if a page number is requested greater than the total pages
+ // Last.Fm will return the last page available if a page number is requested greater than or equal to the total pages
// Ensure that we override this behaviour and return an empty page for this case
- if (pageable != null && pageable.getPageNumber() > pageInfo.getTotalPages())
+ if (pageable != null && pageable.getPageNumber() >= pageInfo.getTotalPages())
{
return new PageImpl<TrackSearchResult>(new ArrayList<TrackSearchResult>(),pageable,pageInfo.getTotal());
}
View
31 src/main/java/org/springframework/social/lastfm/api/impl/UserTemplate.java
@@ -109,9 +109,9 @@ public LastFmProfile getUserProfile(String userName) {
PageInfo pageInfo = simpleTrackListResponse.getPageInfo();
- // Last.Fm will return the last page available if a page number is requested greater than the total pages
+ // Last.Fm will return the last page available if a page number is requested greater than or equal to the total pages
// Ensure that we override this behaviour and return an empty page for this case
- if (pageable != null && pageable.getPageNumber() > pageInfo.getTotalPages())
+ if (pageable != null && pageable.getPageNumber() >= pageInfo.getTotalPages())
{
return new PageImpl<SimpleTrack>(new ArrayList<SimpleTrack>(),pageable,pageInfo.getTotal());
}
@@ -145,9 +145,9 @@ public LastFmProfile getUserProfile(String userName) {
PageInfo pageInfo = trackListResponse.getPageInfo();
- // Last.Fm will return the last page available if a page number is requested greater than the total pages
+ // Last.Fm will return the last page available if a page number is requested greater than or equal to the total pages
// Ensure that we override this behaviour and return an empty page for this case
- if (pageable != null && pageable.getPageNumber() > pageInfo.getTotalPages())
+ if (pageable != null && pageable.getPageNumber() >= pageInfo.getTotalPages())
{
return new PageImpl<Track>(new ArrayList<Track>(),pageable,pageInfo.getTotal());
}
@@ -177,12 +177,10 @@ public LastFmProfile getUserProfile(String userName) {
LastFmTracksResponse.class).getNestedResponse();
PageInfo pageInfo = trackListResponse.getPageInfo();
-
-
- // Last.Fm will return the last page available if a page number is requested greater than the total pages
+ // Last.Fm will return the last page available if a page number is requested greater than or equal to the total pages
// Ensure that we override this behaviour and return an empty page for this case
- if (pageable != null && pageable.getPageNumber() > pageInfo.getTotalPages())
+ if (pageable != null && pageable.getPageNumber() >= pageInfo.getTotalPages())
{
return new PageImpl<Track>(new ArrayList<Track>(),pageable,pageInfo.getTotal());
}
@@ -215,9 +213,9 @@ public LastFmProfile getUserProfile(String userName) {
- // Last.Fm will return the last page available if a page number is requested greater than the total pages
+ // Last.Fm will return the last page available if a page number is requested greater than or equal to the total pages
// Ensure that we override this behaviour and return an empty page for this case
- if (pageable != null && pageable.getPageNumber() > pageInfo.getTotalPages())
+ if (pageable != null && pageable.getPageNumber() >= pageInfo.getTotalPages())
{
return new PageImpl<Artist>(new ArrayList<Artist>(),pageable,pageInfo.getTotal());
}
@@ -301,9 +299,9 @@ public void shout(String userName, String message) {
- // Last.Fm will return the last page available if a page number is requested greater than the total pages
+ // Last.Fm will return the last page available if a page number is requested greater than or equal to the total pages
// Ensure that we override this behaviour and return an empty page for this case
- if (pageable != null && pageable.getPageNumber() > pageInfo.getTotalPages())
+ if (pageable != null && pageable.getPageNumber() >= pageInfo.getTotalPages())
{
return new PageImpl<Shout>(new ArrayList<Shout>(),pageable,pageInfo.getTotal());
}
@@ -333,9 +331,9 @@ public void shout(String userName, String message) {
- // Last.Fm will return the last page available if a page number is requested greater than the total pages
+ // Last.Fm will return the last page available if a page number is requested greater than or equal to the total pages
// Ensure that we override this behaviour and return an empty page for this case
- if (pageable != null && pageable.getPageNumber() > pageInfo.getTotalPages())
+ if (pageable != null && pageable.getPageNumber() >= pageInfo.getTotalPages())
{
return new PageImpl<Artist>(new ArrayList<Artist>(),pageable,pageInfo.getTotal());
}
@@ -369,9 +367,9 @@ public void shout(String userName, String message) {
- // Last.Fm will return the last page available if a page number is requested greater than the total pages
+ // Last.Fm will return the last page available if a page number is requested greater than or equal to the total pages
// Ensure that we override this behaviour and return an empty page for this case
- if (pageable != null && pageable.getPageNumber() > pageInfo.getTotalPages())
+ if (pageable != null && pageable.getPageNumber() >= pageInfo.getTotalPages())
{
return new PageImpl<LastFmProfile>(new ArrayList<LastFmProfile>(),pageable,pageInfo.getTotal());
}
@@ -424,6 +422,7 @@ public void love(String artistName, String trackName) {
}
+
@Override
public void unlove(String artistName, String trackName) {
View
34 src/main/java/org/springframework/social/lastfm/api/impl/json/AlbumMixin.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.social.lastfm.api.impl.json;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.annotate.JsonProperty;
+
+/**
+ * Annotated mixin to add Jackson annotations to Track.
+ *
+ * @author Michael Lavelle
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+abstract class AlbumMixin {
+
+ @JsonCreator
+ AlbumMixin(@JsonProperty("name") String name) {
+ }
+
+}
View
39 src/main/java/org/springframework/social/lastfm/api/impl/json/AlbumTrackMixin.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.social.lastfm.api.impl.json;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.springframework.social.lastfm.api.Album;
+import org.springframework.social.lastfm.api.Artist;
+
+/**
+ * Annotated mixin to add Jackson annotations to Track.
+ *
+ * @author Michael Lavelle
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+abstract class AlbumTrackMixin {
+
+ @JsonCreator
+ AlbumTrackMixin(@JsonProperty("url") String url,
+ @JsonProperty("name") String name,
+ @JsonProperty("mbid") String musicBrainsId,
+ @JsonProperty("artist") Artist artist,@JsonProperty("album") Album album) {
+ }
+
+}
View
34 src/main/java/org/springframework/social/lastfm/api/impl/json/LastFmAlbumTracksResponse.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.social.lastfm.api.impl.json;
+
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.springframework.social.lastfm.api.impl.json.lists.LastFmAlbumTrackListResponse;
+import org.springframework.social.lastfm.api.impl.json.lists.LastFmTrackListResponse;
+
+/**
+ * @author Michael Lavelle
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class LastFmAlbumTracksResponse extends AbstractLastFmNestedResponse<LastFmAlbumTrackListResponse>{
+
+ public LastFmAlbumTracksResponse() {
+ super();
+ }
+
+
+
+}
View
8 src/main/java/org/springframework/social/lastfm/api/impl/json/LastFmModule.java
@@ -20,6 +20,8 @@
import org.codehaus.jackson.Version;
import org.codehaus.jackson.map.module.SimpleModule;
+import org.springframework.social.lastfm.api.Album;
+import org.springframework.social.lastfm.api.AlbumTrack;
import org.springframework.social.lastfm.api.Artist;
import org.springframework.social.lastfm.api.Image;
import org.springframework.social.lastfm.api.LastFmProfile;
@@ -28,6 +30,7 @@
import org.springframework.social.lastfm.api.SimpleTrack;
import org.springframework.social.lastfm.api.Track;
import org.springframework.social.lastfm.api.TrackSearchResult;
+import org.springframework.social.lastfm.api.impl.json.lists.AlbumTrackListContainer;
import org.springframework.social.lastfm.api.impl.json.lists.ShoutListContainer;
import org.springframework.social.lastfm.api.impl.json.lists.SimpleTrackListContainer;
import org.springframework.social.lastfm.api.impl.json.lists.TrackListContainer;
@@ -56,6 +59,7 @@ public DateFormat getDateFormat()
public void setupModule(SetupContext context) {
context.setMixInAnnotations(LastFmProfile.class,
LastFmProfileMixin.class);
+ context.setMixInAnnotations(AlbumTrackListContainer.class, AlbumTrackMixin.class);
context.setMixInAnnotations(TrackListContainer.class, TrackMixin.class);
context.setMixInAnnotations(ShoutListContainer.class, ShoutMixin.class);
context.setMixInAnnotations(UserListContainer.class, LastFmProfileMixin.class);
@@ -66,6 +70,8 @@ public void setupModule(SetupContext context) {
context.setMixInAnnotations(SimpleTrackListContainer.class, SimpleTrackMixin.class);
context.setMixInAnnotations(Track.class, TrackMixin.class);
+ context.setMixInAnnotations(AlbumTrack.class, AlbumTrackMixin.class);
+
context.setMixInAnnotations(Shout.class, ShoutMixin.class);
@@ -76,6 +82,8 @@ public void setupModule(SetupContext context) {
context.setMixInAnnotations(SimpleArtist.class, SimpleArtistMixin.class);
context.setMixInAnnotations(Artist.class, ArtistMixin.class);
+ context.setMixInAnnotations(Album.class, AlbumMixin.class);
+
context.setMixInAnnotations(Image.class, ImageMixin.class);
View
52 ...n/java/org/springframework/social/lastfm/api/impl/json/lists/AlbumTrackListContainer.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.social.lastfm.api.impl.json.lists;
+
+import java.util.List;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.springframework.social.lastfm.api.Album;
+import org.springframework.social.lastfm.api.AlbumTrack;
+import org.springframework.social.lastfm.api.Artist;
+import org.springframework.social.lastfm.api.Track;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+/**
+ * Container for a track list - allows for automatic JSON binding from *either* a list of Tracks
+ * or a Map representation of a single track, as LastFm's responds with different Json structures
+ * depending on whether a single track is returned
+ *
+ * @author Michael Lavelle
+ */
+public class AlbumTrackListContainer extends AbstractLastFmListContainer<AlbumTrack> {
+
+ public AlbumTrackListContainer(String url, String name, String musicBrainsId,
+ Artist artist,Album album) {
+ super(new AlbumTrack(url, name, musicBrainsId, artist,album));
+ }
+
+ @JsonCreator
+ public AlbumTrackListContainer(List<AlbumTrack> tracks) {
+ super(tracks);
+
+ }
+
+ public List<AlbumTrack> getTracks() {
+ return elements;
+ }
+
+}
View
52 ...a/org/springframework/social/lastfm/api/impl/json/lists/LastFmAlbumTrackListResponse.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.social.lastfm.api.impl.json.lists;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.springframework.social.lastfm.api.AlbumTrack;
+import org.springframework.social.lastfm.api.Track;
+
+/**
+ * @author Michael Lavelle
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class LastFmAlbumTrackListResponse extends PageInfoContainer {
+
+ private AlbumTrackListContainer trackListContainer;
+
+ @JsonCreator
+ public LastFmAlbumTrackListResponse() {
+ this.trackListContainer = new AlbumTrackListContainer(new ArrayList<AlbumTrack>());
+ }
+
+
+
+ @JsonProperty("track")
+ public void setTrackListContainer(AlbumTrackListContainer trackListContainer) {
+ this.trackListContainer = trackListContainer;
+ }
+
+ public List<AlbumTrack> getTracks() {
+ return trackListContainer.getTracks();
+ }
+
+
+}
View
115 src/test/java/org/springframework/social/lastfm/api/UserTemplateTest.java
@@ -284,6 +284,44 @@ public void getLovedTracks() {
}
@Test
+ public void getLibraryTracks() {
+
+ mockServer
+ .expect(requestTo("http://ws.audioscrobbler.com/2.0/?format=json&api_key=someApiKey&method=library.gettracks&user=mattslip"))
+ .andExpect(method(GET))
+ .andExpect(header("User-Agent", UserAgentHelper.getUserAgent()))
+ .andRespond(
+ withResponse(jsonResource("testdata/library-tracks"),
+ responseHeaders));
+
+ Page<AlbumTrack> tracksPage = lastFm.libraryOperations().getTracks("mattslip");
+ assertEquals(0,tracksPage.getNumber());
+ assertEquals(325,tracksPage.getTotalElements());
+ List<AlbumTrack> tracks = tracksPage.getContent();
+ assertAlbumTrackData(tracks.get(0));
+
+ }
+
+ @Test
+ public void getLibraryTracks_SingleTrackResponse() {
+
+ mockServer
+ .expect(requestTo("http://ws.audioscrobbler.com/2.0/?format=json&api_key=someApiKey&method=library.gettracks&user=mattslip"))
+ .andExpect(method(GET))
+ .andExpect(header("User-Agent", UserAgentHelper.getUserAgent()))
+ .andRespond(
+ withResponse(jsonResource("testdata/library-single-track-response"),
+ responseHeaders));
+
+ Page<AlbumTrack> tracksPage = lastFm.libraryOperations().getTracks("mattslip");
+ assertEquals(0,tracksPage.getNumber());
+ assertEquals(1,tracksPage.getTotalElements());
+ List<AlbumTrack> tracks = tracksPage.getContent();
+ assertAlbumTrackData(tracks.get(0));
+
+ }
+
+ @Test
public void getSimilarTracks() {
mockServer
@@ -466,9 +504,8 @@ public void getLovedTracksSingleTrackResponse() {
}
/**
- * Tests for the case where the loved tracks response contains only a single
- * track. In this case the Json format of the response is different to the
- * response for multiple tracks
+ * Tests for the case where the loved tracks response contains no
+ * tracks.
*/
@Test
public void getLovedTracksEmptyResponse() {
@@ -491,6 +528,31 @@ public void getLovedTracksEmptyResponse() {
}
+ /**
+ * Tests for the case where the library tracks response contains no
+ * tracks.
+ */
+ @Test
+ public void getLibraryTracksEmptyResponse() {
+
+ mockServer
+ .expect(requestTo("http://ws.audioscrobbler.com/2.0/?format=json&api_key=someApiKey&method=library.gettracks&user=mattslip"))
+ .andExpect(method(GET))
+ .andExpect(header("User-Agent", UserAgentHelper.getUserAgent()))
+ .andRespond(
+ withResponse(
+ jsonResource("testdata/empty-library-response"),
+ responseHeaders));
+
+ Page<AlbumTrack> tracksPage = lastFm.libraryOperations().getTracks("mattslip");
+ List<AlbumTrack> tracks = tracksPage.getContent();
+ assertEquals(0,tracksPage.getNumber());
+ assertEquals(0,tracksPage.getTotalElements());
+ assertNotNull(tracks);
+ assertEquals(0,tracks.size());
+
+ }
+
@Test
public void getLovedTracks_withoutAuthorization() {
@@ -587,7 +649,47 @@ public void love() {
}
+ @Test
+ public void addTrackToLibrary() {
+
+ mockServer
+ .expect(requestTo("http://ws.audioscrobbler.com/2.0/"))
+ .andExpect(method(POST))
+ .andExpect(header("User-Agent", UserAgentHelper.getUserAgent()))
+ .andExpect(
+ body("format=json&api_sig=9d70a80fc0ffaea3a74d33a793d0bf91&api_key=someApiKey&sk=someSessionKey&method=library.addtrack&token=someToken&track=My+track+name&artist=My+artist+name"))
+ .andRespond(
+ withResponse(jsonResource("testdata/status-ok"),
+ responseHeaders));
+
+ lastFm.libraryOperations().addTrack("My artist name", "My track name");
+
+ }
+
+ @Test
+ public void removeTrackFromLibrary() {
+
+ mockServer
+ .expect(requestTo("http://ws.audioscrobbler.com/2.0/"))
+ .andExpect(method(POST))
+ .andExpect(header("User-Agent", UserAgentHelper.getUserAgent()))
+ .andExpect(
+ body("format=json&api_sig=3d2860a9ba668aa4344bf3ddb34fffb4&api_key=someApiKey&sk=someSessionKey&method=library.removetrack&token=someToken&track=My+track+name&artist=My+artist+name"))
+ .andRespond(
+ withResponse(jsonResource("testdata/status-ok"),
+ responseHeaders));
+
+ lastFm.libraryOperations().removeTrack("My artist name", "My track name");
+
+ }
+ @Test(expected = NotAuthorizedException.class)
+ public void addTrackToLibrary_unauthorized() {
+
+
+ unauthorizedLastFm.libraryOperations().addTrack("My artist name", "My track name");
+
+ }
@Test(expected = NotAuthorizedException.class)
@@ -675,6 +777,13 @@ private void assertTrackData(Track track) {
.getUrl());
}
+ private void assertAlbumTrackData(AlbumTrack track)
+ {
+ assertTrackData(track);
+ assertNotNull(track.getAlbum());
+ assertEquals("Moon Theory",track.getAlbum().getName());
+ }
+
private void assertArtistData(Artist artist) {
View
1 ...test/resources/org/springframework/social/lastfm/api/testdata/empty-library-response.json
@@ -0,0 +1 @@
+{"tracks":{"#text":"\n","user":"mattslip","page":"0","perPage":"50","totalPages":"0","total":"0"}}
View
1 ...sources/org/springframework/social/lastfm/api/testdata/library-single-track-response.json
@@ -0,0 +1 @@
+{"tracks":{"track":{"name":"Moon Theory","duration":"212000","playcount":"0","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Miami+Horror\/_\/Moon+Theory","streamable":{"#text":"1","fulltrack":"0"},"artist":{"name":"Miami Horror","mbid":"a5db16f8-dadc-4885-88e3-6cff50fa44f3","url":"http:\/\/www.last.fm\/music\/Miami+Horror"},"album":{"name":"Moon Theory","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/61748267.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/61748267.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/61748267.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/61748267.png","size":"extralarge"}]},"@attr":{"user":"michaeltesting","page":"1","perPage":"50","totalPages":"1","total":"1"}}}
View
1 src/test/resources/org/springframework/social/lastfm/api/testdata/library-tracks.json
@@ -0,0 +1 @@
+{"tracks":{"track":[{"name":"Moon Theory","duration":"212000","playcount":"16","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Miami+Horror\/_\/Moon+Theory","streamable":{"#text":"1","fulltrack":"0"},"artist":{"name":"Miami Horror","mbid":"","url":"http:\/\/www.last.fm\/music\/Miami+Horror"},"album":{"name":"Moon Theory","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/61748267.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/61748267.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/61748267.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/61748267.png","size":"extralarge"}]},{"name":"White Horse","duration":"299000","playcount":"11","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Jessica+6\/_\/White+Horse","streamable":{"#text":"1","fulltrack":"0"},"artist":{"name":"Jessica 6","mbid":"db571b33-c9cd-4364-a738-3cf55e9f95d1","url":"http:\/\/www.last.fm\/music\/Jessica+6"},"album":{"name":"White Horse","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/68202412.jpg","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/68202412.jpg","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/68202412.jpg","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/68202412.jpg","size":"extralarge"}]},{"name":"Wherever We Are (GRUM Remix)","duration":"413000","playcount":"10","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Human+Life\/_\/Wherever+We+Are+%28GRUM+Remix%29","streamable":{"#text":"1","fulltrack":"0"},"artist":{"name":"Human Life","mbid":"831afa7f-c8a5-4d8d-9a54-c91f5bd6244f","url":"http:\/\/www.last.fm\/music\/Human+Life"},"album":{"name":"Wherever We Are","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/53115653.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/53115653.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/53115653.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/53115653.png","size":"extralarge"}]},{"name":"Keep Up With You (Lifelike Remix)","duration":"30000","playcount":"10","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Teenage+Bad+Girl\/_\/Keep+Up+With+You+%28Lifelike+Remix%29","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Teenage Bad Girl","mbid":"0e9d0de0-db26-4204-b141-3fe2ddb06ea4","url":"http:\/\/www.last.fm\/music\/Teenage+Bad+Girl"},"album":{"name":"Keep Up With You (Bonus Track Version) - EP","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/59604523.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/59604523.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/59604523.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/59604523.png","size":"extralarge"}]},{"name":"Killing It","duration":"218000","playcount":"9","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/The+Hundred+In+The+Hands\/_\/Killing+It","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"The Hundred In The Hands","mbid":"ce8021ad-6957-4775-913e-be6562cf779b","url":"http:\/\/www.last.fm\/music\/The+Hundred+In+The+Hands"},"album":{"name":"The Hundred in the Hands","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/52139479.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/52139479.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/52139479.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/52139479.png","size":"extralarge"}]},{"name":"Slow Motion","duration":"227000","playcount":"8","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Holy+Ghost%21\/_\/Slow+Motion","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Holy Ghost!","mbid":"3c0d5463-6688-4f4a-8273-a191657d8084","url":"http:\/\/www.last.fm\/music\/Holy+Ghost%21"},"album":{"name":"Holy Ghost!","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/59819213.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/59819213.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/59819213.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/59819213.png","size":"extralarge"}]},{"name":"Don't Turn the Lights On (Aeroplane remix)","duration":"332000","playcount":"8","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Chromeo\/_\/Don%27t+Turn+the+Lights+On+%28Aeroplane+remix%29","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Chromeo","mbid":"647221d0-f6b1-4e03-924c-c59b8059536f","url":"http:\/\/www.last.fm\/music\/Chromeo"},"album":{"name":"Don't Turn the Lights On","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/48434307.jpg","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/48434307.jpg","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/48434307.jpg","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/48434307.jpg","size":"extralarge"}]},{"name":"Music (Monsieur Adi Remix)","duration":"315000","playcount":"8","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Madonna\/_\/Music+%28Monsieur+Adi+Remix%29","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Madonna","mbid":"79239441-bfd5-4981-a70c-55c3f15c1287","url":"http:\/\/www.last.fm\/music\/Madonna"}},{"name":"Skeleton (Grum remix)","duration":"0","playcount":"8","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/The+Good+Natured\/_\/Skeleton+%28Grum+remix%29","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"The Good Natured","mbid":"50eaa78a-c1ca-4610-9d97-d5bc930a6a9c","url":"http:\/\/www.last.fm\/music\/The+Good+Natured"}},{"name":"Perfection","duration":"298000","playcount":"7","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Oh+Land\/_\/Perfection","streamable":{"#text":"1","fulltrack":"0"},"artist":{"name":"Oh Land","mbid":"73700583-9245-4a62-b73b-68f3904a0ef3","url":"http:\/\/www.last.fm\/music\/Oh+Land"},"album":{"name":"Oh Land","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/61372671.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/61372671.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/61372671.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/61372671.png","size":"extralarge"}]},{"name":"Voodoo","duration":"170000","playcount":"7","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Oh+Land\/_\/Voodoo","streamable":{"#text":"1","fulltrack":"0"},"artist":{"name":"Oh Land","mbid":"73700583-9245-4a62-b73b-68f3904a0ef3","url":"http:\/\/www.last.fm\/music\/Oh+Land"},"album":{"name":"Oh Land","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/61372671.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/61372671.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/61372671.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/61372671.png","size":"extralarge"}]},{"name":"Big (Oliver Remix)","duration":"430000","playcount":"7","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Sneaky+Sound+System\/_\/Big+%28Oliver+Remix%29","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Sneaky Sound System","mbid":"495fe320-091e-43eb-9321-54a20e7c3f98","url":"http:\/\/www.last.fm\/music\/Sneaky+Sound+System"},"album":{"name":"Big","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/68751234.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/68751234.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/68751234.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/68751234.png","size":"extralarge"}]},{"name":"Moon Theory","duration":"263000","playcount":"6","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Miami+Horror\/_\/Moon+Theory","streamable":{"#text":"1","fulltrack":"0"},"artist":{"name":"Miami Horror","mbid":"fa92553b-3cd5-4876-a7db-1d9dfcdf9fa9","url":"http:\/\/www.last.fm\/music\/Miami+Horror"},"album":{"name":"Moon Theory","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/59180109.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/59180109.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/59180109.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/59180109.png","size":"extralarge"}]},{"name":"Danger! (Cotton Crew remix)","duration":"279000","playcount":"6","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/The+Sound+of+Arrows\/_\/Danger%21+%28Cotton+Crew+remix%29","streamable":{"#text":"1","fulltrack":"0"},"artist":{"name":"The Sound of Arrows","mbid":"25d6c9b6-051e-4b98-8eb7-bf648889521a","url":"http:\/\/www.last.fm\/music\/The+Sound+of+Arrows"},"album":{"name":"Danger!","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/66436721.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/66436721.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/66436721.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/66436721.png","size":"extralarge"}]},{"name":"Wonderful Life - Arthur Baker Remix Kitsun\u00e9 Edit","duration":"305000","playcount":"6","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Hurts\/_\/Wonderful+Life+-+Arthur+Baker+Remix+Kitsun%C3%A9+Edit","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Hurts","mbid":"bc07552e-d2f4-42c7-8b47-995cc674c81c","url":"http:\/\/www.last.fm\/music\/Hurts"},"album":{"name":"Kitsun\u00e9 Maison Compilation 9: Petit Bateau Edition","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/45995057.jpg","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/45995057.jpg","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/45995057.jpg","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/45995057.jpg","size":"extralarge"}]},{"name":"Stars in Your Eyes","duration":"292000","playcount":"6","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Jessica+6\/_\/Stars+in+Your+Eyes","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Jessica 6","mbid":"db571b33-c9cd-4364-a738-3cf55e9f95d1","url":"http:\/\/www.last.fm\/music\/Jessica+6"},"album":{"name":"See the Light","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/61893503.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/61893503.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/61893503.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/61893503.png","size":"extralarge"}]},{"name":"This Woman's Work (Echoes Remix)","duration":"388000","playcount":"6","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Kate+Bush\/_\/This+Woman%27s+Work+%28Echoes+Remix%29","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Kate Bush","mbid":"4b585938-f271-45e2-b19a-91c634b5e396","url":"http:\/\/www.last.fm\/music\/Kate+Bush"}},{"name":"Doubt","duration":"209000","playcount":"6","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Amanda+Mair\/_\/Doubt","streamable":{"#text":"1","fulltrack":"0"},"artist":{"name":"Amanda Mair","mbid":"e8b0851b-638f-4ec5-90c0-904cde590b40","url":"http:\/\/www.last.fm\/music\/Amanda+Mair"},"album":{"name":"Doubt","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/70472156.jpg","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/70472156.jpg","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/70472156.jpg","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/70472156.jpg","size":"extralarge"}]},{"name":"Commotion","duration":"286000","playcount":"5","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/The+Hundred+In+The+Hands\/_\/Commotion","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"The Hundred In The Hands","mbid":"ce8021ad-6957-4775-913e-be6562cf779b","url":"http:\/\/www.last.fm\/music\/The+Hundred+In+The+Hands"},"album":{"name":"The Hundred in the Hands","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/52139479.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/52139479.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/52139479.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/52139479.png","size":"extralarge"}]},{"name":"Second Go (Echoes Remix)","duration":"340000","playcount":"5","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Lights\/_\/Second+Go+%28Echoes+Remix%29","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Lights","mbid":"dfcb8d48-6cc8-43eb-b4e2-eac68797c60b","url":"http:\/\/www.last.fm\/music\/Lights"}},{"name":"Prisoner of Love","duration":"270000","playcount":"5","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Jessica+6\/_\/Prisoner+of+Love","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Jessica 6","mbid":"db571b33-c9cd-4364-a738-3cf55e9f95d1","url":"http:\/\/www.last.fm\/music\/Jessica+6"},"album":{"name":"See the Light","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/61893503.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/61893503.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/61893503.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/61893503.png","size":"extralarge"}]},{"name":"In the Heat","duration":"264000","playcount":"5","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Jessica+6\/_\/In+the+Heat","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Jessica 6","mbid":"db571b33-c9cd-4364-a738-3cf55e9f95d1","url":"http:\/\/www.last.fm\/music\/Jessica+6"},"album":{"name":"See the Light","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/61893503.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/61893503.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/61893503.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/61893503.png","size":"extralarge"}]},{"name":"Ringing","duration":"300000","playcount":"5","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Vanbot\/_\/Ringing","streamable":{"#text":"1","fulltrack":"0"},"artist":{"name":"Vanbot","mbid":"a5db16f8-dadc-4885-88e3-6cff50fa44f3","url":"http:\/\/www.last.fm\/music\/Vanbot"},"album":{"name":"Vanbot","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/61748267.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/61748267.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/61748267.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/61748267.png","size":"extralarge"}]},{"name":"Puppets (Royksopp Remix)","duration":"280000","playcount":"5","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Depeche+Mode\/_\/Puppets+%28Royksopp+Remix%29","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Depeche Mode","mbid":"8538e728-ca0b-4321-b7e5-cff6565dd4c0","url":"http:\/\/www.last.fm\/music\/Depeche+Mode"}},{"name":"Planets of the Universe (Illicit Club mix)","duration":"469000","playcount":"4","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Stevie+Nicks\/_\/Planets+of+the+Universe+%28Illicit+Club+mix%29","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Stevie Nicks","mbid":"b7f2cca2-72c6-41fb-ae33-53370fc62fe7","url":"http:\/\/www.last.fm\/music\/Stevie+Nicks"},"album":{"name":"Planets of the Universe","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/24815127.jpg","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/24815127.jpg","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/24815127.jpg","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/24815127.jpg","size":"extralarge"}]},{"name":"Strangers In The Wind","duration":"284000","playcount":"4","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Cut+Copy\/_\/Strangers+In+The+Wind","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Cut Copy","mbid":"caaba574-dfbc-4681-8e56-19b5150897d2","url":"http:\/\/www.last.fm\/music\/Cut+Copy"},"album":{"name":"In Ghost Colours","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/69495270.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/69495270.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/69495270.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/69495270.png","size":"extralarge"}]},{"name":"What You Need (Grum Remix)","duration":"270000","playcount":"4","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Priors\/_\/What+You+Need+%28Grum+Remix%29","streamable":{"#text":"1","fulltrack":"0"},"artist":{"name":"Priors","mbid":"f52603f2-1673-478e-b332-a15824509022","url":"http:\/\/www.last.fm\/music\/Priors"},"album":{"name":"What You Need Remixes","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/43063417.jpg","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/43063417.jpg","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/43063417.jpg","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/43063417.jpg","size":"extralarge"}]},{"name":"Dreams","duration":"291000","playcount":"4","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Futurecop%21\/_\/Dreams","streamable":{"#text":"1","fulltrack":"0"},"artist":{"name":"Futurecop!","mbid":"24f7a6d4-c9bf-4f1e-ba90-0f36cb51964c","url":"http:\/\/www.last.fm\/music\/Futurecop%21"},"album":{"name":"The Remixes <3","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/60124769.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/60124769.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/60124769.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/60124769.png","size":"extralarge"}]},{"name":"Love Harder","duration":"243000","playcount":"4","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Ali+Love\/_\/Love+Harder","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Ali Love","mbid":"6326499b-c7be-4f85-a56a-867c8328ab00","url":"http:\/\/www.last.fm\/music\/Ali+Love"},"album":{"name":"Love Harder","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/50958131.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/50958131.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/50958131.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/50958131.png","size":"extralarge"}]},{"name":"Say My Name","duration":"394000","playcount":"4","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Holy+Ghost%21\/_\/Say+My+Name","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Holy Ghost!","mbid":"3c0d5463-6688-4f4a-8273-a191657d8084","url":"http:\/\/www.last.fm\/music\/Holy+Ghost%21"},"album":{"name":"Kitsun\u00e9 Maison Compilation 9: Petit Bateau Edition","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/53651593.jpg","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/53651593.jpg","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/53651593.jpg","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/53651593.jpg","size":"extralarge"}]},{"name":"Wait And See","duration":"219000","playcount":"4","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Holy+Ghost%21\/_\/Wait+And+See","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Holy Ghost!","mbid":"3c0d5463-6688-4f4a-8273-a191657d8084","url":"http:\/\/www.last.fm\/music\/Holy+Ghost%21"},"album":{"name":"Wait And See","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/61126503.jpg","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/61126503.jpg","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/61126503.jpg","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/61126503.jpg","size":"extralarge"}]},{"name":"Dreamy Eyes","duration":"252000","playcount":"4","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Azure+Blue\/_\/Dreamy+Eyes","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Azure Blue","mbid":"ca6e042e-0edd-4137-a8cb-d3418f752e9d","url":"http:\/\/www.last.fm\/music\/Azure+Blue"},"album":{"name":"Rule Of Thirds","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/71645256.jpg","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/71645256.jpg","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/71645256.jpg","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/71645256.jpg","size":"extralarge"}]},{"name":"Call It What You Want - Planet of Sound Remix","duration":"386000","playcount":"4","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Foster+the+People\/_\/Call+It+What+You+Want+-+Planet+of+Sound+Remix","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Foster the People","mbid":"e0e1a584-dd0a-4bd1-88d1-c4c62895039d","url":"http:\/\/www.last.fm\/music\/Foster+the+People"},"album":{"name":"Call It What You Want","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/71598692.jpg","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/71598692.jpg","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/71598692.jpg","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/71598692.jpg","size":"extralarge"}]},{"name":"Big Love","duration":"217000","playcount":"3","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Fleetwood+Mac\/_\/Big+Love","streamable":{"#text":"1","fulltrack":"0"},"artist":{"name":"Fleetwood Mac","mbid":"bd13909f-1c29-4c27-a874-d4aaf27c5b1a","url":"http:\/\/www.last.fm\/music\/Fleetwood+Mac"},"album":{"name":"Tango in the Night","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/63827201.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/63827201.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/63827201.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/63827201.png","size":"extralarge"}]},{"name":"Precious Heart (Lush remix)","duration":"541000","playcount":"3","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Tall+Paul+vs.+INXS\/_\/Precious+Heart+%28Lush+remix%29","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Tall Paul vs. INXS","mbid":"99109694-5d84-43f9-923a-77cbd26d5a5f","url":"http:\/\/www.last.fm\/music\/Tall+Paul+vs.+INXS"},"album":{"name":"MOS - Ibiza Chillout Session 2001 (Disc 2)","position":""},"image":[{"#text":"http:\/\/cdn.last.fm\/flatness\/catalogue\/noimage\/2\/default_album_medium.png","size":"small"},{"#text":"http:\/\/cdn.last.fm\/flatness\/catalogue\/noimage\/2\/default_album_medium.png","size":"medium"},{"#text":"http:\/\/cdn.last.fm\/flatness\/catalogue\/noimage\/2\/default_album_medium.png","size":"large"},{"#text":"http:\/\/cdn.last.fm\/flatness\/catalogue\/noimage\/2\/default_album_medium.png","size":"extralarge"}]},{"name":"Lights & Music","duration":"278000","playcount":"3","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Cut+Copy\/_\/Lights%2B%2526%2BMusic","streamable":{"#text":"1","fulltrack":"0"},"artist":{"name":"Cut Copy","mbid":"caaba574-dfbc-4681-8e56-19b5150897d2","url":"http:\/\/www.last.fm\/music\/Cut+Copy"},"album":{"name":"In Ghost Colours","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/69495270.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/69495270.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/69495270.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/69495270.png","size":"extralarge"}]},{"name":"Freak the Night","duration":"218000","playcount":"3","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Jessica+6\/_\/Freak+the+Night","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Jessica 6","mbid":"db571b33-c9cd-4364-a738-3cf55e9f95d1","url":"http:\/\/www.last.fm\/music\/Jessica+6"},"album":{"name":"See the Light","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/61893503.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/61893503.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/61893503.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/61893503.png","size":"extralarge"}]},{"name":"I Feel Better","duration":"280000","playcount":"3","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Hot+Chip\/_\/I+Feel+Better","streamable":{"#text":"1","fulltrack":"0"},"artist":{"name":"Hot Chip","mbid":"d8915e13-d67a-4aa0-9c0b-1f126af951af","url":"http:\/\/www.last.fm\/music\/Hot+Chip"},"album":{"name":"One Life Stand","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/72410682.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/72410682.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/72410682.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/72410682.png","size":"extralarge"}]},{"name":"Moon Theory (Baby Monster Remix)","duration":"30000","playcount":"3","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Miami+Horror\/_\/Moon+Theory+%28Baby+Monster+Remix%29","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Miami Horror","mbid":"fa92553b-3cd5-4876-a7db-1d9dfcdf9fa9","url":"http:\/\/www.last.fm\/music\/Miami+Horror"}},{"name":"What You Need Grum Remix","duration":"270000","playcount":"3","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Priors\/_\/What+You+Need+Grum+Remix","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Priors","mbid":"f52603f2-1673-478e-b332-a15824509022","url":"http:\/\/www.last.fm\/music\/Priors"},"album":{"name":"What You Need","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/75364116.jpg","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/75364116.jpg","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/75364116.jpg","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/75364116.jpg","size":"extralarge"}]},{"name":"Two Hearts","duration":"147000","playcount":"3","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Azure+Blue\/_\/Two+Hearts","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Azure Blue","mbid":"ca6e042e-0edd-4137-a8cb-d3418f752e9d","url":"http:\/\/www.last.fm\/music\/Azure+Blue"},"album":{"name":"Rule Of Thirds","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/71645256.jpg","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/71645256.jpg","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/71645256.jpg","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/71645256.jpg","size":"extralarge"}]},{"name":"DJ, Ease My Mind","duration":"256000","playcount":"3","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Niki%2B%2526%2BThe%2BDove\/_\/DJ%2C+Ease+My+Mind","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Niki & The Dove","mbid":"","url":"http:\/\/www.last.fm\/music\/Niki%2B%2526%2BThe%2BDove"},"album":{"name":"Northern Lights - New Sounds of Scandinavia","position":""},"image":[{"#text":"http:\/\/cdn.last.fm\/flatness\/catalogue\/noimage\/2\/default_album_medium.png","size":"small"},{"#text":"http:\/\/cdn.last.fm\/flatness\/catalogue\/noimage\/2\/default_album_medium.png","size":"medium"},{"#text":"http:\/\/cdn.last.fm\/flatness\/catalogue\/noimage\/2\/default_album_medium.png","size":"large"},{"#text":"http:\/\/cdn.last.fm\/flatness\/catalogue\/noimage\/2\/default_album_medium.png","size":"extralarge"}]},{"name":"My Shadow","duration":"258000","playcount":"3","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/The+Sound+of+Arrows\/_\/My+Shadow","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"The Sound of Arrows","mbid":"25d6c9b6-051e-4b98-8eb7-bf648889521a","url":"http:\/\/www.last.fm\/music\/The+Sound+of+Arrows"},"album":{"name":"Voyage","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/70197704.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/70197704.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/70197704.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/70197704.png","size":"extralarge"}]},{"name":"Shameless (Mylo Remix)","duration":"428000","playcount":"3","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Bryan+Ferry\/_\/Shameless+%28Mylo+Remix%29","streamable":{"#text":"1","fulltrack":"0"},"artist":{"name":"Bryan Ferry","mbid":"4ef7a9e2-2cf5-483a-8616-ef7791a98026","url":"http:\/\/www.last.fm\/music\/Bryan+Ferry"},"album":{"name":"Shameless","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/76148622.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/76148622.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/76148622.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/76148622.png","size":"extralarge"}]},{"name":"The Catcher in the Rye","duration":"197000","playcount":"3","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Azure+Blue\/_\/The+Catcher+in+the+Rye","streamable":{"#text":"1","fulltrack":"0"},"artist":{"name":"Azure Blue","mbid":"ca6e042e-0edd-4137-a8cb-d3418f752e9d","url":"http:\/\/www.last.fm\/music\/Azure+Blue"},"album":{"name":"Rule Of Thirds","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/71645256.jpg","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/71645256.jpg","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/71645256.jpg","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/71645256.jpg","size":"extralarge"}]},{"name":"Out of Control feat. Paul Parker","duration":"220000","playcount":"3","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Wolfram\/_\/Out+of+Control+feat.+Paul+Parker","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Wolfram","mbid":"7ed0b22a-22ac-4395-89d8-78737526abde","url":"http:\/\/www.last.fm\/music\/Wolfram"},"album":{"name":"Wolfram","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/61347003.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/61347003.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/61347003.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/61347003.png","size":"extralarge"}]},{"name":"It's Not Over","duration":"250000","playcount":"3","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Holy+Ghost%21\/_\/It%27s+Not+Over","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Holy Ghost!","mbid":"3c0d5463-6688-4f4a-8273-a191657d8084","url":"http:\/\/www.last.fm\/music\/Holy+Ghost%21"},"album":{"name":"Holy Ghost!","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/59819213.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/59819213.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/59819213.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/59819213.png","size":"extralarge"}]},{"name":"Little Confusions","duration":"186000","playcount":"3","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Azure+Blue\/_\/Little+Confusions","streamable":{"#text":"1","fulltrack":"0"},"artist":{"name":"Azure Blue","mbid":"ca6e042e-0edd-4137-a8cb-d3418f752e9d","url":"http:\/\/www.last.fm\/music\/Azure+Blue"},"album":{"name":"Rule Of Thirds","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/71645256.jpg","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/71645256.jpg","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/71645256.jpg","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/71645256.jpg","size":"extralarge"}]},{"name":"Numb","duration":"206000","playcount":"3","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Vanbot\/_\/Numb","streamable":{"#text":"1","fulltrack":"0"},"artist":{"name":"Vanbot","mbid":"a5db16f8-dadc-4885-88e3-6cff50fa44f3","url":"http:\/\/www.last.fm\/music\/Vanbot"},"album":{"name":"Vanbot","position":""},"image":[{"#text":"http:\/\/userserve-ak.last.fm\/serve\/34s\/61748267.png","size":"small"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/64s\/61748267.png","size":"medium"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/126\/61748267.png","size":"large"},{"#text":"http:\/\/userserve-ak.last.fm\/serve\/300x300\/61748267.png","size":"extralarge"}]},{"name":"Get Together (Monsieur Adi Remix)","duration":"293000","playcount":"3","tagcount":"0","mbid":"","url":"http:\/\/www.last.fm\/music\/Madonna\/_\/Get+Together+%28Monsieur+Adi+Remix%29","streamable":{"#text":"0","fulltrack":"0"},"artist":{"name":"Madonna","mbid":"79239441-bfd5-4981-a70c-55c3f15c1287","url":"http:\/\/www.last.fm\/music\/Madonna"}}],"@attr":{"user":"mattslip","page":"1","perPage":"50","totalPages":"7","total":"325"}}}

0 comments on commit 64bdb02

Please sign in to comment.