Skip to content

Commit

Permalink
See if playlists already contain a stream from db
Browse files Browse the repository at this point in the history
  • Loading branch information
Stypox committed Jan 14, 2023
1 parent 9c41bad commit 61a9c79
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 84 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.schabi.newpipe.database.playlist;

import androidx.room.ColumnInfo;

/**
* This class adds a field to {@link PlaylistMetadataEntry} that contains an integer representing
* how many times a specific stream is already contained inside a local playlist. Used to be able
* to grey out playlists which already contain the current stream in the playlist append dialog.
* @see org.schabi.newpipe.local.playlist.LocalPlaylistManager#getPlaylistDuplicates(String)
*/
public class PlaylistDuplicatesEntry extends PlaylistMetadataEntry {
public static final String PLAYLIST_TIMES_STREAM_IS_CONTAINED = "timesStreamIsContained";
@ColumnInfo(name = PLAYLIST_TIMES_STREAM_IS_CONTAINED)
public final long timesStreamIsContained;

public PlaylistDuplicatesEntry(final long uid,
final String name,
final String thumbnailUrl,
final long streamCount,
final long timesStreamIsContained) {
super(uid, name, thumbnailUrl, streamCount);
this.timesStreamIsContained = timesStreamIsContained;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import androidx.room.Transaction;

import org.schabi.newpipe.database.BasicDAO;
import org.schabi.newpipe.database.playlist.PlaylistDuplicatesEntry;
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
import org.schabi.newpipe.database.playlist.PlaylistStreamEntry;
import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity;
Expand All @@ -14,6 +15,7 @@

import io.reactivex.rxjava3.core.Flowable;

import static org.schabi.newpipe.database.playlist.PlaylistDuplicatesEntry.PLAYLIST_TIMES_STREAM_IS_CONTAINED;
import static org.schabi.newpipe.database.playlist.PlaylistMetadataEntry.PLAYLIST_STREAM_COUNT;
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_ID;
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_NAME;
Expand Down Expand Up @@ -49,23 +51,6 @@ default Flowable<List<PlaylistStreamEntity>> listByService(final int serviceId)
+ " WHERE " + JOIN_PLAYLIST_ID + " = :playlistId")
void deleteBatch(long playlistId);

@Query("SELECT COALESCE(COUNT(*), 0)"
+ " FROM " + STREAM_TABLE
+ " LEFT JOIN " + PLAYLIST_STREAM_JOIN_TABLE
+ " ON " + STREAM_ID + " = " + JOIN_STREAM_ID
+ " WHERE " + JOIN_PLAYLIST_ID + " = :playlistId "
+ " AND " + STREAM_URL + " = :streamURL"
)
Flowable<Integer> getDuplicateCount(long playlistId, String streamURL);

@Query("SELECT " + JOIN_PLAYLIST_ID
+ " FROM " + STREAM_TABLE
+ " LEFT JOIN " + PLAYLIST_STREAM_JOIN_TABLE
+ " ON " + STREAM_ID + " = " + JOIN_STREAM_ID
+ " WHERE " + STREAM_URL + " = :streamURL"
)
Flowable<List<Long>> getDuplicatePlaylists(String streamURL);

@Query("SELECT COALESCE(MAX(" + JOIN_INDEX + "), -1)"
+ " FROM " + PLAYLIST_STREAM_JOIN_TABLE
+ " WHERE " + JOIN_PLAYLIST_ID + " = :playlistId")
Expand Down Expand Up @@ -101,4 +86,24 @@ default Flowable<List<PlaylistStreamEntity>> listByService(final int serviceId)
+ " GROUP BY " + JOIN_PLAYLIST_ID
+ " ORDER BY " + PLAYLIST_NAME + " COLLATE NOCASE ASC")
Flowable<List<PlaylistMetadataEntry>> getPlaylistMetadata();

@Transaction
@Query("SELECT " + PLAYLIST_TABLE + "." + PLAYLIST_ID + ", "
+ PLAYLIST_NAME + ", "
+ PLAYLIST_TABLE + "." + PLAYLIST_THUMBNAIL_URL + ", "
+ "COALESCE(COUNT(" + JOIN_PLAYLIST_ID + "), 0) AS " + PLAYLIST_STREAM_COUNT + ", "
+ "COALESCE(SUM(" + STREAM_URL + " = :streamUrl), 0) AS "
+ PLAYLIST_TIMES_STREAM_IS_CONTAINED

+ " FROM " + PLAYLIST_TABLE
+ " LEFT JOIN " + PLAYLIST_STREAM_JOIN_TABLE
+ " ON " + PLAYLIST_TABLE + "." + PLAYLIST_ID + " = " + JOIN_PLAYLIST_ID

+ " LEFT JOIN " + STREAM_TABLE
+ " ON " + STREAM_TABLE + "." + STREAM_ID + " = " + JOIN_STREAM_ID
+ " AND :streamUrl = :streamUrl"

+ " GROUP BY " + JOIN_PLAYLIST_ID
+ " ORDER BY " + PLAYLIST_NAME + " COLLATE NOCASE ASC")
Flowable<List<PlaylistDuplicatesEntry>> getPlaylistDuplicatesMetadata(String streamUrl);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

import org.schabi.newpipe.NewPipeDatabase;
import org.schabi.newpipe.R;
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
import org.schabi.newpipe.database.playlist.PlaylistDuplicatesEntry;
import org.schabi.newpipe.database.stream.model.StreamEntity;
import org.schabi.newpipe.local.LocalItemListAdapter;
import org.schabi.newpipe.local.playlist.LocalPlaylistManager;
Expand All @@ -26,12 +26,8 @@
public final class PlaylistAppendDialog extends PlaylistDialog {
private static final String TAG = PlaylistAppendDialog.class.getCanonicalName();

private static final float DEFAULT_ALPHA = 1f;
private static final float GRAYED_OUT_ALPHA = 0.3f;

private RecyclerView playlistRecyclerView;
private LocalItemListAdapter playlistAdapter;
private List<Long> duplicateIds;

private final CompositeDisposable playlistDisposables = new CompositeDisposable();

Expand Down Expand Up @@ -64,15 +60,13 @@ public void onViewCreated(@NonNull final View view, @Nullable final Bundle saved
final LocalPlaylistManager playlistManager =
new LocalPlaylistManager(NewPipeDatabase.getInstance(requireContext()));

duplicateIds = playlistManager.getDuplicatePlaylists(getStreamEntities().get(0).getUrl())
.blockingFirst();

playlistAdapter = new LocalItemListAdapter(getActivity());
playlistAdapter.setHasStableIds(true);
playlistAdapter.setSelectedListener(selectedItem -> {
final List<StreamEntity> entities = getStreamEntities();
if (selectedItem instanceof PlaylistMetadataEntry && entities != null) {
onPlaylistSelected(playlistManager, (PlaylistMetadataEntry) selectedItem, entities);
if (selectedItem instanceof PlaylistDuplicatesEntry && entities != null) {
onPlaylistSelected(playlistManager,
(PlaylistDuplicatesEntry) selectedItem, entities);
}
});

Expand All @@ -83,7 +77,8 @@ public void onViewCreated(@NonNull final View view, @Nullable final Bundle saved
final View newPlaylistButton = view.findViewById(R.id.newPlaylist);
newPlaylistButton.setOnClickListener(ignored -> openCreatePlaylistDialog());

playlistDisposables.add(playlistManager.getPlaylists()
playlistDisposables.add(playlistManager
.getPlaylistDuplicates(getStreamEntities().get(0).getUrl())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::onPlaylistsReceived));
}
Expand Down Expand Up @@ -125,63 +120,24 @@ public void openCreatePlaylistDialog() {
requireDialog().dismiss();
}

private void onPlaylistsReceived(@NonNull final List<PlaylistMetadataEntry> playlists) {
private void onPlaylistsReceived(@NonNull final List<PlaylistDuplicatesEntry> playlists) {
if (playlistAdapter != null && playlistRecyclerView != null) {
playlistAdapter.clearStreamItemList();
playlistAdapter.addItems(playlists);
playlistRecyclerView.setVisibility(View.VISIBLE);

playlistRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull final RecyclerView recyclerView, final int dx,
final int dy) {
showDuplicateIndicators(recyclerView);
}
});
initDuplicateIndicators(playlistRecyclerView);
}
}

public void initDuplicateIndicators(@NonNull final RecyclerView view) {
showDuplicateIndicators(view);

if (!duplicateIds.isEmpty()) {
final View indicatorExplanation = getView()
.findViewById(R.id.playlist_duplicate);
indicatorExplanation.setVisibility(View.VISIBLE);
}
}

public void showDuplicateIndicators(@NonNull final RecyclerView view) {
if (view.getAdapter() == null) {
return;
}

final int count = view.getAdapter().getItemCount();
for (int i = 0; i < count; i++) {

final RecyclerView.ViewHolder viewHolder = view.findViewHolderForAdapterPosition(i);
if (viewHolder != null) {
if (duplicateIds.contains(view.getAdapter().getItemId(i))) {
viewHolder.itemView.setAlpha(GRAYED_OUT_ALPHA);
} else {
viewHolder.itemView.setAlpha(DEFAULT_ALPHA);
}

}
}
}

private void onPlaylistSelected(@NonNull final LocalPlaylistManager manager,
@NonNull final PlaylistMetadataEntry playlist,
@NonNull final PlaylistDuplicatesEntry playlist,
@NonNull final List<StreamEntity> streams) {

final int numOfDuplicates = manager.getPlaylistDuplicateCount(playlist.uid,
streams.get(0).getUrl()).blockingFirst();
String toastText = getString(R.string.playlist_add_stream_success);

if (numOfDuplicates > 0) {
toastText = getString(R.string.playlist_add_stream_success_duplicate, numOfDuplicates);
final String toastText;
if (playlist.timesStreamIsContained > 0) {
toastText = getString(R.string.playlist_add_stream_success_duplicate,
playlist.timesStreamIsContained);
} else {
toastText = getString(R.string.playlist_add_stream_success);
}

final Toast successToast = Toast.makeText(getContext(), toastText, Toast.LENGTH_SHORT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import android.view.ViewGroup;

import org.schabi.newpipe.database.LocalItem;
import org.schabi.newpipe.database.playlist.PlaylistDuplicatesEntry;
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
import org.schabi.newpipe.local.LocalItemBuilder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
Expand All @@ -13,6 +14,9 @@
import java.time.format.DateTimeFormatter;

public class LocalPlaylistItemHolder extends PlaylistItemHolder {

private static final float GRAYED_OUT_ALPHA = 0.6f;

public LocalPlaylistItemHolder(final LocalItemBuilder infoItemBuilder, final ViewGroup parent) {
super(infoItemBuilder, parent);
}
Expand All @@ -38,6 +42,13 @@ public void updateFromItem(final LocalItem localItem,

PicassoHelper.loadPlaylistThumbnail(item.thumbnailUrl).into(itemThumbnailView);

if (item instanceof PlaylistDuplicatesEntry
&& ((PlaylistDuplicatesEntry) item).timesStreamIsContained > 0) {
itemView.setAlpha(GRAYED_OUT_ALPHA);
} else {
itemView.setAlpha(1.0f);
}

super.updateFromItem(localItem, historyRecordManager, dateTimeFormatter);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import androidx.annotation.Nullable;

import org.schabi.newpipe.database.AppDatabase;
import org.schabi.newpipe.database.playlist.PlaylistDuplicatesEntry;
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
import org.schabi.newpipe.database.playlist.PlaylistStreamEntry;
import org.schabi.newpipe.database.playlist.dao.PlaylistDAO;
Expand Down Expand Up @@ -86,17 +87,20 @@ public Flowable<List<PlaylistMetadataEntry>> getPlaylists() {
return playlistStreamTable.getPlaylistMetadata().subscribeOn(Schedulers.io());
}

public Flowable<List<PlaylistStreamEntry>> getPlaylistStreams(final long playlistId) {
return playlistStreamTable.getOrderedStreamsOf(playlistId).subscribeOn(Schedulers.io());
}

public Flowable<Integer> getPlaylistDuplicateCount(final long playlistId,
final String streamURL) {
return playlistStreamTable.getDuplicateCount(playlistId, streamURL);
/**
* Get playlists with attached information about how many times the provided stream is already
* contained in each playlist.
*
* @param streamUrl the stream url for which to check for duplicates
* @return a list of {@link PlaylistDuplicatesEntry}
*/
public Flowable<List<PlaylistDuplicatesEntry>> getPlaylistDuplicates(final String streamUrl) {
return playlistStreamTable.getPlaylistDuplicatesMetadata(streamUrl)
.subscribeOn(Schedulers.io());
}

public Flowable<List<Long>> getDuplicatePlaylists(final String streamURL) {
return playlistStreamTable.getDuplicatePlaylists(streamURL);
public Flowable<List<PlaylistStreamEntry>> getPlaylistStreams(final long playlistId) {
return playlistStreamTable.getOrderedStreamsOf(playlistId).subscribeOn(Schedulers.io());
}

public Single<Integer> deletePlaylist(final long playlistId) {
Expand Down

0 comments on commit 61a9c79

Please sign in to comment.