Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 195 additions & 0 deletions app/src/main/java/com/cappielloantonio/tempo/service/MediaManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,16 @@
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

import java.lang.ref.WeakReference;
import java.util.List;
import java.util.Collections;
import java.util.stream.Collectors;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
Expand Down Expand Up @@ -239,6 +246,153 @@ public static void startQueue(ListenableFuture<MediaBrowser> mediaBrowserListena
}
}

public static void startQueue(List<Child> media, int startIndex) {


//Stop current media
App.getSubsonicClientInstance(false)
.getJukeboxControlClient()
.jukeboxControl("stop", null, null, null, null)
.enqueue(new Callback<ApiResponse>() {
@Override
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {

//Pull the ids from the list of media and put into a string list for jukeboxControl
List<String> ids = media.stream()
.map(Child::getId)
.collect(Collectors.toList());

int itemCount = media.size();

App.getSubsonicClientInstance(false)
.getJukeboxControlClient()
.jukeboxControl("set", null, null, ids, null)
.enqueue(new Callback<ApiResponse>() {
@Override
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {

// Then skip to startIndex if valid
if (itemCount > 0 && startIndex >= 0 && startIndex < itemCount) {
App.getSubsonicClientInstance(false)
.getJukeboxControlClient()
.jukeboxControl("skip", startIndex, null, null, null)
.enqueue(new Callback<ApiResponse>() {
@Override
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {

// set does NOT auto-start the queue, must start it here
App.getSubsonicClientInstance(false)
.getJukeboxControlClient()
.jukeboxControl("start", null, null, null, null)
.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) {

}
});

}

@Override
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {

}
});
}

else {

// set does NOT auto-start the queue, must start it here
App.getSubsonicClientInstance(false)
.getJukeboxControlClient()
.jukeboxControl("start", null, null, null, null)
.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) {

}
});

}

}

@Override
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {

}
});

}

@Override
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {

}
});

}

public static void startQueue(Child media) {
//Stop current media
App.getSubsonicClientInstance(false)
.getJukeboxControlClient()
.jukeboxControl("stop", null, null, null, null)
.enqueue(new Callback<ApiResponse>() {
@Override
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
List<String> ids = Collections.singletonList(media.getId());

App.getSubsonicClientInstance(false)
.getJukeboxControlClient()
.jukeboxControl("set", null, null, ids, null)
.enqueue(new Callback<ApiResponse>() {
@Override
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
// set does NOT auto-start the queue, must start it here
App.getSubsonicClientInstance(false)
.getJukeboxControlClient()
.jukeboxControl("start", null, null, null, null)
.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) {

}
});
}

@Override
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {

}
});

}

@Override
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {

}
});


}

public static void playDownloadedMediaItem(ListenableFuture<MediaBrowser> mediaBrowserListenableFuture, MediaItem mediaItem) {
if (mediaBrowserListenableFuture != null && mediaItem != null) {
mediaBrowserListenableFuture.addListener(() -> {
Expand Down Expand Up @@ -338,6 +492,47 @@ public static void enqueue(ListenableFuture<MediaBrowser> mediaBrowserListenable
}
}

public static void enqueue(List<Child> media) {
List<String> ids = media.stream()
.map(Child::getId)
.collect(Collectors.toList());

App.getSubsonicClientInstance(false)
.getJukeboxControlClient()
.jukeboxControl("add", null, null, ids, null)
.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 static void enqueue(Child media){

List<String> ids = Collections.singletonList(media.getId());

App.getSubsonicClientInstance(false)
.getJukeboxControlClient()
.jukeboxControl("add", null, null, ids, null)
.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 static void shuffle(ListenableFuture<MediaBrowser> mediaBrowserListenableFuture, List<Child> media, int startIndex, int endIndex) {
if (mediaBrowserListenableFuture != null) {
mediaBrowserListenableFuture.addListener(() -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.cappielloantonio.tempo.subsonic.api.bookmarks.BookmarksClient;
import com.cappielloantonio.tempo.subsonic.api.browsing.BrowsingClient;
import com.cappielloantonio.tempo.subsonic.api.internetradio.InternetRadioClient;
import com.cappielloantonio.tempo.subsonic.api.jukeboxcontrol.JukeboxControlClient;
import com.cappielloantonio.tempo.subsonic.api.mediaannotation.MediaAnnotationClient;
import com.cappielloantonio.tempo.subsonic.api.medialibraryscanning.MediaLibraryScanningClient;
import com.cappielloantonio.tempo.subsonic.api.mediaretrieval.MediaRetrievalClient;
Expand Down Expand Up @@ -35,6 +36,7 @@ public class Subsonic {
private MediaLibraryScanningClient mediaLibraryScanningClient;
private BookmarksClient bookmarksClient;
private InternetRadioClient internetRadioClient;
private JukeboxControlClient jukeboxControlClient;
private SharingClient sharingClient;
private OpenClient openClient;

Expand Down Expand Up @@ -123,6 +125,13 @@ public InternetRadioClient getInternetRadioClient() {
return internetRadioClient;
}

public JukeboxControlClient getJukeboxControlClient() {
if (jukeboxControlClient == null) {
jukeboxControlClient = new JukeboxControlClient(this);
}
return jukeboxControlClient;
}

public SharingClient getSharingClient() {
if (sharingClient == null) {
sharingClient = new SharingClient(this);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.cappielloantonio.tempo.subsonic.api.jukeboxcontrol;

import android.util.Log;
import java.util.List;

import com.cappielloantonio.tempo.subsonic.RetrofitClient;
import com.cappielloantonio.tempo.subsonic.Subsonic;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;

import retrofit2.Call;

public class JukeboxControlClient {
private static final String TAG = "JukeboxControlClient";

private final Subsonic subsonic;
private final JukeboxControlService jukeboxControlService;

public JukeboxControlClient(Subsonic subsonic) {
this.subsonic = subsonic;
this.jukeboxControlService = new RetrofitClient(subsonic).getRetrofit().create(JukeboxControlService.class);
}

// see https://opensubsonic.netlify.app/docs/endpoints/jukeboxcontrol/ for actions
// "set" to clear queue and add id(s) to queue (does not stop currently playing track)
// "add" to add to end of queue

// index is only used by actions skip and remove
// offset is only used by action skip
// id is only used by actions add and set
// gain is only used by action setGain

public Call<ApiResponse> jukeboxControl(String action, Integer index, Integer offset, List<String> ids, Float gain) {
Log.d(TAG, "jukeboxControl()");
return jukeboxControlService.jukeboxControl(subsonic.getParams(), action, index, offset, ids, gain);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.cappielloantonio.tempo.subsonic.api.jukeboxcontrol;

import com.cappielloantonio.tempo.subsonic.base.ApiResponse;

import java.util.Map;
import java.util.List;

import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
import retrofit2.http.QueryMap;

public interface JukeboxControlService {
@GET("jukeboxControl")
Call<ApiResponse> jukeboxControl(@QueryMap Map<String, String> params, @Query("action") String action, @Query("index") Integer index, @Query("offset") Integer offset, @Query("id") List<String> ids, @Query("gain") Float gain );
}
Original file line number Diff line number Diff line change
Expand Up @@ -298,10 +298,15 @@ private void initMusicButton() {
MediaManager.startQueue(mediaBrowserListenableFuture, songs, 0);
activity.setBottomSheetInPeek(true);
});

bind.albumPageJukeboxButton.setOnClickListener(v -> {
MediaManager.startQueue(songs, 0);
});
}

if (bind != null && songs.isEmpty()) {
bind.albumPagePlayButton.setEnabled(false);
bind.albumPageJukeboxButton.setEnabled(false);
bind.albumPageShuffleButton.setEnabled(false);
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ private void initMusicButton() {
MediaManager.startQueue(mediaBrowserListenableFuture, songs, 0);
activity.setBottomSheetInPeek(true);
});

bind.playlistPageJukeboxButton.setOnClickListener(v -> {
MediaManager.startQueue(songs, 0);
});
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,11 @@ public void onLoadMedia(List<?> media) {
dismissBottomSheet();
}));

TextView addToQueueJukebox = view.findViewById(R.id.add_to_queue_jukebox_text_view);
addToQueueJukebox.setOnClickListener(v -> albumBottomSheetViewModel.getAlbumTracks().observe(getViewLifecycleOwner(), songs -> {
MediaManager.enqueue(songs);
}));

TextView downloadAll = view.findViewById(R.id.download_all_text_view);
albumBottomSheetViewModel.getAlbumTracks().observe(getViewLifecycleOwner(), songs -> {
List<MediaItem> mediaItems = MappingUtil.mapDownloads(songs);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,11 @@ private void init(View view) {
dismissBottomSheet();
});

TextView addToQueueJukebox = view.findViewById(R.id.add_to_queue_jukebox_text_view);
addToQueueJukebox.setOnClickListener(v -> {
MediaManager.enqueue(song);
});

TextView rate = view.findViewById(R.id.rate_text_view);
rate.setOnClickListener(v -> {
Bundle bundle = new Bundle();
Expand Down
13 changes: 13 additions & 0 deletions app/src/main/res/layout/bottom_sheet_album_dialog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,19 @@
android:paddingBottom="12dp"
android:text="@string/album_bottom_sheet_add_to_queue" />

<TextView
android:id="@+id/add_to_queue_jukebox_text_view"
style="@style/LabelMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:paddingStart="20dp"
android:paddingTop="12dp"
android:paddingEnd="20dp"
android:paddingBottom="12dp"
android:text="@string/album_bottom_sheet_add_to_queue_jukebox" />

<TextView
android:id="@+id/download_all_text_view"
style="@style/LabelMedium"
Expand Down
13 changes: 13 additions & 0 deletions app/src/main/res/layout/bottom_sheet_song_dialog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,19 @@
android:paddingBottom="12dp"
android:text="@string/song_bottom_sheet_add_to_queue" />

<TextView
android:id="@+id/add_to_queue_jukebox_text_view"
style="@style/LabelMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:paddingStart="20dp"
android:paddingTop="12dp"
android:paddingEnd="20dp"
android:paddingBottom="12dp"
android:text="@string/song_bottom_sheet_add_to_queue_jukebox" />

<TextView
android:id="@+id/rate_text_view"
style="@style/LabelMedium"
Expand Down
Loading