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.HashMap; 030import java.util.Locale; 031import java.util.Map; 032 033import de.umass.util.MapUtilities; 034import de.umass.xml.DomElement; 035 036/** 037 * Provides access to the Last.fm radio streaming service.<br/> 038 * Note that you have to be a subscriber (or have a special API key) to use this API. 039 * Official documentation can be found here: <a href="https://www.last.fm/api/radio">https://www.last.fm/api/radio</a> 040 * 041 * @author Janni Kovacs 042 */ 043public class Radio { 044 045 private String type; 046 private String stationName; 047 private String stationUrl; 048 private boolean supportsDiscovery; 049 050 private Session session; 051 private int expiry = -1; 052 053 private Radio(Session session) { 054 this.session = session; 055 } 056 057 public String getType() { 058 return type; 059 } 060 061 public String getStationName() { 062 return stationName; 063 } 064 065 public String getStationUrl() { 066 return stationUrl; 067 } 068 069 public boolean supportsDiscovery() { 070 return supportsDiscovery; 071 } 072 073 /** 074 * Returns the playlist expiration value for the last playlist fetchet, or -1 if no playlist has been fetched yet. 075 * 076 * @return playlist expiration in seconds 077 */ 078 public int playlistExpiresIn() { 079 return expiry; 080 } 081 082 /** 083 * Resolve the name of a resource into a station depending on which resource it is most likely to represent 084 * 085 * @param name The tag or artist to resolve 086 * @param apiKey A Last.fm API key. 087 * @return A {@link RadioStation} or <code>null</code> 088 */ 089 public static RadioStation search(String name, String apiKey) { 090 Result result = Caller.getInstance().call("radio.search", apiKey, "name", name); 091 if(!result.isSuccessful()) 092 return null; 093 094 DomElement stationElement = result.getContentElement().getChild("station"); 095 if(stationElement == null) 096 return null; 097 098 return new RadioStation(stationElement.getChildText("url"), stationElement.getChildText("name")); 099 } 100 101 /** 102 * Tune in to a Last.fm radio station. 103 * 104 * @param station An instance of {@link RadioStation} 105 * @param session A Session instance 106 * @return a Radio instance 107 */ 108 public static Radio tune(RadioStation station, Session session) { 109 return tune(station, Locale.getDefault(), session); 110 } 111 112 /** 113 * Tune in to a Last.fm radio station. 114 * 115 * @param station An instance of {@link RadioStation} 116 * @param locale The language you want the radio's name in 117 * @param session A Session instance 118 * @return a Radio instance 119 */ 120 public static Radio tune(RadioStation station, Locale locale, Session session) { 121 return tune(station.getUrl(), locale, session); 122 } 123 124 /** 125 * Tune in to a Last.fm radio station. 126 * 127 * @param station A lastfm radio URL 128 * @param locale The language you want the radio's name in 129 * @param session A Session instance 130 * @return a Radio instance 131 */ 132 public static Radio tune(String station, Locale locale, Session session) { 133 Map<String, String> params = new HashMap<String, String>(); 134 params.put("station", station); 135 if (locale != null && locale.getLanguage().length() != 0) { 136 params.put("lang", locale.getLanguage()); 137 } 138 139 Result result = Caller.getInstance().call("radio.tune", session, params); 140 if (!result.isSuccessful()) 141 return null; 142 143 DomElement root = result.getContentElement(); 144 Radio radio = new Radio(session); 145 radio.type = root.getChildText("type"); 146 radio.stationName = root.getChildText("name"); 147 radio.stationUrl = root.getChildText("url"); 148 radio.supportsDiscovery = "1".equals(root.getChildText("type")); 149 return radio; 150 } 151 152 /** 153 * Fetches a new radio playlist or <code>null</code> if an error occured, such as when the user is not allowed to stream radio 154 * (no subscriber). 155 * 156 * @return a new {@link Playlist} or <code>null</code> 157 */ 158 public Playlist getPlaylist() { 159 return getPlaylist(false, false); 160 } 161 162 /** 163 * Fetches a new radio playlist. 164 * 165 * @param discovery Whether to request last.fm content with discovery mode switched on 166 * @param rtp Whether the user is scrobbling or not during this radio session (helps content generation) 167 * @return a new Playlist 168 */ 169 public Playlist getPlaylist(boolean discovery, boolean rtp) { 170 return getPlaylist(discovery, rtp, false, -1, -1); 171 } 172 173 /** 174 * Fetches a new radio playlist. 175 * 176 * @param discovery Whether to request last.fm content with discovery mode switched on 177 * @param rtp Whether the user is scrobbling or not during this radio session (helps content generation) 178 * @param buyLinks Whether the response should contain links for purchase/download, if available 179 * @param speedMultiplier The rate at which to provide the stream (supported multipliers are 1.0 and 2.0) 180 * @param bitrate What bitrate to stream content at, in kbps (supported bitrates are 64 and 128) 181 * @return a new Playlist 182 */ 183 public Playlist getPlaylist(boolean discovery, boolean rtp, boolean buyLinks, double speedMultiplier, int bitrate) { 184 Map<String, String> params = new HashMap<String, String>(); 185 params.put("discovery", String.valueOf(discovery)); 186 params.put("rtp", String.valueOf(rtp)); 187 params.put("buylinks", String.valueOf(buyLinks)); 188 MapUtilities.nullSafePut(params, "speed_multiplier", speedMultiplier); 189 MapUtilities.nullSafePut(params, "bitrate", bitrate); 190 Result result = Caller.getInstance().call("radio.getPlaylist", session, params); 191 192 if (!result.isSuccessful()) 193 return null; 194 195 DomElement root = result.getContentElement(); 196 for (DomElement e : root.getChildren("link")) { 197 if ("http://www.last.fm/expiry".equals(e.getAttribute("rel"))) { 198 this.expiry = Integer.parseInt(e.getText()); 199 break; 200 } 201 } 202 return ResponseBuilder.buildItem(root, Playlist.class); 203 } 204 205 public static class RadioStation { 206 private String name; 207 private String url; 208 209 public RadioStation(String url) { 210 this(url, null); 211 } 212 213 public RadioStation(String url, String name) { 214 this.url = url; 215 this.name = name; 216 } 217 218 public String getUrl() { 219 return url; 220 } 221 222 public String getName() { 223 return name; 224 } 225 226 public static RadioStation similarArtists(String artist) { 227 return new RadioStation("lastfm://artist/" + artist + "/similarartists"); 228 } 229 230 public static RadioStation artistFans(String artist) { 231 return new RadioStation("lastfm://artist/" + artist + "/fans"); 232 } 233 234 public static RadioStation library(String user) { 235 return new RadioStation("lastfm://user/" + user + "/library"); 236 } 237 238 public static RadioStation neighbours(String user) { 239 return new RadioStation("lastfm://user/" + user + "/neighbours"); 240 } 241 242 /** 243 * @deprecated This station has been deprected as of nov. 2010, see <a href="https://www.last.fm/stationchanges2010">here</a> 244 */ 245 public static RadioStation lovedTracks(String user) { 246 return new RadioStation("lastfm://user/" + user + "/loved"); 247 } 248 249 public static RadioStation recommended(String user) { 250 return new RadioStation("lastfm://user/" + user + "/recommended"); 251 } 252 253 public static RadioStation tagged(String tag) { 254 return new RadioStation("lastfm://globaltags/" + tag); 255 } 256 257 /** 258 * @deprecated This station has been deprected as of nov. 2010, see <a href="https://www.last.fm/stationchanges2010">here</a> 259 */ 260 public static RadioStation playlist(String playlistId) { 261 return new RadioStation("lastfm://playlist/" + playlistId); 262 } 263 264 /** 265 * @deprecated This station has been deprected as of nov. 2010, see <a href="https://www.last.fm/stationchanges2010">here</a> 266 */ 267 public static RadioStation personalTag(String user, String tag) { 268 return new RadioStation("lastfm://usertags/" + user + "/" + tag); 269 } 270 } 271}