/* * Copyright (C) 2012-2016 Julien Bonjean <julien@bonjean.info> * * This file is part of Beluga Player. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 3 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package info.bonjean.beluga.client; import info.bonjean.beluga.configuration.BelugaConfiguration; import info.bonjean.beluga.exception.BelugaException; import info.bonjean.beluga.request.ArtistBookmarkDeleteRequest; import info.bonjean.beluga.request.ArtistBookmarkRequest; import info.bonjean.beluga.request.BookmarksRequest; import info.bonjean.beluga.request.CreateStationRequest; import info.bonjean.beluga.request.CreateUserRequest; import info.bonjean.beluga.request.DeleteStationRequest; import info.bonjean.beluga.request.FeedbackDeleteRequest; import info.bonjean.beluga.request.FeedbackRequest; import info.bonjean.beluga.request.Method; import info.bonjean.beluga.request.ParameterMap; import info.bonjean.beluga.request.PartnerAuthRequest; import info.bonjean.beluga.request.PlayListRequest; import info.bonjean.beluga.request.SearchRequest; import info.bonjean.beluga.request.SetQuickMixRequest; import info.bonjean.beluga.request.SongBookmarkDeleteRequest; import info.bonjean.beluga.request.SongBookmarkRequest; import info.bonjean.beluga.request.SongSleepRequest; import info.bonjean.beluga.request.StationListRequest; import info.bonjean.beluga.request.StationRequest; import info.bonjean.beluga.request.UserLoginRequest; import info.bonjean.beluga.response.Bookmarks; import info.bonjean.beluga.response.Feedback; import info.bonjean.beluga.response.Response; import info.bonjean.beluga.response.Result; import info.bonjean.beluga.response.Song; import info.bonjean.beluga.response.Station; import info.bonjean.beluga.util.HTTPUtil; import info.bonjean.beluga.util.PandoraUtil; import java.util.ArrayList; import java.util.List; import javax.xml.parsers.DocumentBuilderFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import com.google.gson.reflect.TypeToken; /** * * @author Julien Bonjean <julien@bonjean.info> * */ public class PandoraClient { private static final Logger log = LoggerFactory.getLogger(PandoraClient.class); private static PandoraClient instance; private String partnerId; private String partnerAuthToken; private String userAuthToken; private String userId; private static final BelugaConfiguration configuration = BelugaConfiguration.getInstance(); private PandoraClient() { } public static PandoraClient getInstance() { if (instance == null) instance = new PandoraClient(); return instance; } public void reset() { partnerId = null; userId = null; partnerAuthToken = null; userAuthToken = null; } public boolean isPandoraReachable() { return partnerAuthToken != null && partnerAuthToken.length() > 0; } public boolean isLoggedIn() { return userAuthToken != null && userAuthToken.length() > 0; } private ParameterMap getDefaultParameterMap() { ParameterMap params = new ParameterMap(); params.add("partner_id", partnerId); params.add("auth_token", userAuthToken); params.add("user_id", userId); return params; } public void partnerLogin() throws BelugaException { partnerId = null; partnerAuthToken = null; Result result = HTTPUtil.<Result> request(Method.PARTNER_LOGIN, null, new PartnerAuthRequest(), false, new TypeToken<Response<Result>>() { }); partnerId = result.getPartnerId(); partnerAuthToken = result.getPartnerAuthToken(); } public void userLogin() throws BelugaException { userId = null; userAuthToken = null; ParameterMap params = new ParameterMap(); params.add("partner_id", partnerId); params.add("auth_token", partnerAuthToken); UserLoginRequest userLogin = new UserLoginRequest(); userLogin.setSyncTime(PandoraUtil.getSyncTime()); userLogin.setPartnerAuthToken(partnerAuthToken); userLogin.setUsername(configuration.getUserName()); userLogin.setPassword(configuration.getPassword()); Result result = HTTPUtil.<Result> request(Method.USER_LOGIN, params, userLogin, true, new TypeToken<Response<Result>>() { }); userId = result.getUserId(); userAuthToken = result.getUserAuthToken(); } public List<Station> getStationList() throws BelugaException { ParameterMap params = getDefaultParameterMap(); StationListRequest stationList = new StationListRequest(); stationList.setSyncTime(PandoraUtil.getSyncTime()); stationList.setUserAuthToken(userAuthToken); Result result = HTTPUtil.<Result> request(Method.GET_STATION_LIST, params, stationList, true, new TypeToken<Response<Result>>() { }); return result.getStations(); } public Station getStation(Station station) throws BelugaException { ParameterMap params = getDefaultParameterMap(); StationRequest stationRequest = new StationRequest(); stationRequest.setSyncTime(PandoraUtil.getSyncTime()); stationRequest.setUserAuthToken(userAuthToken); stationRequest.setStationToken(station.getStationToken()); stationRequest.setIncludeExtendedAttributes(true); Station stationFull = HTTPUtil.<Station> request(Method.GET_STATION, params, stationRequest, true, new TypeToken<Response<Station>>() { }); return stationFull; } public List<String> retrieveFocusTraits(Song song) { List<String> traits = new ArrayList<String>(); try { Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder() .parse(song.getSongExplorerUrl()); NodeList nodes = doc.getElementsByTagName("focusTrait"); for (int i = 0; i < nodes.getLength(); i++) { traits.add(nodes.item(i).getTextContent()); } } catch (Exception ex) { log.debug("Cannot retrieve focus traits for song " + song.getSongName()); } return traits; } public List<Song> getPlaylist(Station station) throws BelugaException { ParameterMap params = getDefaultParameterMap(); PlayListRequest playlist = new PlayListRequest(); playlist.setSyncTime(PandoraUtil.getSyncTime()); playlist.setUserAuthToken(userAuthToken); playlist.setStationToken(station.getStationToken()); playlist.setAdditionalAudioUrl("HTTP_128_MP3"); Result result = HTTPUtil.<Result> request(Method.GET_PLAYLIST, params, playlist, true, new TypeToken<Response<Result>>() { }); List<Song> currentPlaylist = result.getItems(); PandoraUtil.cleanItemList(currentPlaylist); log.debug("Playlist updated"); return currentPlaylist; } public Bookmarks getBookmarks() throws BelugaException { ParameterMap params = getDefaultParameterMap(); BookmarksRequest playlist = new BookmarksRequest(); playlist.setSyncTime(PandoraUtil.getSyncTime()); playlist.setUserAuthToken(userAuthToken); return HTTPUtil.<Bookmarks> request(Method.GET_BOOKMARKS, params, playlist, true, new TypeToken<Response<Bookmarks>>() { }); } public Feedback addFeedback(Song song, boolean isPositive) throws BelugaException { ParameterMap params = getDefaultParameterMap(); FeedbackRequest feedbackRequest = new FeedbackRequest(); feedbackRequest.setSyncTime(PandoraUtil.getSyncTime()); feedbackRequest.setUserAuthToken(userAuthToken); feedbackRequest.setPositive(isPositive); feedbackRequest.setTrackToken(song.getTrackToken()); Feedback feedback = HTTPUtil.<Feedback> request(Method.ADD_FEEDBACK, params, feedbackRequest, true, new TypeToken<Response<Feedback>>() { }); if (isPositive) song.setSongRating(1); return feedback; } public void deleteSongBookmark(String bookmarkToken) throws BelugaException { ParameterMap params = getDefaultParameterMap(); SongBookmarkDeleteRequest songBookmarkDeleteRequest = new SongBookmarkDeleteRequest(); songBookmarkDeleteRequest.setSyncTime(PandoraUtil.getSyncTime()); songBookmarkDeleteRequest.setUserAuthToken(userAuthToken); songBookmarkDeleteRequest.setBookmarkToken(bookmarkToken); HTTPUtil.<Result> request(Method.DELETE_SONG_BOOKMARK, params, songBookmarkDeleteRequest, true, new TypeToken<Response<Result>>() { }); } public void deleteArtistBookmark(String bookmarkToken) throws BelugaException { ParameterMap params = getDefaultParameterMap(); ArtistBookmarkDeleteRequest artistBookmarkDeleteRequest = new ArtistBookmarkDeleteRequest(); artistBookmarkDeleteRequest.setSyncTime(PandoraUtil.getSyncTime()); artistBookmarkDeleteRequest.setUserAuthToken(userAuthToken); artistBookmarkDeleteRequest.setBookmarkToken(bookmarkToken); HTTPUtil.<Result> request(Method.DELETE_ARTIST_BOOKMARK, params, artistBookmarkDeleteRequest, true, new TypeToken<Response<Result>>() { }); } public void deleteFeedback(String feedbackId) throws BelugaException { ParameterMap params = getDefaultParameterMap(); FeedbackDeleteRequest feedbackDeleteRequest = new FeedbackDeleteRequest(); feedbackDeleteRequest.setSyncTime(PandoraUtil.getSyncTime()); feedbackDeleteRequest.setUserAuthToken(userAuthToken); feedbackDeleteRequest.setFeedbackId(feedbackId); HTTPUtil.<Result> request(Method.DELETE_FEEDBACK, params, feedbackDeleteRequest, true, new TypeToken<Response<Result>>() { }); } public void sleepSong(Song song) throws BelugaException { ParameterMap params = getDefaultParameterMap(); SongSleepRequest songSleep = new SongSleepRequest(); songSleep.setSyncTime(PandoraUtil.getSyncTime()); songSleep.setUserAuthToken(userAuthToken); songSleep.setTrackToken(song.getTrackToken()); HTTPUtil.<Result> request(Method.SLEEP_SONG, params, songSleep, true, new TypeToken<Response<Result>>() { }); } public void addSongBookmark(String trackToken) throws BelugaException { ParameterMap params = getDefaultParameterMap(); SongBookmarkRequest songBookmark = new SongBookmarkRequest(); songBookmark.setSyncTime(PandoraUtil.getSyncTime()); songBookmark.setUserAuthToken(userAuthToken); songBookmark.setTrackToken(trackToken); HTTPUtil.<Result> request(Method.ADD_SONG_BOOKMARK, params, songBookmark, true, new TypeToken<Response<Result>>() { }); } public void addArtistBookmark(String trackToken) throws BelugaException { ParameterMap params = getDefaultParameterMap(); ArtistBookmarkRequest artistBookmark = new ArtistBookmarkRequest(); artistBookmark.setSyncTime(PandoraUtil.getSyncTime()); artistBookmark.setUserAuthToken(userAuthToken); artistBookmark.setTrackToken(trackToken); HTTPUtil.<Result> request(Method.ADD_ARTIST_BOOKMARK, params, artistBookmark, true, new TypeToken<Response<Result>>() { }); } public Result search(String query) throws BelugaException { ParameterMap params = getDefaultParameterMap(); SearchRequest search = new SearchRequest(); search.setSyncTime(PandoraUtil.getSyncTime()); search.setUserAuthToken(userAuthToken); search.setSearchText(query); return HTTPUtil.<Result> request(Method.SEARCH, params, search, true, new TypeToken<Response<Result>>() { }); } public void addStation(String musicToken) throws BelugaException { ParameterMap params = getDefaultParameterMap(); CreateStationRequest createStation = new CreateStationRequest(); createStation.setSyncTime(PandoraUtil.getSyncTime()); createStation.setUserAuthToken(userAuthToken); createStation.setMusicToken(musicToken); HTTPUtil.<Result> request(Method.CREATE_STATION, params, createStation, true, new TypeToken<Response<Result>>() { }); } public void addStation(String type, String trackToken) throws BelugaException { ParameterMap params = getDefaultParameterMap(); CreateStationRequest createStation = new CreateStationRequest(); createStation.setSyncTime(PandoraUtil.getSyncTime()); createStation.setUserAuthToken(userAuthToken); createStation.setMusicType(type); createStation.setTrackToken(trackToken); HTTPUtil.<Result> request(Method.CREATE_STATION, params, createStation, true, new TypeToken<Response<Result>>() { }); } public void deleteStation(Station station) throws BelugaException { ParameterMap params = getDefaultParameterMap(); DeleteStationRequest createStation = new DeleteStationRequest(); createStation.setSyncTime(PandoraUtil.getSyncTime()); createStation.setUserAuthToken(userAuthToken); createStation.setStationToken(station.getStationToken()); HTTPUtil.<Result> request(Method.DELETE_STATION, params, createStation, true, new TypeToken<Response<Result>>() { }); } public void setQuickMix(List<String> quickMixStationIds) throws BelugaException { ParameterMap params = getDefaultParameterMap(); SetQuickMixRequest setQuickMix = new SetQuickMixRequest(); setQuickMix.setSyncTime(PandoraUtil.getSyncTime()); setQuickMix.setUserAuthToken(userAuthToken); setQuickMix.setQuickMixStationIds(quickMixStationIds); HTTPUtil.<Result> request(Method.SET_QUICK_MIX, params, setQuickMix, true, new TypeToken<Response<Result>>() { }); } public void createUser(String username, String password, String birthYearStr, String zipCode, String gender, String emailOptInStr) throws BelugaException { Integer birthYear = 0; try { birthYear = Integer.valueOf(birthYearStr); } catch (NumberFormatException e) { // we don't care, Pandora is going to reject it anyway } Boolean emailOptIn = Boolean.valueOf(emailOptInStr); ParameterMap params = new ParameterMap(); params.add("partner_id", partnerId); params.add("auth_token", partnerAuthToken); CreateUserRequest createUser = new CreateUserRequest(); createUser.setUsername(username); createUser.setPassword(password); createUser.setBirthYear(birthYear); createUser.setZipCode(zipCode); createUser.setGender(gender); createUser.setEmailOptIn(emailOptIn); createUser.setSyncTime(PandoraUtil.getSyncTime()); createUser.setPartnerAuthToken(partnerAuthToken); HTTPUtil.<Result> request(Method.CREATE_USER, params, createUser, true, new TypeToken<Response<Result>>() { }); } }