Skip to content

Commit

Permalink
Save playback state even if stream is finished and add isFinished()
Browse files Browse the repository at this point in the history
  • Loading branch information
Stypox committed Jun 9, 2021
1 parent e846f69 commit 360f5ac
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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.FeedLastUpdatedEntity
import org.schabi.newpipe.database.stream.StreamWithState
import org.schabi.newpipe.database.stream.model.StreamStateEntity
import org.schabi.newpipe.database.subscription.SubscriptionEntity
import java.time.OffsetDateTime

Expand Down Expand Up @@ -79,6 +80,9 @@ abstract class FeedDAO {
WHERE (
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 = 'AUDIO_LIVE_STREAM'
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
import androidx.room.Entity;
import androidx.room.ForeignKey;

import java.util.concurrent.TimeUnit;

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.STREAM_STATE_TABLE;
Expand All @@ -30,11 +28,13 @@ public class StreamStateEntity {
/**
* 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)
private long streamUid;
Expand Down Expand Up @@ -63,10 +63,27 @@ public void setProgressTime(final long progressTime) {
this.progressTime = progressTime;
}

public boolean isValid(final int durationInSeconds) {
final int seconds = (int) TimeUnit.MILLISECONDS.toSeconds(progressTime);
return seconds > PLAYBACK_SAVE_THRESHOLD_START_SECONDS
&& seconds < durationInSeconds - PLAYBACK_SAVE_THRESHOLD_END_SECONDS;
/**
* The state will be considered valid, and thus be saved, if the progress is more than {@link
* #PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS}.
* @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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ public Maybe<StreamStateEntity> loadStreamState(final PlayQueueItem queueItem) {
.flatMapPublisher(streamStateTable::getState)
.firstElement()
.flatMap(list -> list.isEmpty() ? Maybe.empty() : Maybe.just(list.get(0)))
.filter(state -> state.isValid((int) queueItem.getDuration()))
.filter(StreamStateEntity::isValid)
.subscribeOn(Schedulers.io());
}

Expand All @@ -224,15 +224,15 @@ public Maybe<StreamStateEntity> loadStreamState(final StreamInfo info) {
.flatMapPublisher(streamStateTable::getState)
.firstElement()
.flatMap(list -> list.isEmpty() ? Maybe.empty() : Maybe.just(list.get(0)))
.filter(state -> state.isValid((int) info.getDuration()))
.filter(StreamStateEntity::isValid)
.subscribeOn(Schedulers.io());
}

public Completable saveStreamState(@NonNull final StreamInfo info, final long progressTime) {
return Completable.fromAction(() -> database.runInTransaction(() -> {
final long streamId = streamTable.upsert(new StreamEntity(info));
final StreamStateEntity state = new StreamStateEntity(streamId, progressTime);
if (state.isValid((int) info.getDuration())) {
if (state.isValid()) {
streamStateTable.upsert(state);
} else {
streamStateTable.deleteState(streamId);
Expand Down
6 changes: 5 additions & 1 deletion app/src/main/java/org/schabi/newpipe/player/Player.java
Original file line number Diff line number Diff line change
Expand Up @@ -671,7 +671,11 @@ && isPlaybackResumeEnabled(this)
//.doFinally()
.subscribe(
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,
playbackSkipSilence, playWhenReady, isMuted);
},
Expand Down

0 comments on commit 360f5ac

Please sign in to comment.