Fix hiding finished streams in groups; new stream state validity condition
Consider stream state valid also if >1/4 of video was watched
This commit is contained in:
parent
0113ad5e14
commit
2142f05a88
|
@ -64,6 +64,12 @@ abstract class FeedDAO {
|
||||||
)
|
)
|
||||||
abstract fun getAllStreamsForGroup(groupId: Long): Flowable<List<StreamWithState>>
|
abstract fun getAllStreamsForGroup(groupId: Long): Flowable<List<StreamWithState>>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see StreamStateEntity.isFinished()
|
||||||
|
* @see StreamStateEntity.PLAYBACK_FINISHED_END_MILLISECONDS
|
||||||
|
* @return all of the non-live, never-played and non-finished streams in the feed
|
||||||
|
* (all of the cited conditions must hold for a stream to be in the returned list)
|
||||||
|
*/
|
||||||
@Query(
|
@Query(
|
||||||
"""
|
"""
|
||||||
SELECT s.*, sst.progress_time
|
SELECT s.*, sst.progress_time
|
||||||
|
@ -93,6 +99,13 @@ abstract class FeedDAO {
|
||||||
)
|
)
|
||||||
abstract fun getLiveOrNotPlayedStreams(): Flowable<List<StreamWithState>>
|
abstract fun getLiveOrNotPlayedStreams(): Flowable<List<StreamWithState>>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see StreamStateEntity.isFinished()
|
||||||
|
* @see StreamStateEntity.PLAYBACK_FINISHED_END_MILLISECONDS
|
||||||
|
* @param groupId the group id to get streams of
|
||||||
|
* @return all of the non-live, never-played and non-finished streams for the given feed group
|
||||||
|
* (all of the cited conditions must hold for a stream to be in the returned list)
|
||||||
|
*/
|
||||||
@Query(
|
@Query(
|
||||||
"""
|
"""
|
||||||
SELECT s.*, sst.progress_time
|
SELECT s.*, sst.progress_time
|
||||||
|
@ -113,6 +126,9 @@ abstract class FeedDAO {
|
||||||
WHERE fgs.group_id = :groupId
|
WHERE fgs.group_id = :groupId
|
||||||
AND (
|
AND (
|
||||||
sh.stream_id IS NULL
|
sh.stream_id IS NULL
|
||||||
|
OR sst.stream_id IS NULL
|
||||||
|
OR sst.progress_time < s.duration * 1000 - ${StreamStateEntity.PLAYBACK_FINISHED_END_MILLISECONDS}
|
||||||
|
OR sst.progress_time < s.duration * 1000 * 3 / 4
|
||||||
OR s.stream_type = 'LIVE_STREAM'
|
OR s.stream_type = 'LIVE_STREAM'
|
||||||
OR s.stream_type = 'AUDIO_LIVE_STREAM'
|
OR s.stream_type = 'AUDIO_LIVE_STREAM'
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,6 +5,8 @@ import androidx.room.ColumnInfo;
|
||||||
import androidx.room.Entity;
|
import androidx.room.Entity;
|
||||||
import androidx.room.ForeignKey;
|
import androidx.room.ForeignKey;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import static androidx.room.ForeignKey.CASCADE;
|
import static androidx.room.ForeignKey.CASCADE;
|
||||||
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.JOIN_STREAM_ID;
|
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.JOIN_STREAM_ID;
|
||||||
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_STATE_TABLE;
|
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_STATE_TABLE;
|
||||||
|
@ -26,15 +28,18 @@ public class StreamStateEntity {
|
||||||
public static final String STREAM_PROGRESS_MILLIS = "progress_time";
|
public static final String STREAM_PROGRESS_MILLIS = "progress_time";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Playback state will not be saved, if playback time is less than this threshold.
|
* Playback state will not be saved, if playback time is less than this threshold (5000ms = 5s).
|
||||||
*/
|
*/
|
||||||
private static final long PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS = 5000; // 5000ms = 5s
|
private static final long PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS = 5000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Stream will be considered finished if the playback time left exceeds this threshold
|
||||||
|
* (60000ms = 60s).
|
||||||
* @see #isFinished(long)
|
* @see #isFinished(long)
|
||||||
* @see org.schabi.newpipe.database.feed.dao.FeedDAO#getLiveOrNotPlayedStreams()
|
* @see org.schabi.newpipe.database.feed.dao.FeedDAO#getLiveOrNotPlayedStreams()
|
||||||
|
* @see org.schabi.newpipe.database.feed.dao.FeedDAO#getLiveOrNotPlayedStreamsForGroup(long)
|
||||||
*/
|
*/
|
||||||
public static final long PLAYBACK_FINISHED_END_MILLISECONDS = 60000; // 60000ms = 60s
|
public static final long PLAYBACK_FINISHED_END_MILLISECONDS = 60000;
|
||||||
|
|
||||||
@ColumnInfo(name = JOIN_STREAM_ID)
|
@ColumnInfo(name = JOIN_STREAM_ID)
|
||||||
private long streamUid;
|
private long streamUid;
|
||||||
|
@ -65,11 +70,13 @@ public class StreamStateEntity {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The state will be considered valid, and thus be saved, if the progress is more than {@link
|
* The state will be considered valid, and thus be saved, if the progress is more than {@link
|
||||||
* #PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS}.
|
* #PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS} or at least 1/4 of the video length.
|
||||||
|
* @param durationInSeconds the duration of the stream connected with this state, in seconds
|
||||||
* @return whether this stream state entity should be saved or not
|
* @return whether this stream state entity should be saved or not
|
||||||
*/
|
*/
|
||||||
public boolean isValid() {
|
public boolean isValid(final long durationInSeconds) {
|
||||||
return progressMillis > PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS;
|
return progressMillis > PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS
|
||||||
|
|| progressMillis > durationInSeconds * 1000 / 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,6 +85,8 @@ public class StreamStateEntity {
|
||||||
* The state will be saved anyway, so that it can be shown under stream info items, but the
|
* The state will be saved anyway, so that it can be shown under stream info items, but the
|
||||||
* player will not resume if a state is considered as finished. Finished streams are also the
|
* player will not resume if a state is considered as finished. Finished streams are also the
|
||||||
* ones that can be filtered out in the feed fragment.
|
* ones that can be filtered out in the feed fragment.
|
||||||
|
* @see org.schabi.newpipe.database.feed.dao.FeedDAO#getLiveOrNotPlayedStreams()
|
||||||
|
* @see org.schabi.newpipe.database.feed.dao.FeedDAO#getLiveOrNotPlayedStreamsForGroup(long)
|
||||||
* @param durationInSeconds the duration of the stream connected with this state, in seconds
|
* @param durationInSeconds the duration of the stream connected with this state, in seconds
|
||||||
* @return whether the stream is finished or not
|
* @return whether the stream is finished or not
|
||||||
*/
|
*/
|
||||||
|
@ -95,4 +104,9 @@ public class StreamStateEntity {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(streamUid, progressMillis);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -211,11 +211,11 @@ public class HistoryRecordManager {
|
||||||
|
|
||||||
public Maybe<StreamStateEntity> loadStreamState(final PlayQueueItem queueItem) {
|
public Maybe<StreamStateEntity> loadStreamState(final PlayQueueItem queueItem) {
|
||||||
return queueItem.getStream()
|
return queueItem.getStream()
|
||||||
.map((info) -> streamTable.upsert(new StreamEntity(info)))
|
.map(info -> streamTable.upsert(new StreamEntity(info)))
|
||||||
.flatMapPublisher(streamStateTable::getState)
|
.flatMapPublisher(streamStateTable::getState)
|
||||||
.firstElement()
|
.firstElement()
|
||||||
.flatMap(list -> list.isEmpty() ? Maybe.empty() : Maybe.just(list.get(0)))
|
.flatMap(list -> list.isEmpty() ? Maybe.empty() : Maybe.just(list.get(0)))
|
||||||
.filter(StreamStateEntity::isValid)
|
.filter(state -> state.isValid(queueItem.getDuration()))
|
||||||
.subscribeOn(Schedulers.io());
|
.subscribeOn(Schedulers.io());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,7 +224,7 @@ public class HistoryRecordManager {
|
||||||
.flatMapPublisher(streamStateTable::getState)
|
.flatMapPublisher(streamStateTable::getState)
|
||||||
.firstElement()
|
.firstElement()
|
||||||
.flatMap(list -> list.isEmpty() ? Maybe.empty() : Maybe.just(list.get(0)))
|
.flatMap(list -> list.isEmpty() ? Maybe.empty() : Maybe.just(list.get(0)))
|
||||||
.filter(StreamStateEntity::isValid)
|
.filter(state -> state.isValid(info.getDuration()))
|
||||||
.subscribeOn(Schedulers.io());
|
.subscribeOn(Schedulers.io());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,7 +232,7 @@ public class HistoryRecordManager {
|
||||||
return Completable.fromAction(() -> database.runInTransaction(() -> {
|
return Completable.fromAction(() -> database.runInTransaction(() -> {
|
||||||
final long streamId = streamTable.upsert(new StreamEntity(info));
|
final long streamId = streamTable.upsert(new StreamEntity(info));
|
||||||
final StreamStateEntity state = new StreamStateEntity(streamId, progressMillis);
|
final StreamStateEntity state = new StreamStateEntity(streamId, progressMillis);
|
||||||
if (state.isValid()) {
|
if (state.isValid(info.getDuration())) {
|
||||||
streamStateTable.upsert(state);
|
streamStateTable.upsert(state);
|
||||||
}
|
}
|
||||||
})).subscribeOn(Schedulers.io());
|
})).subscribeOn(Schedulers.io());
|
||||||
|
|
Loading…
Reference in New Issue