001/* 002 * Copyright (c) 2012, the Last.fm Java Project and Committers 003 * All rights reserved. 004 * 005 * Redistribution and use of this software in source and binary forms, with or without modification, are 006 * permitted provided that the following conditions are met: 007 * 008 * - Redistributions of source code must retain the above 009 * copyright notice, this list of conditions and the 010 * following disclaimer. 011 * 012 * - Redistributions in binary form must reproduce the above 013 * copyright notice, this list of conditions and the 014 * following disclaimer in the documentation and/or other 015 * materials provided with the distribution. 016 * 017 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 018 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 019 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 020 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 021 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 022 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 023 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 024 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 025 */ 026 027package de.umass.lastfm; 028 029import java.util.ArrayList; 030import java.util.Collection; 031import java.util.Collections; 032import java.util.HashMap; 033import java.util.List; 034import java.util.Locale; 035import java.util.Map; 036 037import de.umass.util.MapUtilities; 038import de.umass.util.StringUtilities; 039import de.umass.xml.DomElement; 040 041/** 042 * Bean that contains artist information.<br/> This class contains static methods that executes API methods relating to artists.<br/> Method 043 * names are equivalent to the last.fm API method names. 044 * 045 * @author Janni Kovacs 046 */ 047public class Artist extends MusicEntry { 048 049 static final ItemFactory<Artist> FACTORY = new ArtistFactory(); 050 051 private Collection<Artist> similar = new ArrayList<Artist>(); 052 053 protected Artist(String name, String url) { 054 super(name, url); 055 } 056 057 protected Artist(String name, String url, String mbid, int playcount, int listeners, boolean streamable) { 058 super(name, url, mbid, playcount, listeners, streamable); 059 } 060 061 /** 062 * Returns a list of similar <code>Artist</code>s. Note that this method does not retrieve this list from the server but instead returns 063 * the result of an <code>artist.getInfo</code> call.<br/> If you need to retrieve similar artists to a specified artist use the {@link 064 * #getSimilar(String, String)} method. 065 * 066 * @return list of similar artists 067 * @see #getSimilar(String, String) 068 * @see #getSimilar(String, int, String) 069 */ 070 public Collection<Artist> getSimilar() { 071 return similar; 072 } 073 074 /** 075 * Retrieves detailed artist info for the given artist or mbid entry. 076 * 077 * @param artistOrMbid Name of the artist or an mbid 078 * @param apiKey The API key 079 * @return detailed artist info 080 */ 081 public static Artist getInfo(String artistOrMbid, String apiKey) { 082 return getInfo(artistOrMbid, null, null, apiKey); 083 } 084 085 /** 086 * Retrieves detailed artist info for the given artist or mbid entry. 087 * 088 * @param artistOrMbid Name of the artist or an mbid 089 * @param username The username for the context of the request, or <code>null</code>. If supplied, the user's playcount for this artist is 090 * included in the response 091 * @param apiKey The API key 092 * @return detailed artist info 093 */ 094 public static Artist getInfo(String artistOrMbid, String username, String apiKey) { 095 return getInfo(artistOrMbid, null, username, apiKey); 096 } 097 098 /** 099 * Retrieves detailed artist info for the given artist or mbid entry. 100 * 101 * @param artistOrMbid Name of the artist or an mbid 102 * @param locale The language to fetch info in, or <code>null</code> 103 * @param username The username for the context of the request, or <code>null</code>. If supplied, the user's playcount for this artist is 104 * included in the response 105 * @param apiKey The API key 106 * @return detailed artist info 107 */ 108 public static Artist getInfo(String artistOrMbid, Locale locale, String username, String apiKey) { 109 Map<String, String> params = new HashMap<String, String>(); 110 if (StringUtilities.isMbid(artistOrMbid)) { 111 params.put("mbid", artistOrMbid); 112 } else { 113 params.put("artist", artistOrMbid); 114 } 115 if (locale != null && locale.getLanguage().length() != 0) { 116 params.put("lang", locale.getLanguage()); 117 } 118 MapUtilities.nullSafePut(params, "username", username); 119 Result result = Caller.getInstance().call("artist.getInfo", apiKey, params); 120 return ResponseBuilder.buildItem(result, Artist.class); 121 } 122 123 /** 124 * Calls {@link #getSimilar(String, int, String)} with the default limit of 100. 125 * 126 * @param artist Artist's name 127 * @param apiKey The API key 128 * @return similar artists 129 * @see #getSimilar(String, int, String) 130 */ 131 public static Collection<Artist> getSimilar(String artist, String apiKey) { 132 return getSimilar(artist, 100, apiKey); 133 } 134 135 /** 136 * Returns <code>limit</code> similar artists to the given one. 137 * 138 * @param artist Artist's name 139 * @param limit Number of maximum results 140 * @param apiKey The API key 141 * @return similar artists 142 */ 143 public static Collection<Artist> getSimilar(String artist, int limit, String apiKey) { 144 Result result = Caller.getInstance().call("artist.getSimilar", apiKey, "artist", artist, "limit", String.valueOf(limit)); 145 return ResponseBuilder.buildCollection(result, Artist.class); 146 } 147 148 /** 149 * Searches for an artist and returns a <code>Collection</code> of possible matches. 150 * 151 * @param name The artist name to look up 152 * @param apiKey The API key 153 * @return a list of possible matches 154 */ 155 public static Collection<Artist> search(String name, String apiKey) { 156 Result result = Caller.getInstance().call("artist.search", apiKey, "artist", name); 157 Collection<DomElement> children = result.getContentElement().getChild("artistmatches").getChildren("artist"); 158 List<Artist> list = new ArrayList<Artist>(children.size()); 159 for (DomElement c : children) { 160 list.add(FACTORY.createItemFromElement(c)); 161 } 162 return list; 163 } 164 165 /** 166 * Returns a list of the given artist's top albums. 167 * 168 * @param artist Artist's name 169 * @param apiKey The API key 170 * @return list of top albums 171 */ 172 public static Collection<Album> getTopAlbums(String artist, String apiKey) { 173 Result result = Caller.getInstance().call("artist.getTopAlbums", apiKey, "artist", artist); 174 return ResponseBuilder.buildCollection(result, Album.class); 175 } 176 177 /** 178 * Retrieves a list of the top fans of the given artist. 179 * 180 * @param artist Artist's name 181 * @param apiKey The API key 182 * @return list of top fans 183 */ 184 public static Collection<User> getTopFans(String artist, String apiKey) { 185 Result result = Caller.getInstance().call("artist.getTopFans", apiKey, "artist", artist); 186 return ResponseBuilder.buildCollection(result, User.class); 187 } 188 189 /** 190 * Retrieves the top tags for the given artist. 191 * 192 * @param artist Artist's name 193 * @param apiKey The API key 194 * @return list of top tags 195 */ 196 public static Collection<Tag> getTopTags(String artist, String apiKey) { 197 Result result = Caller.getInstance().call("artist.getTopTags", apiKey, "artist", artist); 198 return ResponseBuilder.buildCollection(result, Tag.class); 199 } 200 201 /** 202 * Get the top tracks by an artist on Last.fm, ordered by popularity 203 * 204 * @param artist The artist name in question 205 * @param apiKey A Last.fm API key. 206 * @return list of top tracks 207 */ 208 public static Collection<Track> getTopTracks(String artist, String apiKey) { 209 Result result = Caller.getInstance().call("artist.getTopTracks", apiKey, "artist", artist); 210 return ResponseBuilder.buildCollection(result, Track.class); 211 } 212 213 /** 214 * Tag an artist with one or more user supplied tags. 215 * 216 * @param artist The artist name in question. 217 * @param tags A comma delimited list of user supplied tags to apply to this artist. Accepts a maximum of 10 tags. 218 * @param session A Session instance 219 * @return the result of the operation 220 */ 221 public static Result addTags(String artist, String tags, Session session) { 222 return Caller.getInstance().call("artist.addTags", session, "artist", artist, "tags", tags); 223 } 224 225 /** 226 * Remove a user's tag from an artist. 227 * 228 * @param artist The artist name in question. 229 * @param tag A single user tag to remove from this artist. 230 * @param session A Session instance 231 * @return the result of the operation 232 */ 233 public static Result removeTag(String artist, String tag, Session session) { 234 return Caller.getInstance().call("artist.removeTag", session, "artist", artist, "tag", tag); 235 } 236 237 /** 238 * Share an artist with one or more Last.fm users or other friends. 239 * 240 * @param artist The artist to share. 241 * @param recipients A comma delimited list of email addresses or Last.fm usernames. Maximum is 10. 242 * @param message An optional message to send with the recommendation. 243 * @param session A Session instance 244 * @return the Result of the operation 245 */ 246 public static Result share(String artist, String recipients, String message, Session session) { 247 return Caller.getInstance().call("artist.share", session, "artist", artist, "recipient", recipients, "message", message); 248 } 249 250 /** 251 * Get the tags applied by an individual user to an artist on Last.fm. 252 * 253 * @param artist The artist name in question 254 * @param session A Session instance 255 * @return a list of tags 256 */ 257 public static Collection<String> getTags(String artist, Session session) { 258 Result result = Caller.getInstance().call("artist.getTags", session, "artist", artist); 259 if (!result.isSuccessful()) 260 return Collections.emptyList(); 261 DomElement element = result.getContentElement(); 262 Collection<String> tags = new ArrayList<String>(); 263 for (DomElement domElement : element.getChildren("tag")) { 264 tags.add(domElement.getChildText("name")); 265 } 266 return tags; 267 } 268 269 /** 270 * Returns a list of upcoming events for an artist. 271 * 272 * @param artistOrMbid The artist name in question 273 * @param apiKey A Last.fm API key 274 * @return a list of events 275 */ 276 public static PaginatedResult<Event> getEvents(String artistOrMbid, String apiKey) { 277 return getEvents(artistOrMbid, false, -1, -1, apiKey); 278 } 279 280 /** 281 * Returns a list of upcoming events for an artist. 282 * 283 * @param artistOrMbid The artist name in question 284 * @param festivalsOnly Whether only festivals should be returned, or all events 285 * @param page The page number to fetch 286 * @param limit The number of results to fetch per page 287 * @param apiKey A Last.fm API key 288 * @return a list of events 289 */ 290 public static PaginatedResult<Event> getEvents(String artistOrMbid, boolean festivalsOnly, int page, int limit, String apiKey) { 291 Map<String, String> params = new HashMap<String, String>(); 292 if (StringUtilities.isMbid(artistOrMbid)) { 293 params.put("mbid", artistOrMbid); 294 } else { 295 params.put("artist", artistOrMbid); 296 } 297 MapUtilities.nullSafePut(params, "page", page); 298 MapUtilities.nullSafePut(params, "limit", limit); 299 if(festivalsOnly) 300 params.put("festivalsonly", "1"); 301 Result result = Caller.getInstance().call("artist.getEvents", apiKey, params); 302 return ResponseBuilder.buildPaginatedResult(result, Event.class); 303 } 304 305 /** 306 * Get a paginated list of all the events this artist has played at in the past. 307 * 308 * @param artistOrMbid The name of the artist you would like to fetch event listings for 309 * @param apiKey A Last.fm API key 310 * @return a list of past events 311 */ 312 public static PaginatedResult<Event> getPastEvents(String artistOrMbid, String apiKey) { 313 return getPastEvents(artistOrMbid, false, -1, -1, apiKey); 314 } 315 316 /** 317 * Get a paginated list of all the events this artist has played at in the past. 318 * 319 * @param artistOrMbid The name of the artist you would like to fetch event listings for 320 * @param festivalsOnly Whether only festivals should be returned, or all events 321 * @param page The page of results to return 322 * @param limit The maximum number of results to return per page 323 * @param apiKey A Last.fm API key 324 * @return a list of past events 325 */ 326 public static PaginatedResult<Event> getPastEvents(String artistOrMbid, boolean festivalsOnly, int page, int limit, String apiKey) { 327 Map<String, String> params = new HashMap<String, String>(); 328 if (StringUtilities.isMbid(artistOrMbid)) { 329 params.put("mbid", artistOrMbid); 330 } else { 331 params.put("artist", artistOrMbid); 332 } 333 MapUtilities.nullSafePut(params, "page", page); 334 MapUtilities.nullSafePut(params, "limit", limit); 335 if(festivalsOnly) 336 params.put("festivalsonly", "1"); 337 Result result = Caller.getInstance().call("artist.getPastEvents", apiKey, params); 338 return ResponseBuilder.buildPaginatedResult(result, Event.class); 339 } 340 341 /** 342 * Get {@link Image}s for this artist in a variety of sizes. 343 * 344 * @param artistOrMbid The artist name in question 345 * @param apiKey A Last.fm API key 346 * @return a list of {@link Image}s 347 */ 348 public static PaginatedResult<Image> getImages(String artistOrMbid, String apiKey) { 349 return getImages(artistOrMbid, -1, -1, apiKey); 350 } 351 352 /** 353 * Get {@link Image}s for this artist in a variety of sizes. 354 * 355 * @param artistOrMbid The artist name in question 356 * @param page Which page of limit amount to display 357 * @param limit How many to return. Defaults and maxes out at 50 358 * @param apiKey A Last.fm API key 359 * @return a list of {@link Image}s 360 */ 361 public static PaginatedResult<Image> getImages(String artistOrMbid, int page, int limit, String apiKey) { 362 Map<String, String> params = new HashMap<String, String>(); 363 if (StringUtilities.isMbid(artistOrMbid)) { 364 params.put("mbid", artistOrMbid); 365 } else { 366 params.put("artist", artistOrMbid); 367 } 368 MapUtilities.nullSafePut(params, "page", page); 369 MapUtilities.nullSafePut(params, "limit", limit); 370 Result result = Caller.getInstance().call("artist.getImages", apiKey, params); 371 return ResponseBuilder.buildPaginatedResult(result, Image.class); 372 } 373 374 /** 375 * Shout on this artist's shoutbox 376 * 377 * @param artist The name of the artist to shout on 378 * @param message The message to post to the shoutbox 379 * @param session A Session instance 380 * @return the result of the operation 381 */ 382 public static Result shout(String artist, String message, Session session) { 383 return Caller.getInstance().call("artist.shout", session, "artist", artist, "message", message); 384 } 385 386 /** 387 * Use the last.fm corrections data to check whether the supplied artist has a correction to a canonical artist. This method returns a new 388 * {@link Artist} object containing the corrected data, or <code>null</code> if the supplied Artist was not found. 389 * 390 * @param artist The artist name to correct 391 * @param apiKey A Last.fm API key 392 * @return a new {@link Artist}, or <code>null</code> 393 */ 394 public static Artist getCorrection(String artist, String apiKey) { 395 Result result = Caller.getInstance().call("artist.getCorrection", apiKey, "artist", artist); 396 if (!result.isSuccessful()) 397 return null; 398 DomElement correctionElement = result.getContentElement().getChild("correction"); 399 if (correctionElement == null) 400 return new Artist(artist, null); 401 DomElement artistElem = correctionElement.getChild("artist"); 402 return FACTORY.createItemFromElement(artistElem); 403 } 404 405 /** 406 * Get shouts for an artist. 407 * 408 * @param artistOrMbid The artist name or a musicbrainz id 409 * @param apiKey A Last.fm API key. 410 * @return a page of <code>Shout</code>s 411 */ 412 public static PaginatedResult<Shout> getShouts(String artistOrMbid, String apiKey) { 413 return getShouts(artistOrMbid, -1, -1, apiKey); 414 } 415 416 /** 417 * Get shouts for an artist. 418 * 419 * @param artistOrMbid The artist name or a musicbrainz id 420 * @param page The page number to fetch 421 * @param apiKey A Last.fm API key. 422 * @return a page of <code>Shout</code>s 423 */ 424 public static PaginatedResult<Shout> getShouts(String artistOrMbid, int page, String apiKey) { 425 return getShouts(artistOrMbid, page, -1, apiKey); 426 } 427 428 /** 429 * Get shouts for an artist. 430 * 431 * @param artistOrMbid The artist name or a musicbrainz id 432 * @param page The page number to fetch 433 * @param limit An integer used to limit the number of shouts returned per page or -1 for default 434 * @param apiKey A Last.fm API key. 435 * @return a page of <code>Shout</code>s 436 */ 437 public static PaginatedResult<Shout> getShouts(String artistOrMbid, int page, int limit, String apiKey) { 438 Map<String, String> params = new HashMap<String, String>(); 439 if (StringUtilities.isMbid(artistOrMbid)) { 440 params.put("mbid", artistOrMbid); 441 } else { 442 params.put("artist", artistOrMbid); 443 } 444 MapUtilities.nullSafePut(params, "limit", limit); 445 MapUtilities.nullSafePut(params, "page", page); 446 Result result = Caller.getInstance().call("artist.getShouts", apiKey, params); 447 return ResponseBuilder.buildPaginatedResult(result, Shout.class); 448 } 449 450 private static class ArtistFactory implements ItemFactory<Artist> { 451 public Artist createItemFromElement(DomElement element) { 452 Artist artist = new Artist(null, null); 453 MusicEntry.loadStandardInfo(artist, element); 454 // similar artists 455 DomElement similar = element.getChild("similar"); 456 if (similar != null) { 457 Collection<DomElement> children = similar.getChildren("artist"); 458 for (DomElement child : children) { 459 artist.similar.add(createItemFromElement(child)); 460 } 461 } 462 return artist; 463 } 464 } 465}