Save playback state even if stream is finished and add isFinished()
This commit is contained in:
parent
e846f69e38
commit
360f5ac6f7
|
@ -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'
|
||||||
)
|
)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue