2018-04-12 23:46:03 +02:00
|
|
|
package org.schabi.newpipe.local.playlist;
|
2018-01-15 21:30:52 +01:00
|
|
|
|
2019-10-04 14:59:08 +02:00
|
|
|
import androidx.annotation.Nullable;
|
2018-01-26 07:24:59 +01:00
|
|
|
|
2018-01-15 21:30:52 +01:00
|
|
|
import org.schabi.newpipe.database.AppDatabase;
|
2023-01-14 18:00:40 +01:00
|
|
|
import org.schabi.newpipe.database.playlist.PlaylistDuplicatesEntry;
|
2018-01-15 21:30:52 +01:00
|
|
|
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
|
2018-01-28 07:14:38 +01:00
|
|
|
import org.schabi.newpipe.database.playlist.PlaylistStreamEntry;
|
2018-01-15 21:30:52 +01:00
|
|
|
import org.schabi.newpipe.database.playlist.dao.PlaylistDAO;
|
|
|
|
import org.schabi.newpipe.database.playlist.dao.PlaylistStreamDAO;
|
|
|
|
import org.schabi.newpipe.database.playlist.model.PlaylistEntity;
|
|
|
|
import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity;
|
|
|
|
import org.schabi.newpipe.database.stream.dao.StreamDAO;
|
|
|
|
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
|
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.List;
|
|
|
|
|
2020-10-31 21:55:45 +01:00
|
|
|
import io.reactivex.rxjava3.core.Completable;
|
|
|
|
import io.reactivex.rxjava3.core.Flowable;
|
|
|
|
import io.reactivex.rxjava3.core.Maybe;
|
|
|
|
import io.reactivex.rxjava3.core.Single;
|
|
|
|
import io.reactivex.rxjava3.schedulers.Schedulers;
|
2018-01-15 21:30:52 +01:00
|
|
|
|
|
|
|
public class LocalPlaylistManager {
|
2023-02-09 23:17:36 +01:00
|
|
|
private static final long THUMBNAIL_ID_LEAVE_UNCHANGED = -2;
|
|
|
|
|
2018-01-15 21:30:52 +01:00
|
|
|
private final AppDatabase database;
|
|
|
|
private final StreamDAO streamTable;
|
|
|
|
private final PlaylistDAO playlistTable;
|
|
|
|
private final PlaylistStreamDAO playlistStreamTable;
|
|
|
|
|
|
|
|
public LocalPlaylistManager(final AppDatabase db) {
|
|
|
|
database = db;
|
|
|
|
streamTable = db.streamDAO();
|
|
|
|
playlistTable = db.playlistDAO();
|
|
|
|
playlistStreamTable = db.playlistStreamDAO();
|
|
|
|
}
|
|
|
|
|
|
|
|
public Maybe<List<Long>> createPlaylist(final String name, final List<StreamEntity> streams) {
|
2018-01-22 04:32:49 +01:00
|
|
|
// Disallow creation of empty playlists
|
2020-03-31 19:20:15 +02:00
|
|
|
if (streams.isEmpty()) {
|
|
|
|
return Maybe.empty();
|
|
|
|
}
|
2018-01-15 21:30:52 +01:00
|
|
|
final StreamEntity defaultStream = streams.get(0);
|
2018-01-22 04:32:49 +01:00
|
|
|
final PlaylistEntity newPlaylist =
|
2023-02-05 20:32:34 +01:00
|
|
|
new PlaylistEntity(name, false, defaultStream.getUid());
|
2018-01-15 21:30:52 +01:00
|
|
|
|
2023-02-05 20:32:34 +01:00
|
|
|
return Maybe.fromCallable(() -> database.runInTransaction(() -> {
|
|
|
|
final List<Long> streamIds = streamTable.upsertAll(streams);
|
|
|
|
newPlaylist.setThumbnailStreamId(streamIds.get(0));
|
|
|
|
|
|
|
|
return insertJoinEntities(playlistTable.insert(newPlaylist),
|
|
|
|
streamIds, 0);
|
|
|
|
}
|
|
|
|
)).subscribeOn(Schedulers.io());
|
2018-01-22 04:32:49 +01:00
|
|
|
}
|
2018-01-15 21:30:52 +01:00
|
|
|
|
2018-01-22 04:32:49 +01:00
|
|
|
public Maybe<List<Long>> appendToPlaylist(final long playlistId,
|
|
|
|
final List<StreamEntity> streams) {
|
|
|
|
return playlistStreamTable.getMaximumIndexOf(playlistId)
|
|
|
|
.firstElement()
|
2023-02-05 20:32:34 +01:00
|
|
|
.map(maxJoinIndex -> database.runInTransaction(() -> {
|
|
|
|
final List<Long> streamIds = streamTable.upsertAll(streams);
|
|
|
|
return insertJoinEntities(playlistId, streamIds, maxJoinIndex + 1);
|
|
|
|
}
|
|
|
|
)).subscribeOn(Schedulers.io());
|
2018-01-15 21:30:52 +01:00
|
|
|
}
|
|
|
|
|
2023-02-05 20:32:34 +01:00
|
|
|
private List<Long> insertJoinEntities(final long playlistId, final List<Long> streamIds,
|
|
|
|
final int indexOffset) {
|
|
|
|
|
|
|
|
final List<PlaylistStreamEntity> joinEntities = new ArrayList<>(streamIds.size());
|
2018-01-15 21:30:52 +01:00
|
|
|
|
2018-01-22 23:13:11 +01:00
|
|
|
for (int index = 0; index < streamIds.size(); index++) {
|
|
|
|
joinEntities.add(new PlaylistStreamEntity(playlistId, streamIds.get(index),
|
2018-01-22 04:32:49 +01:00
|
|
|
index + indexOffset));
|
|
|
|
}
|
|
|
|
return playlistStreamTable.insertAll(joinEntities);
|
2018-01-15 21:30:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public Completable updateJoin(final long playlistId, final List<Long> streamIds) {
|
2020-08-16 10:24:58 +02:00
|
|
|
final List<PlaylistStreamEntity> joinEntities = new ArrayList<>(streamIds.size());
|
2018-01-15 21:30:52 +01:00
|
|
|
for (int i = 0; i < streamIds.size(); i++) {
|
|
|
|
joinEntities.add(new PlaylistStreamEntity(playlistId, streamIds.get(i), i));
|
|
|
|
}
|
|
|
|
|
|
|
|
return Completable.fromRunnable(() -> database.runInTransaction(() -> {
|
|
|
|
playlistStreamTable.deleteBatch(playlistId);
|
|
|
|
playlistStreamTable.insertAll(joinEntities);
|
2018-01-22 23:13:11 +01:00
|
|
|
})).subscribeOn(Schedulers.io());
|
2018-01-15 21:30:52 +01:00
|
|
|
}
|
|
|
|
|
2018-01-17 06:12:03 +01:00
|
|
|
public Flowable<List<PlaylistMetadataEntry>> getPlaylists() {
|
|
|
|
return playlistStreamTable.getPlaylistMetadata().subscribeOn(Schedulers.io());
|
|
|
|
}
|
|
|
|
|
2023-01-14 18:00:40 +01:00
|
|
|
/**
|
|
|
|
* 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());
|
2022-12-05 00:15:05 +01:00
|
|
|
}
|
|
|
|
|
2018-01-28 07:14:38 +01:00
|
|
|
public Flowable<List<PlaylistStreamEntry>> getPlaylistStreams(final long playlistId) {
|
2018-01-17 06:12:03 +01:00
|
|
|
return playlistStreamTable.getOrderedStreamsOf(playlistId).subscribeOn(Schedulers.io());
|
|
|
|
}
|
|
|
|
|
|
|
|
public Single<Integer> deletePlaylist(final long playlistId) {
|
|
|
|
return Single.fromCallable(() -> playlistTable.deletePlaylist(playlistId))
|
2018-01-16 20:48:52 +01:00
|
|
|
.subscribeOn(Schedulers.io());
|
2018-01-15 21:30:52 +01:00
|
|
|
}
|
2018-01-26 07:24:59 +01:00
|
|
|
|
|
|
|
public Maybe<Integer> renamePlaylist(final long playlistId, final String name) {
|
2023-02-09 23:17:36 +01:00
|
|
|
return modifyPlaylist(playlistId, name, THUMBNAIL_ID_LEAVE_UNCHANGED, false);
|
2018-01-26 07:24:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public Maybe<Integer> changePlaylistThumbnail(final long playlistId,
|
2023-02-05 20:32:34 +01:00
|
|
|
final long thumbnailStreamId,
|
2022-12-07 02:32:53 +01:00
|
|
|
final boolean isPermanent) {
|
2023-02-05 20:32:34 +01:00
|
|
|
return modifyPlaylist(playlistId, null, thumbnailStreamId, isPermanent);
|
2018-01-26 07:24:59 +01:00
|
|
|
}
|
|
|
|
|
2023-02-05 20:32:34 +01:00
|
|
|
public long getPlaylistThumbnailStreamId(final long playlistId) {
|
|
|
|
return playlistTable.getPlaylist(playlistId).blockingFirst().get(0).getThumbnailStreamId();
|
2019-12-02 22:20:43 +01:00
|
|
|
}
|
|
|
|
|
2022-12-09 12:01:59 +01:00
|
|
|
public boolean getIsPlaylistThumbnailPermanent(final long playlistId) {
|
|
|
|
return playlistTable.getPlaylist(playlistId).blockingFirst().get(0)
|
|
|
|
.getIsThumbnailPermanent();
|
2022-12-07 02:32:53 +01:00
|
|
|
}
|
|
|
|
|
2023-02-05 20:32:34 +01:00
|
|
|
public long getAutomaticPlaylistThumbnailStreamId(final long playlistId) {
|
2023-02-09 23:17:36 +01:00
|
|
|
final long streamId = playlistStreamTable.getAutomaticThumbnailStreamId(playlistId)
|
2023-02-05 20:32:34 +01:00
|
|
|
.blockingFirst();
|
|
|
|
if (streamId < 0) {
|
2023-02-09 23:17:36 +01:00
|
|
|
return PlaylistEntity.DEFAULT_THUMBNAIL_ID;
|
2023-02-05 20:32:34 +01:00
|
|
|
}
|
|
|
|
return streamId;
|
2022-12-08 23:31:20 +01:00
|
|
|
}
|
|
|
|
|
2018-01-26 07:24:59 +01:00
|
|
|
private Maybe<Integer> modifyPlaylist(final long playlistId,
|
|
|
|
@Nullable final String name,
|
2023-02-05 20:32:34 +01:00
|
|
|
final long thumbnailStreamId,
|
2022-12-07 02:32:53 +01:00
|
|
|
final boolean isPermanent) {
|
2018-01-26 07:24:59 +01:00
|
|
|
return playlistTable.getPlaylist(playlistId)
|
|
|
|
.firstElement()
|
2022-12-08 23:31:20 +01:00
|
|
|
.filter(playlistEntities -> !playlistEntities.isEmpty())
|
2018-01-26 07:24:59 +01:00
|
|
|
.map(playlistEntities -> {
|
2020-08-16 10:24:58 +02:00
|
|
|
final PlaylistEntity playlist = playlistEntities.get(0);
|
2020-03-31 19:20:15 +02:00
|
|
|
if (name != null) {
|
|
|
|
playlist.setName(name);
|
|
|
|
}
|
2023-02-09 23:17:36 +01:00
|
|
|
if (thumbnailStreamId != THUMBNAIL_ID_LEAVE_UNCHANGED) {
|
2023-02-05 20:32:34 +01:00
|
|
|
playlist.setThumbnailStreamId(thumbnailStreamId);
|
2022-12-09 12:01:59 +01:00
|
|
|
playlist.setIsThumbnailPermanent(isPermanent);
|
2020-03-31 19:20:15 +02:00
|
|
|
}
|
2018-01-26 07:24:59 +01:00
|
|
|
return playlistTable.update(playlist);
|
|
|
|
}).subscribeOn(Schedulers.io());
|
|
|
|
}
|
|
|
|
|
2020-09-29 00:32:24 +02:00
|
|
|
public Maybe<Boolean> hasPlaylists() {
|
|
|
|
return playlistTable.getCount()
|
|
|
|
.firstElement()
|
|
|
|
.map(count -> count > 0)
|
|
|
|
.subscribeOn(Schedulers.io());
|
|
|
|
}
|
2018-01-15 21:30:52 +01:00
|
|
|
}
|