mirror of
https://github.com/bookorbit/bookorbit.git
synced 2026-11-03 00:11:37 -06:00
80244ea4e2
Squash of feat/koreader-widget-board. KOReader plugin 2.0.0 gets the widget-board dashboard, redesigned book details, menus, lists and dialogs, Decor page and reading companions. Highlights, notes and bookmarks now stay in step across web, Kobo, KOReader and the phones (defects D-00 to D-20, migration 0121), and reading progress and narration hand off cleanly between devices.
95 lines
4.2 KiB
Lua
95 lines
4.2 KiB
Lua
local function read(path)
|
|
local file = assert(io.open(path))
|
|
local source = file:read("*a")
|
|
file:close()
|
|
return source
|
|
end
|
|
|
|
local source = read("koreader-plugin/bookorbit.koplugin/bookorbit_catalog.lua")
|
|
local catalog = { settings = {}, on_device = {}, on_device_files = {} }
|
|
local modes, checks = {}, 0
|
|
local env = setmetatable({
|
|
BookOrbitCatalog = catalog,
|
|
lfs = { attributes = function(path)
|
|
checks = checks + 1
|
|
return modes[path]
|
|
end },
|
|
}, { __index = _G })
|
|
local chunk = assert(loadstring(assert(source:match("(function BookOrbitCatalog:onDeviceBookPath.-)\nfunction BookOrbitCatalog:readStatusLabel"))))
|
|
setfenv(chunk, env)
|
|
chunk()
|
|
|
|
local path = "/path/to/library/book.epub"
|
|
catalog.on_device[1] = path
|
|
catalog.on_device_files[10] = path
|
|
assert(catalog:onDeviceBookPath({ id = 1 }) == nil)
|
|
assert(not catalog:isOnDevice({ id = 1 }))
|
|
assert(catalog:dashboardResumePath({ id = 1 }) == nil)
|
|
assert(catalog:onDeviceFilePath({ id = 10 }) == nil)
|
|
local generation, invalidations, hydrations = 1, 0, 0
|
|
env.BookOrbitStateManager = {
|
|
generation = function() return generation end,
|
|
invalidate = function() generation = generation + 1; invalidations = invalidations + 1 end,
|
|
}
|
|
function catalog:hydrateOnDeviceMaps() hydrations = hydrations + 1 end
|
|
catalog.on_device_generation = generation
|
|
catalog:onDeviceBookPath({ id = 1 })
|
|
catalog:onDeviceBookPath({ id = 1 })
|
|
assert(invalidations == 1 and hydrations == 1, "observing stale paths starts one asynchronous map reconciliation")
|
|
catalog.on_device_generation = nil
|
|
modes[path] = "directory"
|
|
assert(catalog:dashboardResumePath({ id = 1 }) == nil)
|
|
modes[path] = "file"
|
|
assert(catalog:isOnDevice({ id = 1 }))
|
|
assert(catalog:dashboardResumePath({ id = 1 }) == path)
|
|
assert(catalog:onDeviceFilePath({ id = 10 }) == path)
|
|
catalog.settings.catalog_dashboard_tap_resumes = false
|
|
assert(catalog:dashboardResumePath({ id = 1 }) == nil)
|
|
|
|
package.loaded["bookorbit_delivery"] = { key = function() return "account" end }
|
|
catalog.settings.catalog_downloaded_variants = { ["account|10|original"] = { path = path, selection = "current" } }
|
|
local file = { id = 10, selection = "current", downloadVariant = "original" }
|
|
assert(catalog:onDeviceFilePath(file) == path)
|
|
file.selection = "expired"
|
|
assert(catalog:onDeviceFilePath(file) == nil)
|
|
file.selection = "current"
|
|
modes[path] = nil
|
|
assert(catalog:onDeviceFilePath(file) == nil)
|
|
|
|
local detail_source = read("koreader-plugin/bookorbit.koplugin/bookorbit_catalog_detail.lua")
|
|
env.CatalogDetail = catalog
|
|
local detail_chunk = assert(loadstring(assert(detail_source:match("(function CatalogDetail:detailReadPath.-)\nfunction CatalogDetail:detailCache"))))
|
|
setfenv(detail_chunk, env)
|
|
detail_chunk()
|
|
function catalog:supportedFiles(detail) return detail.files or {} end
|
|
assert(catalog:detailReadPath({ id = 1 }) == nil, "cached book fallback cannot resume a missing file")
|
|
modes[path] = "file"
|
|
assert(catalog:detailReadPath({ id = 1 }) == path, "legacy matching paths still work when present")
|
|
|
|
env.ON_DEVICE_MAX_IDS = 200
|
|
env._ = function(text) return text end
|
|
env.UIManager = { show = function() end }
|
|
env.InfoMessage = { new = function(_, value) return value end }
|
|
env.Toast = { show = function() end }
|
|
local device_chunk = assert(loadstring(assert(source:match("(function BookOrbitCatalog:loadOnDevice.-)\nfunction BookOrbitCatalog:collectNotOnDeviceIds"))))
|
|
setfenv(device_chunk, env)
|
|
device_chunk()
|
|
function catalog:refreshOnDevice() end
|
|
local request
|
|
function catalog:loadBooks(params) request = params end
|
|
for id = 1, 300 do catalog.on_device[id] = path end
|
|
catalog.on_device[1] = "/path/to/library/missing.epub"
|
|
catalog.on_device[2] = "/path/to/library/directory.epub"
|
|
modes[catalog.on_device[2]] = "directory"
|
|
checks = 0
|
|
catalog:loadOnDevice()
|
|
assert(checks == 200, "availability checks remain bounded by the server ID-filter cap")
|
|
assert(request.ids:match("^3,4,") and request.ids:match(",200$"), "stale paths are excluded without widening the bounded scope")
|
|
local empty_notice = false
|
|
env.Toast.show = function() empty_notice = true end
|
|
modes[path], request = nil, nil
|
|
catalog:loadOnDevice()
|
|
assert(request == nil and empty_notice, "all missing files show an empty-device notice instead of requesting the entire library")
|
|
|
|
print("bookorbit_missing_file_test.lua: ok")
|