diff --git a/app/src/main/java/com/cappielloantonio/tempo/repository/SongRepository.java b/app/src/main/java/com/cappielloantonio/tempo/repository/SongRepository.java index a40b3c97..4457d37b 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/repository/SongRepository.java +++ b/app/src/main/java/com/cappielloantonio/tempo/repository/SongRepository.java @@ -6,17 +6,22 @@ import androidx.lifecycle.MutableLiveData; import com.cappielloantonio.tempo.App; import com.cappielloantonio.tempo.subsonic.base.ApiResponse; import com.cappielloantonio.tempo.subsonic.models.Child; +import com.cappielloantonio.tempo.subsonic.models.SubsonicResponse; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; public class SongRepository { - private static final String TAG = "SongRepository"; + + public interface MediaCallbackInternal { + void onSongsAvailable(List songs); + } public MutableLiveData> getStarredSongs(boolean random, int size) { MutableLiveData> starredSongs = new MutableLiveData<>(Collections.emptyList()); @@ -42,219 +47,228 @@ public class SongRepository { } @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - - } + public void onFailure(@NonNull Call call, @NonNull Throwable t) {} }); return starredSongs; } + /** + * Used by ViewModels. Updates the LiveData list incrementally as songs are found. + */ public MutableLiveData> getInstantMix(String id, int count) { - MutableLiveData> instantMix = new MutableLiveData<>(); + MutableLiveData> instantMix = new MutableLiveData<>(new ArrayList<>()); - App.getSubsonicClientInstance(false) - .getBrowsingClient() - .getSimilarSongs2(id, count) - .enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getSimilarSongs2() != null) { - instantMix.setValue(response.body().getSubsonicResponse().getSimilarSongs2().getSongs()); - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - instantMix.setValue(null); - } - }); + performSmartMix(id, count, songs -> { + List current = instantMix.getValue(); + if (current != null) { + for (Child s : songs) { + if (!current.contains(s)) current.add(s); + } + instantMix.postValue(current); + } + }); return instantMix; } - public MutableLiveData> getRandomSample(int number, Integer fromYear, Integer toYear) { - MutableLiveData> randomSongsSample = new MutableLiveData<>(); + /** + * Overloaded method used by other Repositories + */ + public void getInstantMix(String id, int count, MediaCallbackInternal callback) { + performSmartMix(id, count, callback); + } + private void performSmartMix(final String id, final int count, final MediaCallbackInternal callback) { App.getSubsonicClientInstance(false) - .getAlbumSongListClient() - .getRandomSongs(number, fromYear, toYear) + .getBrowsingClient() + .getSimilarSongs(id, count) .enqueue(new Callback() { @Override public void onResponse(@NonNull Call call, @NonNull Response response) { - List songs = new ArrayList<>(); - - if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getRandomSongs() != null && response.body().getSubsonicResponse().getRandomSongs().getSongs() != null) { - songs.addAll(response.body().getSubsonicResponse().getRandomSongs().getSongs()); + List songs = extractSongs(response, "similarSongs"); + if (!songs.isEmpty()) { + callback.onSongsAvailable(songs); + } + if (songs.size() < count / 2) { + fetchContextAndSeed(id, count, callback); } - - randomSongsSample.setValue(songs); } @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) { - + fetchContextAndSeed(id, count, callback); } }); + } + private void fetchContextAndSeed(final String id, final int count, final MediaCallbackInternal callback) { + App.getSubsonicClientInstance(false) + .getBrowsingClient() + .getAlbum(id) + .enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getAlbum() != null) { + List albumSongs = response.body().getSubsonicResponse().getAlbum().getSongs(); + if (albumSongs != null && !albumSongs.isEmpty()) { + callback.onSongsAvailable(new ArrayList<>(albumSongs)); + String seedArtistId = albumSongs.get(0).getArtistId(); + fetchSimilarByArtist(seedArtistId, count, callback); + return; + } + } + fillWithRandom(count, callback); + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + fillWithRandom(count, callback); + } + }); + } + + private void fetchSimilarByArtist(String artistId, final int count, final MediaCallbackInternal callback) { + App.getSubsonicClientInstance(false) + .getBrowsingClient() + .getSimilarSongs2(artistId, count) + .enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + List similar = extractSongs(response, "similarSongs2"); + if (!similar.isEmpty()) { + callback.onSongsAvailable(similar); + } + } + @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) {} + }); + } + + private void fillWithRandom(int target, final MediaCallbackInternal callback) { + App.getSubsonicClientInstance(false) + .getAlbumSongListClient() + .getRandomSongs(target, null, null) + .enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + callback.onSongsAvailable(extractSongs(response, "randomSongs")); + } + @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) {} + }); + } + + private List extractSongs(Response response, String type) { + if (response.isSuccessful() && response.body() != null) { + SubsonicResponse res = response.body().getSubsonicResponse(); + List list = null; + if (type.equals("similarSongs") && res.getSimilarSongs() != null) { + list = res.getSimilarSongs().getSongs(); + } else if (type.equals("similarSongs2") && res.getSimilarSongs2() != null) { + list = res.getSimilarSongs2().getSongs(); + } else if (type.equals("randomSongs") && res.getRandomSongs() != null) { + list = res.getRandomSongs().getSongs(); + } + return (list != null) ? list : new ArrayList<>(); + } + return new ArrayList<>(); + } + public MutableLiveData> getRandomSample(int number, Integer fromYear, Integer toYear) { + MutableLiveData> randomSongsSample = new MutableLiveData<>(); + App.getSubsonicClientInstance(false).getAlbumSongListClient().getRandomSongs(number, fromYear, toYear).enqueue(new Callback() { + @Override public void onResponse(@NonNull Call call, @NonNull Response response) { + List songs = new ArrayList<>(); + if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getRandomSongs() != null) { + songs.addAll(Objects.requireNonNull(response.body().getSubsonicResponse().getRandomSongs().getSongs())); + } + randomSongsSample.setValue(songs); + } + @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) {} + }); return randomSongsSample; } public MutableLiveData> getRandomSampleWithGenre(int number, Integer fromYear, Integer toYear, String genre) { MutableLiveData> randomSongsSample = new MutableLiveData<>(); - - App.getSubsonicClientInstance(false) - .getAlbumSongListClient() - .getRandomSongs(number, fromYear, toYear, genre) - .enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - List songs = new ArrayList<>(); - - if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getRandomSongs() != null && response.body().getSubsonicResponse().getRandomSongs().getSongs() != null) { - songs.addAll(response.body().getSubsonicResponse().getRandomSongs().getSongs()); - } - - randomSongsSample.setValue(songs); - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - - } - }); - + App.getSubsonicClientInstance(false).getAlbumSongListClient().getRandomSongs(number, fromYear, toYear, genre).enqueue(new Callback() { + @Override public void onResponse(@NonNull Call call, @NonNull Response response) { + List songs = new ArrayList<>(); + if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getRandomSongs() != null) { + songs.addAll(Objects.requireNonNull(response.body().getSubsonicResponse().getRandomSongs().getSongs())); + } + randomSongsSample.setValue(songs); + } + @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) {} + }); return randomSongsSample; } public void scrobble(String id, boolean submission) { - App.getSubsonicClientInstance(false) - .getMediaAnnotationClient() - .scrobble(id, submission) - .enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - - } - }); + App.getSubsonicClientInstance(false).getMediaAnnotationClient().scrobble(id, submission).enqueue(new Callback() { + @Override public void onResponse(@NonNull Call call, @NonNull Response response) {} + @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) {} + }); } public void setRating(String id, int rating) { - App.getSubsonicClientInstance(false) - .getMediaAnnotationClient() - .setRating(id, rating) - .enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - - } - }); + App.getSubsonicClientInstance(false).getMediaAnnotationClient().setRating(id, rating).enqueue(new Callback() { + @Override public void onResponse(@NonNull Call call, @NonNull Response response) {} + @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) {} + }); } public MutableLiveData> getSongsByGenre(String id, int page) { MutableLiveData> songsByGenre = new MutableLiveData<>(); - - App.getSubsonicClientInstance(false) - .getAlbumSongListClient() - .getSongsByGenre(id, 100, 100 * page) - .enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getSongsByGenre() != null) { - songsByGenre.setValue(response.body().getSubsonicResponse().getSongsByGenre().getSongs()); - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - - } - }); - + App.getSubsonicClientInstance(false).getAlbumSongListClient().getSongsByGenre(id, 100, 100 * page).enqueue(new Callback() { + @Override public void onResponse(@NonNull Call call, @NonNull Response response) { + if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getSongsByGenre() != null) { + songsByGenre.setValue(response.body().getSubsonicResponse().getSongsByGenre().getSongs()); + } + } + @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) {} + }); return songsByGenre; } public MutableLiveData> getSongsByGenres(ArrayList genresId) { MutableLiveData> songsByGenre = new MutableLiveData<>(); - - for (String id : genresId) - App.getSubsonicClientInstance(false) - .getAlbumSongListClient() - .getSongsByGenre(id, 500, 0) - .enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - List songs = new ArrayList<>(); - - if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getSongsByGenre() != null) { - songs.addAll(response.body().getSubsonicResponse().getSongsByGenre().getSongs()); - } - - songsByGenre.setValue(songs); - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - - } - }); - + for (String id : genresId) { + App.getSubsonicClientInstance(false).getAlbumSongListClient().getSongsByGenre(id, 500, 0).enqueue(new Callback() { + @Override public void onResponse(@NonNull Call call, @NonNull Response response) { + List songs = new ArrayList<>(); + if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getSongsByGenre() != null) { + songs.addAll(Objects.requireNonNull(response.body().getSubsonicResponse().getSongsByGenre().getSongs())); + } + songsByGenre.setValue(songs); + } + @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) {} + }); + } return songsByGenre; } public MutableLiveData getSong(String id) { MutableLiveData song = new MutableLiveData<>(); - - App.getSubsonicClientInstance(false) - .getBrowsingClient() - .getSong(id) - .enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - if (response.isSuccessful() && response.body() != null) { - song.setValue(response.body().getSubsonicResponse().getSong()); - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - - } - }); - + App.getSubsonicClientInstance(false).getBrowsingClient().getSong(id).enqueue(new Callback() { + @Override public void onResponse(@NonNull Call call, @NonNull Response response) { + if (response.isSuccessful() && response.body() != null) { + song.setValue(response.body().getSubsonicResponse().getSong()); + } + } + @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) {} + }); return song; } public MutableLiveData getSongLyrics(Child song) { MutableLiveData lyrics = new MutableLiveData<>(null); - - App.getSubsonicClientInstance(false) - .getMediaRetrievalClient() - .getLyrics(song.getArtist(), song.getTitle()) - .enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getLyrics() != null) { - lyrics.setValue(response.body().getSubsonicResponse().getLyrics().getValue()); - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - - } - }); - + App.getSubsonicClientInstance(false).getMediaRetrievalClient().getLyrics(song.getArtist(), song.getTitle()).enqueue(new Callback() { + @Override public void onResponse(@NonNull Call call, @NonNull Response response) { + if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getLyrics() != null) { + lyrics.setValue(response.body().getSubsonicResponse().getLyrics().getValue()); + } + } + @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) {} + }); return lyrics; } -} +} \ No newline at end of file