package org.xbmc.android.remote.business.cm; import java.util.ArrayList; import java.util.List; import org.xbmc.android.jsonrpc.api.AbstractCall; import org.xbmc.android.jsonrpc.api.call.AudioLibrary; import org.xbmc.android.jsonrpc.api.call.Player; import org.xbmc.android.jsonrpc.api.call.Playlist; import org.xbmc.android.jsonrpc.api.model.AudioModel.AlbumDetail; import org.xbmc.android.jsonrpc.api.model.AudioModel.ArtistDetail; import org.xbmc.android.jsonrpc.api.model.AudioModel.SongDetail; import org.xbmc.android.jsonrpc.api.model.LibraryModel.GenreDetail; import org.xbmc.android.jsonrpc.api.model.ListModel; import org.xbmc.android.jsonrpc.api.model.ListModel.AlbumFilter; import org.xbmc.android.jsonrpc.api.model.ListModel.AlbumFilterRule; import org.xbmc.android.jsonrpc.api.model.ListModel.FilterRule.Value; import org.xbmc.android.jsonrpc.api.model.ListModel.SongFilter; import org.xbmc.android.jsonrpc.api.model.ListModel.SongFilterRule; import org.xbmc.android.jsonrpc.api.model.PlaylistModel; import org.xbmc.api.business.DataResponse; import org.xbmc.api.business.IMusicManager; import org.xbmc.api.business.INotifiableManager; import org.xbmc.api.business.ISortableManager; import org.xbmc.api.object.Album; import org.xbmc.api.object.Artist; import org.xbmc.api.object.Genre; import org.xbmc.api.object.ICoverArt; import org.xbmc.api.object.Song; import org.xbmc.httpapi.WifiStateException; import android.content.Context; import android.graphics.Bitmap; public class MusicManager extends AbstractManager implements IMusicManager, ISortableManager, INotifiableManager { public void getCompilations(DataResponse<ArrayList<Album>> response, Context context) { List<AlbumFilter> artistFilters = new ArrayList<AlbumFilter>(); // (String operator, Value value, String field) artistFilters.add(new AlbumFilter( new AlbumFilterRule("startswith", new Value("various artists"), AlbumFilterRule.Field.ALBUMARTIST))); artistFilters.add(new AlbumFilter(new AlbumFilterRule("startswith", new Value("v.a."), AlbumFilterRule.Field.ALBUMARTIST))); artistFilters.add(new AlbumFilter(new AlbumFilterRule("is", new Value( "va"), AlbumFilterRule.Field.ALBUMARTIST))); call(new AudioLibrary.GetAlbums(null, getSort(AlbumDetail.TITLE), new ListModel.AlbumFilter(new AlbumFilter.Or(artistFilters)), AlbumDetail.ARTIST, AlbumDetail.YEAR, AlbumDetail.THUMBNAIL), new ApiHandler<ArrayList<Album>, AlbumDetail>() { @Override public ArrayList<Album> handleResponse( AbstractCall<AlbumDetail> apiCall) { List<AlbumDetail> albumDetails = apiCall.getResults(); ArrayList<Album> result = new ArrayList<Album>(); for (AlbumDetail albumDetail : albumDetails) { result.add(new Album(albumDetail)); } return result; } }, response, context); } public void getAlbums(final DataResponse<ArrayList<Album>> response, Context context) { call(new AudioLibrary.GetAlbums(null, getSort(AlbumDetail.TITLE), (ListModel.AlbumFilter) null, AlbumDetail.ARTIST, AlbumDetail.YEAR, AlbumDetail.THUMBNAIL), new ApiHandler<ArrayList<Album>, AlbumDetail>() { @Override public ArrayList<Album> handleResponse( AbstractCall<AlbumDetail> apiCall) { List<AlbumDetail> albumDetails = apiCall.getResults(); ArrayList<Album> result = new ArrayList<Album>(); for (AlbumDetail albumDetail : albumDetails) { result.add(new Album(albumDetail)); } return result; } }, response, context); } public ArrayList<Album> getAlbums(Context context) { // FIXME: getcovers needs to work properly throw new RuntimeException( "Synchronous calls are incompatible with new API"); } public void getAlbums(DataResponse<ArrayList<Album>> response, Artist artist, Context context) { call(new AudioLibrary.GetAlbums(null, getSort(AlbumDetail.TITLE), new AudioLibrary.GetAlbums.FilterArtistId(artist.getId()), AlbumDetail.ARTIST, AlbumDetail.YEAR, AlbumDetail.THUMBNAIL), new ApiHandler<ArrayList<Album>, AlbumDetail>() { @Override public ArrayList<Album> handleResponse( AbstractCall<AlbumDetail> apiCall) { List<AlbumDetail> albumDetails = apiCall.getResults(); ArrayList<Album> result = new ArrayList<Album>(); for (AlbumDetail albumDetail : albumDetails) { result.add(new Album(albumDetail)); } return result; } }, response, context); } public void getAlbums(DataResponse<ArrayList<Album>> response, Genre genre, Context context) { call(new AudioLibrary.GetAlbums(null, getSort(AlbumDetail.TITLE), new AudioLibrary.GetAlbums.FilterGenreId(genre.getId()), AlbumDetail.ARTIST, AlbumDetail.YEAR, AlbumDetail.THUMBNAIL), new ApiHandler<ArrayList<Album>, AlbumDetail>() { @Override public ArrayList<Album> handleResponse( AbstractCall<AlbumDetail> apiCall) { List<AlbumDetail> albumDetails = apiCall.getResults(); ArrayList<Album> result = new ArrayList<Album>(); for (AlbumDetail albumDetail : albumDetails) { result.add(new Album(albumDetail)); } return result; } }, response, context); } public void getSongs(DataResponse<ArrayList<Song>> response, Album album, Context context) { call(new AudioLibrary.GetSongs(null, getSort(SongDetail.TRACK), new AudioLibrary.GetSongs.FilterAlbumId(album.getId()), SongDetail.ARTIST, SongDetail.TITLE, SongDetail.ALBUM, SongDetail.TRACK, SongDetail.DISC, SongDetail.DURATION, SongDetail.FILE, SongDetail.THUMBNAIL), new ApiHandler<ArrayList<Song>, SongDetail>() { @Override public ArrayList<Song> handleResponse( AbstractCall<SongDetail> apiCall) { List<SongDetail> songDetails = apiCall.getResults(); ArrayList<Song> result = new ArrayList<Song>(); for (SongDetail songDetail : songDetails) { result.add(new Song(songDetail)); } return result; } }, response, context); } public void getSongs(DataResponse<ArrayList<Song>> response, Artist artist, Context context) { call(new AudioLibrary.GetSongs(null, getSort(SongDetail.TRACK), new AudioLibrary.GetSongs.FilterArtistId(artist.getId()), SongDetail.ARTIST, SongDetail.TITLE, SongDetail.ALBUM, SongDetail.TRACK, SongDetail.DISC, SongDetail.DURATION, SongDetail.FILE, SongDetail.THUMBNAIL), new ApiHandler<ArrayList<Song>, SongDetail>() { @Override public ArrayList<Song> handleResponse( AbstractCall<SongDetail> apiCall) { List<SongDetail> songDetails = apiCall.getResults(); ArrayList<Song> result = new ArrayList<Song>(); for (SongDetail songDetail : songDetails) { result.add(new Song(songDetail)); } return result; } }, response, context); } public void getSongs(DataResponse<ArrayList<Song>> response, Genre genre, Context context) { call(new AudioLibrary.GetSongs(null, getSort(SongDetail.TRACK), new AudioLibrary.GetSongs.FilterGenreId(genre.getId()), SongDetail.ARTIST, SongDetail.TITLE, SongDetail.ALBUM, SongDetail.TRACK, SongDetail.DISC, SongDetail.DURATION, SongDetail.FILE, SongDetail.THUMBNAIL), new ApiHandler<ArrayList<Song>, SongDetail>() { @Override public ArrayList<Song> handleResponse( AbstractCall<SongDetail> apiCall) { List<SongDetail> songDetails = apiCall.getResults(); ArrayList<Song> result = new ArrayList<Song>(); for (SongDetail songDetail : songDetails) { result.add(new Song(songDetail)); } return result; } }, response, context); } public void getArtists(DataResponse<ArrayList<Artist>> response, Context context) { // FIXME: Parametize this Boolean albumArtistsOnly = Boolean.TRUE; call(new AudioLibrary.GetArtists(albumArtistsOnly, null, getSort(ArtistDetail.LABEL), (AudioLibrary.GetArtists.FilterGenreId) null, ArtistDetail.THUMBNAIL), new ApiHandler<ArrayList<Artist>, ArtistDetail>() { @Override public ArrayList<Artist> handleResponse( AbstractCall<ArtistDetail> apiCall) { List<ArtistDetail> artistDetails = apiCall.getResults(); ArrayList<Artist> result = new ArrayList<Artist>(); for (ArtistDetail artistDetail : artistDetails) { result.add(new Artist(artistDetail)); } return result; } }, response, context); } public void getArtists(DataResponse<ArrayList<Artist>> response, Genre genre, Context context) { // FIXME: Parametize this Boolean albumArtistsOnly = Boolean.TRUE; call(new AudioLibrary.GetArtists(albumArtistsOnly, null, getSort(ArtistDetail.LABEL), new AudioLibrary.GetArtists.FilterGenreId(genre.getId()), ArtistDetail.THUMBNAIL), new ApiHandler<ArrayList<Artist>, ArtistDetail>() { @Override public ArrayList<Artist> handleResponse( AbstractCall<ArtistDetail> apiCall) { List<ArtistDetail> artistDetails = apiCall.getResults(); ArrayList<Artist> result = new ArrayList<Artist>(); for (ArtistDetail artistDetail : artistDetails) { result.add(new Artist(artistDetail)); } return result; } }, response, context); } public void getGenres(DataResponse<ArrayList<Genre>> response, Context context) { call(new AudioLibrary.GetGenres(null, getSort(ArtistDetail.LABEL), ArtistDetail.THUMBNAIL), new ApiHandler<ArrayList<Genre>, GenreDetail>() { @Override public ArrayList<Genre> handleResponse( AbstractCall<GenreDetail> apiCall) { List<GenreDetail> genreDetails = apiCall.getResults(); ArrayList<Genre> result = new ArrayList<Genre>(); for (GenreDetail genreDetail : genreDetails) { result.add(new Genre(genreDetail)); } return result; } }, response, context); } public void addToPlaylist(DataResponse<Boolean> response, Album album, Context context) { call(new Playlist.Add(PLAYLIST_MUSIC, new PlaylistModel.Item( new PlaylistModel.Item.Albumid(album.getId()))), new ApiHandler<Boolean, String>() { @Override public Boolean handleResponse(AbstractCall<String> apiCall) { return "OK".equals(apiCall.getResult()); } }, response, context); } public void addToPlaylist(DataResponse<Boolean> response, Genre genre, Context context) { call(new Playlist.Add(PLAYLIST_MUSIC, new PlaylistModel.Item( new PlaylistModel.Item.Genreid(genre.getId()))), new ApiHandler<Boolean, String>() { @Override public Boolean handleResponse(AbstractCall<String> apiCall) { return "OK".equals(apiCall.getResult()); } }, response, context); } public void addToPlaylist(DataResponse<Boolean> response, Song song, Context context) { call(new Playlist.Add(PLAYLIST_MUSIC, new PlaylistModel.Item( new PlaylistModel.Item.Songid(song.getId()))), new ApiHandler<Boolean, String>() { @Override public Boolean handleResponse(AbstractCall<String> apiCall) { return "OK".equals(apiCall.getResult()); } }, response, context); } public void addToPlaylist(DataResponse<Boolean> response, Album album, Song song, Context context) { call(new Playlist.Add(PLAYLIST_MUSIC, new PlaylistModel.Item( new PlaylistModel.Item.Albumid(album.getId()))), new ApiHandler<Boolean, String>() { @Override public Boolean handleResponse(AbstractCall<String> apiCall) { return "OK".equals(apiCall.getResult()); } }, response, context); } public void addToPlaylist(DataResponse<Boolean> response, Artist artist, Context context) { call(new Playlist.Add(PLAYLIST_MUSIC, new PlaylistModel.Item( new PlaylistModel.Item.Artistid(artist.getId()))), new ApiHandler<Boolean, String>() { @Override public Boolean handleResponse(AbstractCall<String> apiCall) { return "OK".equals(apiCall.getResult()); } }, response, context); } public void addToPlaylist(final DataResponse<Boolean> response, Artist artist, Genre genre, final Context context) { List<SongFilter> songFilters = new ArrayList<SongFilter>(); // SongFilterRule(String operator, Value value, String field) songFilters.add(new SongFilter(new SongFilterRule("is", new Value( Integer.toString(artist.getId())), "artist"))); songFilters.add(new SongFilter(new SongFilterRule("is", new Value( Integer.toString(genre.getId())), "genre"))); ListModel.SongFilter filter = new ListModel.SongFilter( new ListModel.SongFilter.And(songFilters)); callRaw(new AudioLibrary.GetSongs(null, filter), new ApiHandler<Boolean, SongDetail>() { @Override public Boolean handleResponse( AbstractCall<SongDetail> apiCall) { List<SongDetail> songDetails = apiCall.getResults(); int currentSong = 1; ArrayList<Song> result = new ArrayList<Song>(); for (SongDetail songDetail : songDetails) { final boolean lastSong = currentSong == songDetails .size(); callRaw(new Playlist.Add(PLAYLIST_MUSIC, new PlaylistModel.Item( new PlaylistModel.Item.Songid( songDetail.songid))), new ApiHandler<Boolean, String>() { @Override public Boolean handleResponse( AbstractCall<String> apiCall) { boolean result = "OK" .equals(apiCall.getResult()); if (lastSong) { response.value = result; MusicManager.this .onFinish(response); } return result; } }, context); currentSong++; } return Boolean.TRUE; } }, context); } public void setPlaylistSong(DataResponse<Boolean> response, int position, Context context) { setPlaylist(PLAYLIST_MUSIC, response, position, context); } public void removeFromPlaylist(DataResponse<Boolean> response, int position, Context context) { removeFromPlaylist(PLAYLIST_MUSIC, response, position, context); } public void getPlaylist(DataResponse<ArrayList<String>> response, Context context) { getPlaylist(PLAYLIST_MUSIC, response, context); } public void getPlaylistPosition(DataResponse<Integer> response, Context context) { getPlaylistPosition(PLAYLIST_MUSIC, response, context); } public void play(DataResponse<Boolean> response, Album album, Context context) { call(new Player.Open(new PlaylistModel.Item( new PlaylistModel.Item.Albumid(album.getId()))), new ApiHandler<Boolean, String>() { @Override public Boolean handleResponse(AbstractCall<String> apiCall) { return "OK".equals(apiCall.getResult()); } }, response, context); } public void play(DataResponse<Boolean> response, Genre genre, Context context) { call(new Player.Open(new PlaylistModel.Item( new PlaylistModel.Item.Genreid(genre.getId()))), new ApiHandler<Boolean, String>() { @Override public Boolean handleResponse(AbstractCall<String> apiCall) { return "OK".equals(apiCall.getResult()); } }, response, context); } public void play(DataResponse<Boolean> response, Song song, Context context) { call(new Player.Open(new PlaylistModel.Item( new PlaylistModel.Item.Songid(song.getId()))), new ApiHandler<Boolean, String>() { @Override public Boolean handleResponse(AbstractCall<String> apiCall) { return "OK".equals(apiCall.getResult()); } }, response, context); } public void play(final DataResponse<Boolean> response, final Album album, final Song song, final Context context) { callRaw(new AudioLibrary.GetSongs(null, getSort(SongDetail.TRACK), new AudioLibrary.GetSongs.FilterAlbumId(album.getId()), SongDetail.ARTIST, SongDetail.TITLE, SongDetail.ALBUM, SongDetail.TRACK, SongDetail.DISC, SongDetail.DURATION, SongDetail.FILE, SongDetail.THUMBNAIL), new ApiHandler<Boolean, SongDetail>() { @Override public Boolean handleResponse( AbstractCall<SongDetail> apiCall) { List<SongDetail> songDetails = apiCall.getResults(); int songCount = 0; boolean foundStart = false; for (SongDetail songDetail : songDetails) { songCount++; if (songDetail.songid == song.getId()) { callRaw(new Player.Open(new PlaylistModel.Item( new PlaylistModel.Item.Songid( songDetail.songid))), new ApiHandler<Boolean, String>() { @Override public Boolean handleResponse( AbstractCall<String> apiCall) { return "OK".equals(apiCall .getResult()); } }, context); foundStart = true; } else if (foundStart && songDetails.size() == songCount) { call(new Playlist.Add(PLAYLIST_MUSIC, new PlaylistModel.Item( new PlaylistModel.Item.Songid( songDetail.songid))), new ApiHandler<Boolean, String>() { @Override public Boolean handleResponse( AbstractCall<String> apiCall) { return "OK".equals(apiCall .getResult()); } }, response, context); } else if (foundStart) { callRaw(new Playlist.Add(PLAYLIST_MUSIC, new PlaylistModel.Item( new PlaylistModel.Item.Songid( songDetail.songid))), new ApiHandler<Boolean, String>() { @Override public Boolean handleResponse( AbstractCall<String> apiCall) { return "OK".equals(apiCall .getResult()); } }, context); } } return Boolean.TRUE; } }, context); } public void play(DataResponse<Boolean> response, Artist artist, Context context) { call(new Player.Open(new PlaylistModel.Item( new PlaylistModel.Item.Artistid(artist.getId()))), new ApiHandler<Boolean, String>() { @Override public Boolean handleResponse(AbstractCall<String> apiCall) { return "OK".equals(apiCall.getResult()); } }, response, context); } public void play(final DataResponse<Boolean> response, Artist artist, Genre genre, final Context context) { List<SongFilter> songFilters = new ArrayList<SongFilter>(); // SongFilterRule(String operator, Value value, String field) songFilters.add(new SongFilter(new SongFilterRule("is", new Value( Integer.toString(artist.getId())), "artist"))); songFilters.add(new SongFilter(new SongFilterRule("is", new Value( Integer.toString(genre.getId())), "genre"))); ListModel.SongFilter filter = new ListModel.SongFilter( new ListModel.SongFilter.And(songFilters)); callRaw(new AudioLibrary.GetSongs(null, filter), new ApiHandler<Boolean, SongDetail>() { @Override public Boolean handleResponse( AbstractCall<SongDetail> apiCall) { List<SongDetail> songDetails = apiCall.getResults(); int currentSong = 1; ArrayList<Song> result = new ArrayList<Song>(); for (SongDetail songDetail : songDetails) { final boolean lastSong = currentSong == songDetails .size(); if (currentSong == 1) { callRaw(new Player.Open(new PlaylistModel.Item( new PlaylistModel.Item.Songid( songDetail.songid))), new ApiHandler<Boolean, String>() { @Override public Boolean handleResponse( AbstractCall<String> apiCall) { boolean result = "OK" .equals(apiCall .getResult()); if (lastSong) { response.value = result; MusicManager.this .onFinish(response); } return result; } }, context); continue; } callRaw(new Playlist.Add(PLAYLIST_MUSIC, new PlaylistModel.Item( new PlaylistModel.Item.Songid( songDetail.songid))), new ApiHandler<Boolean, String>() { @Override public Boolean handleResponse( AbstractCall<String> apiCall) { boolean result = "OK" .equals(apiCall.getResult()); if (lastSong) { response.value = result; MusicManager.this .onFinish(response); } return result; } }, context); currentSong++; } return Boolean.TRUE; } }, context); } public void updateAlbumInfo(DataResponse<Album> response, final Album album, Context context) { call(new AudioLibrary.GetAlbumDetails(album.getId(), AlbumDetail.GENRE, AlbumDetail.RATING, AlbumDetail.YEAR), new ApiHandler<Album, AlbumDetail>() { @Override public Album handleResponse( AbstractCall<AlbumDetail> apiCall) { AlbumDetail detail = apiCall.getResult(); album.genres = detail.genre; album.rating = detail.rating; album.year = detail.year; return album; } }, response, context); } public void updateArtistInfo(DataResponse<Artist> response, final Artist artist, Context context) { call(new AudioLibrary.GetArtistDetails(artist.getId(), ArtistDetail.BORN, ArtistDetail.FORMED, ArtistDetail.GENRE, ArtistDetail.MOOD, ArtistDetail.STYLE, ArtistDetail.DESCRIPTION), new ApiHandler<Artist, ArtistDetail>() { @Override public Artist handleResponse( AbstractCall<ArtistDetail> apiCall) { ArtistDetail detail = apiCall.getResult(); artist.born = detail.born; artist.formed = detail.formed; artist.genres = detail.genre; artist.moods = detail.mood; artist.styles = detail.style; artist.biography = detail.description; return artist; } }, response, context); } public void downloadCover(DataResponse<Bitmap> response, ICoverArt cover, int thumbSize, Context context) throws WifiStateException { if (cover instanceof Album) { response.value = getCover(cover, thumbSize, Album.getThumbUri(cover), Album.getFallbackThumbUri(cover)); return; } else if (cover instanceof Artist) { response.value = getCover(cover, thumbSize, Artist.getThumbUri(cover), Artist.getFallbackThumbUri(cover)); return; } throw new RuntimeException("Unsupported cover type"); } }