Save playback state even if stream is finished and add isFinished()

This commit is contained in:
Stypox 2021-03-26 11:27:25 +01:00
parent e846f69e38
commit 360f5ac6f7
No known key found for this signature in database
GPG Key ID: 4BDF1B40A49FDD23
4 changed files with 38 additions and 13 deletions

View File

@ -10,6 +10,7 @@ import io.reactivex.rxjava3.core.Flowable
import org.schabi.newpipe.database.feed.model.FeedEntity import org.schabi.newpipe.database.feed.model.FeedEntity
import org.schabi.newpipe.database.feed.model.FeedLastUpdatedEntity import org.schabi.newpipe.database.feed.model.FeedLastUpdatedEntity
import org.schabi.newpipe.database.stream.StreamWithState import org.schabi.newpipe.database.stream.StreamWithState
import org.schabi.newpipe.database.stream.model.StreamStateEntity
import org.schabi.newpipe.database.subscription.SubscriptionEntity import org.schabi.newpipe.database.subscription.SubscriptionEntity
import java.time.OffsetDateTime import java.time.OffsetDateTime
@ -79,6 +80,9 @@ abstract class FeedDAO {
WHERE ( WHERE (
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'
) )

View File

@ -5,8 +5,6 @@ import androidx.room.ColumnInfo;
import androidx.room.Entity; import androidx.room.Entity;
import androidx.room.ForeignKey; import androidx.room.ForeignKey;
import java.util.concurrent.TimeUnit;
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;
@ -30,11 +28,13 @@ public class StreamStateEntity {
/** /**
* 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.
*/ */
private static final int PLAYBACK_SAVE_THRESHOLD_START_SECONDS = 5; private static final long PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS = 5000; // 5000ms = 5s
/** /**
* Playback state will not be saved, if time left is less than this threshold. * @see #isFinished(long)
* @see org.schabi.newpipe.database.feed.dao.FeedDAO#getLiveOrNotPlayedStreams()
*/ */
private static final int PLAYBACK_SAVE_THRESHOLD_END_SECONDS = 10; public static final long PLAYBACK_FINISHED_END_MILLISECONDS = 60000; // 60000ms = 60s
@ColumnInfo(name = JOIN_STREAM_ID) @ColumnInfo(name = JOIN_STREAM_ID)
private long streamUid; private long streamUid;
@ -63,10 +63,27 @@ public class StreamStateEntity {
this.progressTime = progressTime; this.progressTime = progressTime;
} }
public boolean isValid(final int durationInSeconds) { /**
final int seconds = (int) TimeUnit.MILLISECONDS.toSeconds(progressTime); * The state will be considered valid, and thus be saved, if the progress is more than {@link
return seconds > PLAYBACK_SAVE_THRESHOLD_START_SECONDS * #PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS}.
&& seconds < durationInSeconds - PLAYBACK_SAVE_THRESHOLD_END_SECONDS; * @return whether this stream state entity should be saved or not
*/
public boolean isValid() {
return progressTime > PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS;
}
/**
* The video will be considered as finished, if the time left is less than {@link
* #PLAYBACK_FINISHED_END_MILLISECONDS} and the progress is at least 3/4 of the video length.
* 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
* ones that can be filtered out in the feed fragment.
* @param durationInSeconds the duration of the stream connected with this state, in seconds
* @return whether the stream is finished or not
*/
public boolean isFinished(final long durationInSeconds) {
return progressTime >= durationInSeconds * 1000 - PLAYBACK_FINISHED_END_MILLISECONDS
&& progressTime >= durationInSeconds * 1000 * 3 / 4;
} }
@Override @Override

View File

@ -215,7 +215,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(state -> state.isValid((int) queueItem.getDuration())) .filter(StreamStateEntity::isValid)
.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(state -> state.isValid((int) info.getDuration())) .filter(StreamStateEntity::isValid)
.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, progressTime); final StreamStateEntity state = new StreamStateEntity(streamId, progressTime);
if (state.isValid((int) info.getDuration())) { if (state.isValid()) {
streamStateTable.upsert(state); streamStateTable.upsert(state);
} else { } else {
streamStateTable.deleteState(streamId); streamStateTable.deleteState(streamId);

View File

@ -671,7 +671,11 @@ public final class Player implements
//.doFinally() //.doFinally()
.subscribe( .subscribe(
state -> { state -> {
newQueue.setRecovery(newQueue.getIndex(), state.getProgressTime()); if (!state.isFinished(newQueue.getItem().getDuration())) {
// resume playback only if the stream was not played to the end
newQueue.setRecovery(newQueue.getIndex(),
state.getProgressTime());
}
initPlayback(newQueue, repeatMode, playbackSpeed, playbackPitch, initPlayback(newQueue, repeatMode, playbackSpeed, playbackPitch,
playbackSkipSilence, playWhenReady, isMuted); playbackSkipSilence, playWhenReady, isMuted);
}, },