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 de.umass.xml.DomElement;
030
031import java.util.ArrayList;
032import java.util.List;
033
034/**
035 * Bean for music playlists. Contains the {@link #fetch(String, String) fetch} method and various <code>fetchXXX</code>
036 * methods to retrieve playlists from the server. Playlists are identified by lastfm:// playlist urls. Valid urls
037 * include:
038 * <ul>
039 * <li><b>Album Playlists:</b> lastfm://playlist/album/{@literal <album_id>}</li>
040 * <li><b>User Playlists:</b> lastfm://playlist/{@literal <playlist_id>}</li>
041 * <li><b>Tag Playlists:</b> lastfm://playlist/tag/{@literal <tag_name>}/freetracks</li>
042 * </ul>
043 * See <a href="https://www.last.fm/api/playlists">https://www.last.fm/api/playlists</a> for more information about playlists.
044 *
045 * @author Janni Kovacs
046 */
047public class Playlist {
048
049        static final ItemFactory<Playlist> FACTORY = new PlaylistFactory();
050
051        private int id;
052        private String title;
053        private String annotation;
054        private int size;
055        private String creator;
056
057        private List<Track> tracks = new ArrayList<Track>();
058
059        private Playlist() {
060        }
061
062        public String getCreator() {
063                return creator;
064        }
065
066        public int getId() {
067                return id;
068        }
069
070        public int getSize() {
071                return size;
072        }
073
074        public String getTitle() {
075                return title;
076        }
077
078        public String getAnnotation() {
079                return annotation;
080        }
081
082        public List<Track> getTracks() {
083                return tracks;
084        }
085
086        /**
087         * Fetches an album playlist, which contains the tracks of the specified album.
088         *
089         * @param albumId The album id as returned in {@link Album#getInfo(String, String, String) Album.getInfo}.
090         * @param apiKey A Last.fm API key.
091         * @return a playlist
092         */
093        public static Playlist fetchAlbumPlaylist(String albumId, String apiKey) {
094                return fetch("lastfm://playlist/album/" + albumId, apiKey);
095        }
096
097        /**
098         * Fetches a user-created playlist.
099         *
100         * @param playlistId A playlist id.
101         * @param apiKey A Last.fm API key.
102         * @return a playlist
103         */
104        public static Playlist fetchUserPlaylist(int playlistId, String apiKey) {
105                return fetch("lastfm://playlist/" + playlistId, apiKey);
106        }
107
108        /**
109         * Fetches a playlist of freetracks for a given tag name.
110         *
111         * @param tag A tag name.
112         * @param apiKey A Last.fm API key.
113         * @return a playlist
114         */
115        public static Playlist fetchTagPlaylist(String tag, String apiKey) {
116                return fetch("lastfm://playlist/tag/" + tag + "/freetracks", apiKey);
117        }
118
119        /**
120         * Fetches a playlist using a lastfm playlist url. See the class description for a list of valid
121         * playlist urls.
122         *
123         * @param playlistUrl A valid playlist url.
124         * @param apiKey A Last.fm API key.
125         * @return a playlist
126         */
127        public static Playlist fetch(String playlistUrl, String apiKey) {
128                Result result = Caller.getInstance().call("playlist.fetch", apiKey, "playlistURL", playlistUrl);
129                return ResponseBuilder.buildItem(result, Playlist.class);
130        }
131
132        /**
133         * Add a track to a Last.fm user's playlist.
134         *
135         * @param playlistId The ID of the playlist - this is available in user.getPlaylists
136         * @param artist The artist name that corresponds to the track to be added.
137         * @param track The track name to add to the playlist.
138         * @param session A Session instance.
139         * @return the result of the operation
140         */
141        public static Result addTrack(int playlistId, String artist, String track, Session session) {
142                return Caller.getInstance()
143                                .call("playlist.addTrack", session, "playlistID", String.valueOf(playlistId), "artist", artist, "track",
144                                                track);
145        }
146
147        /**
148         * Creates a Last.fm playlist.
149         *
150         * @param title A title for the playlist
151         * @param description A description for the playlist
152         * @param session A Session instance
153         * @return the result of the operation
154         */
155        public static Playlist create(String title, String description, Session session) {
156                Result result = Caller.getInstance().call("playlist.create", session, "title", title, "description", description);
157                if (!result.isSuccessful())
158                        return null;
159                return ResponseBuilder.buildItem(result.getContentElement().getChild("playlist"), Playlist.class);
160        }
161
162        private static class PlaylistFactory implements ItemFactory<Playlist> {
163                public Playlist createItemFromElement(DomElement element) {
164                        Playlist playlist = new Playlist();
165
166                        if (element.hasChild("id"))
167                                playlist.id = Integer.parseInt(element.getChildText("id"));
168
169                        playlist.title = element.getChildText("title");
170
171                        if (element.hasChild("size"))
172                                playlist.size = Integer.parseInt(element.getChildText("size"));
173
174                        playlist.creator = element.getChildText("creator");
175                        playlist.annotation = element.getChildText("annotation");
176
177                        DomElement trackList = element.getChild("trackList");
178                        if (trackList != null) {
179                                for (DomElement te : trackList.getChildren("track")) {
180                                        Track t = new Track(te.getChildText("title"), te.getChildText("identifier"), te.getChildText("creator"));
181                                        t.album = te.getChildText("album");
182                                        t.duration = Integer.parseInt(te.getChildText("duration")) / 1000;
183                                        t.imageUrls.put(ImageSize.LARGE, te.getChildText("image"));
184                                        t.imageUrls.put(ImageSize.ORIGINAL, te.getChildText("image"));
185                                        t.location = te.getChildText("location");
186                                        for (DomElement ext : te.getChildren("extension")) {
187                                                if ("http://www.last.fm".equals(ext.getAttribute("application"))) {
188                                                        for (DomElement child : ext.getChildren()) {
189                                                                t.lastFmExtensionInfos.put(child.getTagName(), child.getText());
190                                                        }
191                                                }
192                                        }
193                                        playlist.tracks.add(t);
194                                }
195
196                                if (playlist.size == 0)
197                                        playlist.size = playlist.tracks.size();
198                        }
199
200                        return playlist;
201                }
202        }
203}