diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/dao/PlaylistStreamDAO.java b/app/src/main/java/org/schabi/newpipe/database/playlist/dao/PlaylistStreamDAO.java index f173ab0bc09..54bad15d43a 100644 --- a/app/src/main/java/org/schabi/newpipe/database/playlist/dao/PlaylistStreamDAO.java +++ b/app/src/main/java/org/schabi/newpipe/database/playlist/dao/PlaylistStreamDAO.java @@ -97,6 +97,23 @@ default Flowable> listByService(final int serviceId) + " ORDER BY " + PLAYLIST_NAME + " COLLATE NOCASE ASC") Flowable> getPlaylistMetadata(); + @RewriteQueriesToDropUnusedColumns + @Transaction + @Query("SELECT *, MIN(" + JOIN_INDEX + ")" + + " FROM " + STREAM_TABLE + " INNER JOIN" + + " (SELECT " + JOIN_STREAM_ID + "," + JOIN_INDEX + + " FROM " + PLAYLIST_STREAM_JOIN_TABLE + + " WHERE " + JOIN_PLAYLIST_ID + " = :playlistId)" + + " ON " + STREAM_ID + " = " + JOIN_STREAM_ID + + " LEFT JOIN " + + "(SELECT " + JOIN_STREAM_ID + " AS " + JOIN_STREAM_ID_ALIAS + ", " + + STREAM_PROGRESS_MILLIS + + " FROM " + STREAM_STATE_TABLE + " )" + + " ON " + STREAM_ID + " = " + JOIN_STREAM_ID_ALIAS + + " GROUP BY " + STREAM_ID + + " ORDER BY MIN(" + JOIN_INDEX + ") ASC") + Flowable> getStreamsWithoutDuplicates(long playlistId); + @Transaction @Query("SELECT " + PLAYLIST_TABLE + "." + PLAYLIST_ID + ", " + PLAYLIST_NAME + ", " diff --git a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java index 68a35e72b2e..1da211b8097 100644 --- a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java @@ -95,8 +95,8 @@ public class LocalPlaylistFragment extends BaseLocalListFragment showError(new ErrorInfo(throwable, UserAction.REQUESTED_BOOKMARK, "Removing watched videos, partially watched=" + removePartiallyWatched)))); } @@ -628,6 +632,43 @@ private void updateThumbnailUrl() { changeThumbnailUrl(newThumbnailUrl, false); } + private void openRemoveDuplicatesDialog() { + final AlertDialog.Builder builder = new AlertDialog.Builder(this.getActivity()); + + builder.setTitle(R.string.remove_duplicates_title) + .setMessage(R.string.remove_duplicates_message) + .setPositiveButton(R.string.ok, + (dialog, i) -> removeDuplicatesInPlaylist()) + .setNeutralButton(R.string.cancel, null); + + builder.create().show(); + } + + private void removeDuplicatesInPlaylist() { + if (isRewritingPlaylist) { + return; + } + isRewritingPlaylist = true; + showLoading(); + + final var streamsMaybe = playlistManager + .getDistinctPlaylistStreams(playlistId).firstElement(); + + + disposables.add(streamsMaybe.subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(itemsToKeep -> { + itemListAdapter.clearStreamItemList(); + itemListAdapter.addItems(itemsToKeep); + setVideoCount(itemListAdapter.getItemsList().size()); + saveChanges(); + + hideLoading(); + isRewritingPlaylist = false; + }, throwable -> showError(new ErrorInfo(throwable, UserAction.REQUESTED_BOOKMARK, + "Removing duplicated streams")))); + } + private void deleteItem(final PlaylistStreamEntry item) { if (itemListAdapter == null) { return; diff --git a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistManager.java b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistManager.java index 8ea64f34376..fd158b2d561 100644 --- a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistManager.java +++ b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistManager.java @@ -88,6 +88,11 @@ public Flowable> getPlaylists() { return playlistStreamTable.getPlaylistMetadata().subscribeOn(Schedulers.io()); } + public Flowable> getDistinctPlaylistStreams(final long playlistId) { + return playlistStreamTable + .getStreamsWithoutDuplicates(playlistId).subscribeOn(Schedulers.io()); + } + /** * Get playlists with attached information about how many times the provided stream is already * contained in each playlist. diff --git a/app/src/main/res/menu/menu_local_playlist.xml b/app/src/main/res/menu/menu_local_playlist.xml index 0ff182b48bd..c57e8ad9580 100644 --- a/app/src/main/res/menu/menu_local_playlist.xml +++ b/app/src/main/res/menu/menu_local_playlist.xml @@ -12,8 +12,14 @@ android:id="@+id/menu_item_rename_playlist" android:title="@string/rename_playlist" app:showAsAction="never" /> + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 661f05c8c50..8a1342f5069 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -631,6 +631,9 @@ System default Remove watched Remove watched videos? + Remove duplicates + Remove duplicates? + Do you want to remove all duplicate streams in this playlist? Videos that have been watched before and after being added to the playlist will be removed. \nAre you sure\? This cannot be undone! Yes, and partially watched videos