Skip to content

Conversation

@zgtm
Copy link

@zgtm zgtm commented Aug 20, 2025

What is it?

  • Bugfix (user facing)
  • Feature (user facing)
  • Codebase improvement (dev facing)
  • Meta improvement to the project (dev facing)

Description of the changes in your PR

Adds a sleep timer menu with some predefined values.

The sleep timer pauses the video as soon as the timer runs out.

Closes

Fix #2830

Before/After Screenshots/Screen Record

  • Before:
Screenshot_20250821-001942 Screenshot_20250821-001910
  • After:
Screenshot_20250820-233737 Screenshot_20250820-233813 Screenshot_20250820-233741 Screenshot_20250820-233817 Screenshot_20250820-233753 Screenshot_20250820-233822

Relies on the following changes

  • based on refactor branch, can also port to dev if useful

APK testing

The APK can be found by going to the "Checks" tab below the title. On the left pane, click on "CI", scroll down to "artifacts" and click "app" to download the zip file which contains the debug APK of this PR. You can find more info and a video demonstration on this wiki page.

Will add APK links as soon as a maintainer approves the workflows for this PR.

Due diligence

@github-actions github-actions bot added the size/large PRs with less than 750 changed lines label Aug 20, 2025
@zgtm
Copy link
Author

zgtm commented Aug 20, 2025

I added a new sleep timer after the PR #2892 got closed. This is not based on the other PR, but I tried to address the issues with the other PR.

Some notes / open questions:

  • I added two new icons (ic_alarm and ic_alarm_off). I took the icons from https://github.com/marella/material-design-icons/ . I don't know if that is the right way to add these icons or if it does even matter …
  • I don't know if the icons / menu placement is to everyones liking. I experimented a bit and this seemed to be the best place to me, but I am open to move the icons / menu around
  • I added the StringArray sleep_timer_description and the IntArray sleep_timer_value to settings_keys.xml. This does not seem to be the right place, but I added them there because seek_duration_description and seek_duration_value live there. Should I create a new XML-file (e.g. menu_items.xml)?
  • I don't know where the values in app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java (lines 127-131) come from. Is the value I picked there available?
  • When the timer runs out, the Player calls playerUi.onSleepTimerUpdate in the timer-Thread. The UI then uses binding.sleepTimerTextView.post to switch to the UI thread, to call player.pause. It seems a bit convoluted to me, but it is the cleanest way I could think of. Is there a better way to do this?

@zgtm
Copy link
Author

zgtm commented Aug 21, 2025

Linking to #2830 and #2892 for visibility (both ways).

@TobiGr TobiGr added feature request Issue is related to a feature in the app player Issues related to any player (main, popup and background) labels Aug 28, 2025
Copy link
Contributor

@TobiGr TobiGr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello and thank you for looking into this!

Note: @Stypox is the player master, he knows the player better than me. So take my comments with a grain of salt. You might want to wait with implementing the suggestion before he commented on this.

I added the StringArray sleep_timer_description and the IntArray sleep_timer_value to settings_keys.xml. This does not seem to be the right place, but I added them there because seek_duration_description and seek_duration_value live there. Should I create a new XML-file (e.g. menu_items.xml)?

Sounds like a good idea in general. However, I am not sure if we should have a fixed list of options. I'd prefer to have a fragment which allows me to enter a custom value. That might be done at a later point though.

When the timer runs out, the Player calls playerUi.onSleepTimerUpdate in the timer-Thread. The UI then uses binding.sleepTimerTextView.post to switch to the UI thread, to call player.pause. It seems a bit convoluted to me, but it is the cleanest way I could think of. Is there a better way to do this?

You could use a Disposable like this to run on the correct thread. You might want to check whether .timer().repeat() or .interval() should be used, I guess the latter.

    @NonNull
    private final CompositeDisposable sleepTimerDisposable = new CompositeDisposable();

// [...]

    public void saveAndShutDown() {
        // [...]
        cancelSleepTimer();
        // [...]
    }

    // [...]

    public void setSleepTimer(@Nullable final long sleepMinutes) {
        sleepTimerEnd = java.time.Instant.now().plus(sleepMinutes, ChronoUnit.MINUTES);
        final Player thisPlayer = this;
        final Disposable sleepTimer = Observable.timer(1, TimeUnit.SECONDS)
                .repeat()
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(t -> {
                    if (java.time.Instant.now().isAfter(sleepTimerEnd)) {
                        UIs.call(playerUi -> playerUi.onSleepTimerUpdate(0));
                        thisPlayer.pause();
                        cancelSleepTimer();
                    } else {
                        final long remainingMinutes = java.time.Instant.now()
                                .until(sleepTimerEnd, ChronoUnit.MINUTES);
                        UIs.call(ui -> ui.onSleepTimerUpdate(remainingMinutes + 1));
                    }
                }, throwable -> {
                    // FIXME: Use proper error handling here, e.g. ErrorUtil
                    if (DEBUG) {
                        Log.e(TAG, "Sleep timer error", throwable);
                    }
                });
        sleepTimerDisposable.clear();
        sleepTimerDisposable.add(sleepTimer);
    }

    public void cancelSleepTimer() {
        sleepTimerDisposable.clear(); // or .dispose() please check which one should be used here
    }

On a different note: we also have a background player (see PlayQueueActivity) which would make best use of this feature. The sleep timer for videos is good for TV users but the I assume the sleep timer in the background player would be used by most people. It would be good to also add a way to interact with the timer there.

Comment on lines +832 to +834
<string name="sleep_timer_popup_title">Sleep Timer</string>
<string name="sleep_timer_set">Sleep Timer stellen</string>
<string name="sleep_timer_cancel">Sleep Timer beenden</string>
Copy link
Contributor

@TobiGr TobiGr Aug 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: Check VLC translation. AFAIK they use a different word than "Sleep Timer". We might want to use the same terminology (German and English).

They use "Ruhemodus". Not sure if that is a good translation. But "Sleep Timer" is English. We might want to let the translators figure this out :)

Comment on lines +213 to +218
/**
* @param remainingTime the remaining sleep timer time, set to 0 to pause the player and
* disable the sleep timer
*/
public void onSleepTimerUpdate(final long remainingTime) {
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please ensure that the time unit is mentioned.

Comment on lines +2291 to +2293
final long remainingMinutes = java.time.Instant.now().until(sleepTimerEnd,
ChronoUnit.MINUTES);
UIs.call(playerUi -> playerUi.onSleepTimerUpdate(remainingMinutes + 1));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is remainingMinutes + 1 used because until floors the value? If so, add an explaining comment.

if (remainingTime == 0) {
binding.sleepTimerTextView.post(new Runnable() {
public void run() {
player.pause();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this method is just used for UI updates. The pause() call should happen inside the player.

@TobiGr TobiGr linked an issue Aug 28, 2025 that may be closed by this pull request
@Stypox
Copy link
Member

Stypox commented Aug 28, 2025

Thank you for this PR! I am not sure this is the right time to start adding this feature. NewPlayer is about to be integrated on the refactor branch and that will mean throwing away most of the current player code. So it might be better if you postpone this to after NewPlayer is integrated in NewPipe.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature request Issue is related to a feature in the app player Issues related to any player (main, popup and background) size/large PRs with less than 750 changed lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add sleep timer

3 participants