diff --git a/app/src/main/java/app/fedilab/fedilabtube/PeertubeActivity.java b/app/src/main/java/app/fedilab/fedilabtube/PeertubeActivity.java index 5f6051b..bb723de 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/PeertubeActivity.java +++ b/app/src/main/java/app/fedilab/fedilabtube/PeertubeActivity.java @@ -68,8 +68,10 @@ import androidx.recyclerview.widget.RecyclerView; import com.github.vkay94.dtpv.youtube.YouTubeOverlay; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.MediaItem; +import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector; import com.google.android.exoplayer2.source.MediaSource; @@ -136,9 +138,10 @@ import static app.fedilab.fedilabtube.client.RetrofitPeertubeAPI.ActionType.REPO import static app.fedilab.fedilabtube.helper.Helper.getAttColor; import static app.fedilab.fedilabtube.helper.Helper.getLiveInstance; import static app.fedilab.fedilabtube.helper.Helper.isLoggedIn; +import static com.google.android.exoplayer2.Player.MEDIA_ITEM_TRANSITION_REASON_AUTO; -public class PeertubeActivity extends AppCompatActivity implements CommentListAdapter.AllCommentRemoved { +public class PeertubeActivity extends AppCompatActivity implements CommentListAdapter.AllCommentRemoved, Player.EventListener { public static String video_id; private String peertubeInstance, videoUuid; @@ -165,6 +168,8 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd private BroadcastReceiver mPowerKeyReceiver = null; private boolean isPlayInMinimized; private Intent urlIntent; + public static List playedVideos = new ArrayList<>(); + private VideoData.Video nextVideo; public static void hideKeyboard(Activity activity) { if (activity != null && activity.getWindow() != null) { @@ -572,6 +577,35 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd } + public void manageNextVideos(APIResponse apiResponse) { + if (apiResponse == null || apiResponse.getError() != null || apiResponse.getPeertubes() == null || apiResponse.getPeertubes().size() == 0) { + return; + } + List suggestedVideos = apiResponse.getPeertubes(); + for(VideoData.Video video: suggestedVideos) { + if(!playedVideos.contains(video.getId())){ + TimelineVM feedsViewModel = new ViewModelProvider(PeertubeActivity.this).get(TimelineVM.class); + feedsViewModel.getVideo(null, suggestedVideos.get(0).getUuid(), false).observe(PeertubeActivity.this, this::nextVideoDetails); + return; + } + } + } + + @SuppressLint("ClickableViewAccessibility") + public void nextVideoDetails(APIResponse apiResponse) { + if (apiResponse == null || (apiResponse.getError() != null) || apiResponse.getPeertubes() == null || apiResponse.getPeertubes().size() == 0) { + return; + } + int i = 0; + while (i < (apiResponse.getPeertubes().size()-1) && playedVideos.contains(apiResponse.getPeertubes().get(i).getId())) { + i++; + } + nextVideo = apiResponse.getPeertubes().get(i); + MediaItem mediaItem = new MediaItem.Builder().setUri(Uri.parse(nextVideo.getFileUrl(null, PeertubeActivity.this))).build(); + player.addMediaItem(mediaItem); + } + + @SuppressLint("ClickableViewAccessibility") public void manageVIewVideo(APIResponse apiResponse) { @@ -588,6 +622,10 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd peertube = apiResponse.getPeertubes().get(0); + if( peertube.getTags() != null && peertube.getTags().size() > 0) { + SearchVM searchViewModel = new ViewModelProvider(PeertubeActivity.this).get(SearchVM.class); + searchViewModel.searchNextVideos(peertube.getTags()).observe(PeertubeActivity.this, this::manageNextVideos); + } if (sepiaSearch) { peertubeInstance = peertube.getAccount().getHost(); } @@ -711,6 +749,7 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd ProgressiveMediaSource videoSource; player = new SimpleExoPlayer.Builder(PeertubeActivity.this).build(); + player.addListener(this); binding.mediaVideo.player(player); binding.doubleTapPlayerView.setPlayer(player); binding.loader.setVisibility(View.GONE); @@ -1273,6 +1312,8 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd } player.setPlayWhenReady(true); }); + View exo_next = controlView.findViewById(R.id.exo_next); + exo_next.setOnClickListener(v -> playNextVideo()); } private void initResolution() { @@ -1415,4 +1456,35 @@ public class PeertubeActivity extends AppCompatActivity implements CommentListAd public void onAllCommentRemoved() { binding.noActionText.setVisibility(View.VISIBLE); } + + + + private void playNextVideo() { + if( nextVideo != null) { + Intent intent = new Intent(PeertubeActivity.this, PeertubeActivity.class); + Bundle b = new Bundle(); + b.putParcelable("video",nextVideo); + b.putString("video_id", nextVideo.getId()); + b.putString("video_uuid", nextVideo.getUuid()); + playedVideos.add(nextVideo.getId()); + b.putBoolean("sepia_search", sepiaSearch); + intent.putExtras(b); + startActivity(intent); + } + } + + + + @Override + public void onMediaItemTransition(MediaItem mediaItem, int reason) { + if (reason == MEDIA_ITEM_TRANSITION_REASON_AUTO){ + player.removeMediaItems(0, player.getMediaItemCount()); + playNextVideo(); + } + } + + @Override + public void onPlayerError(ExoPlaybackException error) { + + } } diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeService.java b/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeService.java index ab11398..cbf6d1f 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeService.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/PeertubeService.java @@ -172,7 +172,20 @@ public interface PeertubeService { //Search @GET("search/videos") - Call searchVideos(@Header("Authorization") String credentials, @Query("search") String search, @Query("start") String maxId, @Query("count") String count); + Call searchVideos( + @Header("Authorization") String credentials, + @Query("search") String search, + @Query("start") String maxId, + @Query("count") String count); + + + //Search + @GET("search/videos") + Call searchNextVideo( + @Header("Authorization") String credentials, + @Query("tagsOneOf") List tagsOneOf, + @Query("start") String maxId, + @Query("count") String count); //Get notifications @GET("users/me/notifications") diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/RetrofitPeertubeAPI.java b/app/src/main/java/app/fedilab/fedilabtube/client/RetrofitPeertubeAPI.java index eeccf16..e9f84b1 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/RetrofitPeertubeAPI.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/RetrofitPeertubeAPI.java @@ -702,6 +702,33 @@ public class RetrofitPeertubeAPI { return apiResponse; } + + /** + * Retrieves next peertube videos *synchronously* + * + * @param tags List search + * @return APIResponse + */ + public APIResponse searchNextVideos(List tags) { + PeertubeService peertubeService = init(); + Call searchVideosCall = peertubeService.searchNextVideo(getToken(), tags, "0" , "20"); + APIResponse apiResponse = new APIResponse(); + try { + Response response = searchVideosCall.execute(); + if (response.isSuccessful() && response.body() != null) { + apiResponse.setPeertubes(response.body().data); + } else { + setError(apiResponse, response.code(), response.errorBody()); + } + } catch (IOException e) { + Error error = new Error(); + error.setError(_context.getString(R.string.toast_error)); + apiResponse.setError(error); + e.printStackTrace(); + } + return apiResponse; + } + /** * Retrieves peertube search *synchronously* * diff --git a/app/src/main/java/app/fedilab/fedilabtube/client/entities/File.java b/app/src/main/java/app/fedilab/fedilabtube/client/entities/File.java index 2d0b50d..1120da2 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/client/entities/File.java +++ b/app/src/main/java/app/fedilab/fedilabtube/client/entities/File.java @@ -1,10 +1,13 @@ package app.fedilab.fedilabtube.client.entities; +import android.os.Parcel; +import android.os.Parcelable; + import com.google.gson.annotations.SerializedName; @SuppressWarnings({"unused", "RedundantSuppression"}) -public class File { +public class File implements Parcelable { @SerializedName("fileDownloadUrl") private String fileDownloadUrl; @@ -96,4 +99,50 @@ public class File { public void setTorrentUrl(String torrentUrl) { this.torrentUrl = torrentUrl; } + + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(this.fileDownloadUrl); + dest.writeString(this.fileUrl); + dest.writeInt(this.fps); + dest.writeString(this.magnetUri); + dest.writeString(this.metadataUrl); + dest.writeParcelable(this.resolutions, flags); + dest.writeLong(this.size); + dest.writeString(this.torrentDownloadUrl); + dest.writeString(this.torrentUrl); + } + + public File() { + } + + protected File(Parcel in) { + this.fileDownloadUrl = in.readString(); + this.fileUrl = in.readString(); + this.fps = in.readInt(); + this.magnetUri = in.readString(); + this.metadataUrl = in.readString(); + this.resolutions = in.readParcelable(Item.class.getClassLoader()); + this.size = in.readLong(); + this.torrentDownloadUrl = in.readString(); + this.torrentUrl = in.readString(); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public File createFromParcel(Parcel source) { + return new File(source); + } + + @Override + public File[] newArray(int size) { + return new File[size]; + } + }; } diff --git a/app/src/main/java/app/fedilab/fedilabtube/viewmodel/SearchVM.java b/app/src/main/java/app/fedilab/fedilabtube/viewmodel/SearchVM.java index 7f43034..a46eb30 100644 --- a/app/src/main/java/app/fedilab/fedilabtube/viewmodel/SearchVM.java +++ b/app/src/main/java/app/fedilab/fedilabtube/viewmodel/SearchVM.java @@ -24,6 +24,8 @@ import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; +import java.util.List; + import app.fedilab.fedilabtube.client.APIResponse; import app.fedilab.fedilabtube.client.RetrofitPeertubeAPI; @@ -41,6 +43,12 @@ public class SearchVM extends AndroidViewModel { return apiResponseMutableLiveData; } + public LiveData searchNextVideos(List tags) { + apiResponseMutableLiveData = new MutableLiveData<>(); + loadNextVideos(tags); + return apiResponseMutableLiveData; + } + private void loadVideos(String max_id, String query) { Context _mContext = getApplication().getApplicationContext(); new Thread(() -> { @@ -55,4 +63,20 @@ public class SearchVM extends AndroidViewModel { } }).start(); } + + + private void loadNextVideos(List tags) { + Context _mContext = getApplication().getApplicationContext(); + new Thread(() -> { + try { + RetrofitPeertubeAPI api = new RetrofitPeertubeAPI(_mContext); + APIResponse apiResponse = api.searchNextVideos(tags); + Handler mainHandler = new Handler(Looper.getMainLooper()); + Runnable myRunnable = () -> apiResponseMutableLiveData.setValue(apiResponse); + mainHandler.post(myRunnable); + } catch (Exception e) { + e.printStackTrace(); + } + }).start(); + } }