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 89b89b2fe..8aa1a0c8c 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 @@ -108,6 +108,23 @@ public interface PlaylistStreamDAO extends BasicDAO { + " 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 3de630b96..08e43df95 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 @@ -96,8 +96,8 @@ public class LocalPlaylistFragment extends BaseLocalListFragment showError(new ErrorInfo(throwable, UserAction.REQUESTED_BOOKMARK, "Removing watched videos, partially watched=" + removePartiallyWatched)))); } @@ -629,6 +633,43 @@ public class LocalPlaylistFragment extends BaseLocalListFragment 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 0cf2d67c5..27c148561 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 @@ -93,6 +93,11 @@ public class LocalPlaylistManager { 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 0ff182b48..c57e8ad95 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 c842dc51b..ba217650f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -632,6 +632,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