Skip to content

Instantly share code, notes, and snippets.

@mallomar
Created September 11, 2025 19:10
Show Gist options
  • Select an option

  • Save mallomar/6a4c017ebbb30f4f5354b9271429f64c to your computer and use it in GitHub Desktop.

Select an option

Save mallomar/6a4c017ebbb30f4f5354b9271429f64c to your computer and use it in GitHub Desktop.
Advise you if file appears to have been modified since binary checksum hash was created, which could affect syncing which depends on binary hash
--[[
KOReader Patch: File Modification Warning
Alerts when book files may have been modified since sync hash was calculated
--]]
local ConfirmBox = require("ui/widget/confirmbox")
local DocSettings = require("docsettings")
local UIManager = require("ui/uimanager")
local InfoMessage = require("ui/widget/infomessage")
local lfs = require("libs/libkoreader-lfs")
-- Function to get file modification time
local function getFileModTime(file_path)
local attr = lfs.attributes(file_path)
return attr and attr.modification or 0
end
-- Function to check if file appears modified since hash calculation
local function checkFileModification(file_path, doc_settings)
if not file_path or not lfs.attributes(file_path) then return end
local stored_hash = doc_settings:readSetting("partial_md5_checksum")
if not stored_hash then return end -- No stored hash, nothing to check
local file_mod_time = getFileModTime(file_path)
local last_check_time = doc_settings:readSetting("file_mod_last_check") or 0
local ignored_time = doc_settings:readSetting("file_mod_ignored") or 0
-- Only notify if file was modified after our last check and user hasn't recently ignored
if file_mod_time <= last_check_time or (os.time() - ignored_time) < 86400 then -- 24 hour grace period
return
end
-- Show warning about potential file modification
local filename = file_path:match("([^/]+)$") or "Unknown"
UIManager:show(ConfirmBox:new{
text = "Sync Warning: File Modified\n\n" ..
"File: " .. filename .. "\n\n" ..
"This file appears to have been modified since the sync hash was calculated. " ..
"This may cause sync failures with external services.\n\n" ..
"Options:\n" ..
"• Keep current setup (sync may fail)\n" ..
"• Wait for fingerprint-based sync solutions\n" ..
"• Manually manage bookmarks if sync is critical\n\n" ..
"Dismiss this warning?",
ok_text = "Dismiss",
cancel_text = "Remind Later",
ok_callback = function()
-- Mark that user dismissed this warning
doc_settings:saveSetting("file_mod_ignored", os.time())
doc_settings:saveSetting("file_mod_last_check", os.time())
doc_settings:flush()
end,
cancel_callback = function()
-- Just update check time, will remind again if file changes more
doc_settings:saveSetting("file_mod_last_check", os.time())
doc_settings:flush()
end,
})
end
-- Function to show current file status
local function showFileStatus()
local ReaderUI = require("apps/reader/readerui")
if not (ReaderUI.instance and ReaderUI.instance.document and ReaderUI.instance.document.file) then
UIManager:show(InfoMessage:new{
text = "No document currently open."
})
return
end
local file_path = ReaderUI.instance.document.file
local doc_settings = DocSettings:open(file_path)
local stored_hash = doc_settings:readSetting("partial_md5_checksum")
local filename = file_path:match("([^/]+)$") or "Unknown"
if not stored_hash then
UIManager:show(InfoMessage:new{
text = "No sync hash found for this book.\n\nHash will be calculated on first sync attempt."
})
return
end
local file_mod_time = getFileModTime(file_path)
local last_check_time = doc_settings:readSetting("file_mod_last_check") or 0
local status_text = "File Sync Status\n\n" ..
"File: " .. filename .. "\n" ..
"Sync Hash: " .. stored_hash:sub(1, 8) .. "...\n\n"
if file_mod_time > last_check_time then
status_text = status_text .. "⚠ File may have been modified since hash was calculated.\n" ..
"Sync with external services may fail.\n\n" ..
"Consider waiting for fingerprint-based sync solutions."
else
status_text = status_text .. "✓ File appears unchanged since last check.\n" ..
"Sync should work normally."
end
UIManager:show(InfoMessage:new{
text = status_text
})
end
-- Create menu item
local function createFileStatusMenuItem()
return {
text = "Check File Sync Status",
callback = function()
showFileStatus()
end,
}
end
-- Add menu items
local function patchMenu(menu, order)
if order and order.more_tools then
table.insert(order.more_tools, "file_sync_status")
menu.menu_items.file_sync_status = createFileStatusMenuItem()
elseif order and order.tools then
table.insert(order.tools, "file_sync_status")
menu.menu_items.file_sync_status = createFileStatusMenuItem()
else
menu.menu_items.file_sync_status = createFileStatusMenuItem()
end
end
-- Hook into ReaderMenu
local ok_reader_menu, ReaderMenu = pcall(require, "apps/reader/modules/readermenu")
if ok_reader_menu then
local orig_ReaderMenu_setUpdateItemTable = ReaderMenu.setUpdateItemTable
ReaderMenu.setUpdateItemTable = function(self)
local ok_order, reader_order = pcall(require, "ui/elements/reader_menu_order")
if ok_order then
patchMenu(self, reader_order)
end
orig_ReaderMenu_setUpdateItemTable(self)
end
end
-- Hook into document opening to check for file modifications
local ReaderUI = require("apps/reader/readerui")
local orig_ReaderUI_showReader = ReaderUI.showReader
ReaderUI.showReader = function(self, ...)
orig_ReaderUI_showReader(self, ...)
-- Schedule file modification check after document is fully loaded
UIManager:scheduleIn(3, function()
if self.document and self.document.file then
local doc_settings = DocSettings:open(self.document.file)
checkFileModification(self.document.file, doc_settings)
end
end)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment