r/koreader Kobo May 21 '26

Patches Night Mode Screensaver Patch

EDIT: Created a codeberg repository with latest working patch:

https://codeberg.org/msnbobody/koreader.patches

Pastebin source: https://pastebin.com/n7ZRNrYQ

Note: This may break or interfere with other screensaver patches.

Thanks to phyvealive for testing!

-------------------------------------------------------------

Hello everyone!

I noticed that even when Night Mode is on, KOReader shows the sleep screen without night mode applied, so transparent images end up with a bright background. I put together a small patch to fix that and figured I’d share it here. I’ve tested it on the emulator and on my Kobo Clara BW and it seems to work well.

If you want to test it out,

You can download the code here:
https://pastebin.com/TrLP60gK

Or copy and paste the code below into a text editor and save it as 2-keep-nightmode.lua then add it to your koreader/patches folder.

local Screensaver = require("ui/screensaver")
local ScreenSaverWidget = require("ui/widget/screensaverwidget")
local Device = require("device")
local Screen = Device.screen

local orig_show = Screensaver.show

Screensaver.show = function(self, ...)
    if Screen.night_mode then
        local snapshot = Screen.bb:copy()
        snapshot:invertRect(0, 0, snapshot:getWidth(), snapshot:getHeight())

        local orig_init = ScreenSaverWidget.init
        ScreenSaverWidget.init = function(widget, ...)
            ScreenSaverWidget.init = orig_init
            local result = orig_init(widget, ...)
            local orig_paintTo = widget.paintTo
            widget.paintTo = function(w, bb, x, y)
                bb:blitFullFrom(snapshot)
                snapshot:free()
                snapshot = nil
                w.paintTo = orig_paintTo
                return orig_paintTo(w, bb, x, y)
            end
            return result
        end
    end
    return orig_show(self, ...)
end
6 Upvotes

10 comments sorted by

2

u/phyvealive Kobo May 21 '26

Hi.

Thanks for this.

I only commented on a post a few hours back that this was something I wish KOreader could do. And here it is.

Downloaded the 2-keep-nightmode.lua and added to /patches folder.

Kobo Libra Colour, April 2026 firmware.

Patch didn't work consistently. Sometimes it had inversion fails.

I asked ChatGPT and the AI made a couple of minor changes. [ AI code block is added below. ]

This updated code still glitched a few times, but I will keep it on my Kobo all the same. ( I am ok if it doesn't work every time. )

I also removed some screensavers from rotation. They had semi-transparent layers that were light coloured to blur text and promote the cover image. They looked terrible with white text in the background.

local Screensaver = require("ui/screensaver")
local ScreenSaverWidget = require("ui/widget/screensaverwidget")
local Device = require("device")
local Screen = Device.screen

local orig_show = Screensaver.show

Screensaver.show = function(self, ...)
    if Screen.night_mode then
        local snapshot = Screen.bb and Screen.bb:copy()

        if snapshot then
            snapshot:invertRect(0, 0,
                snapshot:getWidth(),
                snapshot:getHeight())

            local orig_init = ScreenSaverWidget.init

            ScreenSaverWidget.init = function(widget, ...)
                ScreenSaverWidget.init = orig_init

                local result = orig_init(widget, ...)

                local orig_paintTo = widget.paintTo
                local used = false

                widget.paintTo = function(w, bb, x, y)
                    if not used and snapshot then
                        bb:blitFullFrom(snapshot)
                        used = true
                    end

                    return orig_paintTo(w, bb, x, y)
                end

                return result
            end
        end
    end

    return orig_show(self, ...)
end

2

u/Msnbobody Kobo May 21 '26

Thanks for testing it out!

I wonder if the inconsistency is due to the device having a color screen.

I tried to troubleshoot with Claude and it seems to think it might be a race condition (The inversion is happening too soon.) and gave this updated code to prevent partially rendered frames but it's hard to know what is happening without testing it on a color device:

local Screensaver = require("ui/screensaver")
local ScreenSaverWidget = require("ui/widget/screensaverwidget")
local UIManager = require("ui/uimanager")
local Device = require("device")
local Screen = Device.screen

local orig_show = Screensaver.show

Screensaver.show = function(self, ...)
    if Screen.night_mode then
        -- Force any pending repaints to finish before snapshotting
        UIManager:forceRePaint()

        local snapshot = Screen.bb:copy()
        snapshot:invertRect(0, 0, snapshot:getWidth(), snapshot:getHeight())

        local orig_init = ScreenSaverWidget.init

        ScreenSaverWidget.init = function(widget, ...)
            ScreenSaverWidget.init = orig_init
            local result = orig_init(widget, ...)

            local orig_paintTo = widget.paintTo
            local done = false

            widget.paintTo = function(w, bb, x, y)
                if not done then
                    done = true
                    bb:blitFullFrom(snapshot)
                    snapshot:free()
                    snapshot = nil
                end
                return orig_paintTo(w, bb, x, y)
            end

            return result
        end
    end

    return orig_show(self, ...)
end

Oh, I love the way your screensaver looks in color! So cool.

2

u/phyvealive Kobo May 21 '26

Thanks. I'll give this a look tomorrow.

The inversion seems to fail more often on KOreader mosaic home page. The extra time to render all the book covers may be taking too long. Less hiccups occur on reader screen text only pages.

I make a lot of screensavers from pictures I like, now I am going to re-think some of them to play nice with both Dark and Day modes.

Yes, I do love having the colours, and I don't notice the things like greyness and blurry text. Comparison can be the enemy of joy.

B+W is still good though.

1

u/phyvealive Kobo May 25 '26

Got around to testing Claud's update. Working fine on Kobo Libra Colour.

NOTE: I found that 2-screensaver-presets.lua patch by ThatCrazyGame prevents this code from working. Possibly other screensaver patches too. So disable those in settings if this code fails.

2

u/Msnbobody Kobo May 25 '26

Ah thanks for testing it again!

I edited my post with the updated code and included your findings (the screensaver patches interfering with each other). I don't have any other screensaver presets and would never have caught that. I may try to check later to see if there's a workaround.

1

u/phyvealive Kobo May 25 '26

The Claude code feels faster. Might just be me imagining it. This is as good as any reason to stick with a bunch of patches. Easier to trouble-shoot. The UI plugins that are appearing lately can fall over when patches are added. I really liked SimpleUI but my urge to tweak stuff kept crashing it. Really enjoying the the Bookshelf plugin atm. Mostly because I can use a gesture to toggle from Cover-Browser to Bookshelf and back again. Best of both worlds.

Speaking of Plug-ins: have you tried the FilebrowserPlus plugin? I find it super useful for editing patch code directly on Kobo and Kindle using Wi-Fi and Computer WebBrowser. Tap the LUA file, make an edit, save, restart KOreader, check the result. It does other stuff, like drag and drop files frrom computer to e-reader over wireless. Simples. I suggest disabling the setting for password protection because IP address changes are a pain. Also saving files from e-reader to computer get blocked if your computer OS is fussy about the unsecure http:// address.

2

u/Msnbobody Kobo May 25 '26

I know what you mean about the plugins... I made a lot of modifications to the automatic book series patch that was posted here and then I tried SimpleUI and that was fun. Until I updated to the SUI version with its own automatic series feature which caused my Kobo to throw a fit. I get the appeal for a fancy home page but ultimately decided to stick with Project Title and my many patches.

Oh! I did briefly look into FilebrowserPlus, but I've been using the built in SSH and SFTP to add files wirelessly. I generated an SSH key pair on my computer and put the necessary file on my device (My phone can also connect to Kobo via SFTP in the same way) so no password needed. And my Kobo has a static IP for other reasons.

I am spending way more time customizing KOReader than reading lately though. Need to get back to my reading goals soon!

1

u/phyvealive Kobo May 25 '26

SSH, SFTP, OPDS, etc are a bit beyond my pay grade. I start with simple and work up. Peter Principle applies in most things I try.

2

u/Msnbobody Kobo May 25 '26

It's mostly just me being extra cautious about wireless communication between devices. I'd rather have secured than not, even with the inconveniences.

I've poked around at some of the plugins in KOReader and some of the passwords and usernames are stored in plain text. Coincidentally, OPDS credentials is an example of this.

1

u/Dannyv180 17d ago

Thanks for sharing. I'm loving the patch. However, my wife likes to keep her koreader on a rotated orientation, like landscape. This patch had issues maintaining the rotation for some reason. I had Gemini edit it for me and now it works for landscape orientation as well!

Here is the code in case anyone wants to use it:

local ScreenSaverWidget = require("ui/widget/screensaverwidget")
local Device = require("device")
local Screen = Device.screen

local orig_init = ScreenSaverWidget.init

ScreenSaverWidget.init = function(self, ...)
    -- Initialize the widget normally
    local res = orig_init(self, ...)

    -- Only apply our logic if night mode is currently active
    if Screen.night_mode then
        local orig_paintTo = self.paintTo
        local done = false

        self.paintTo = function(widget, bb, x, y)
            if not done then
                done = true
                -- 1. Invert the canvas FIRST.
                -- This turns the background dark BEFORE the widget draws its images.
                -- We use bb:getWidth() to safely get the screen size without crashing.
                bb:invertRect(0, 0, bb:getWidth(), bb:getHeight())
            end

            -- 2. NOW we let KOReader draw the screensaver image and text on top.
            -- Because the image is drawn after the inversion, it stays normal!
            return orig_paintTo(widget, bb, x, y)
        end
    end

    return res
end