wip: initial refactor of instant mix in to be used everywhere else

This commit is contained in:
eddyizm 2025-12-26 17:03:41 -08:00
parent bbd6d0864c
commit 3c1975f6bf
No known key found for this signature in database
GPG key ID: CF5F671829E8158A

View file

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