mirror of https://github.com/koreader/koreader
Book information: refactored and additional features
- Factored out duplicate code from filemanager.lua and filemanagerhistory.lua to new filemanagerbookinfo.lua (and other common code to filemanagerutil.lua). - Uses sidecar files' new doc_props and doc_pages settings, or fallback to old 'stats' settings, or to opening document. - Shows filename, filetype and directory. - Shows description (Hold to see whole truncated text), keywords, and cover image (tap to extract image from document and display it if available). - Book information now available from reader menu, to display info about the currently opened book. - Convert possibly HTML description to plain text via added util.htmlToPlainTextIfHtml() (for simple HTML conversion).pull/3011/head
parent
64f699ba36
commit
17656778b1
@ -0,0 +1,183 @@
|
|||||||
|
--[[--
|
||||||
|
This module provides a way to display book information (filename and book metadata)
|
||||||
|
]]
|
||||||
|
|
||||||
|
local DocSettings = require("docsettings")
|
||||||
|
local DocumentRegistry = require("document/documentregistry")
|
||||||
|
local ImageViewer = require("ui/widget/imageviewer")
|
||||||
|
local InfoMessage = require("ui/widget/infomessage")
|
||||||
|
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||||
|
local KeyValuePage = require("ui/widget/keyvaluepage")
|
||||||
|
local UIManager = require("ui/uimanager")
|
||||||
|
local filemanagerutil = require("apps/filemanager/filemanagerutil")
|
||||||
|
local lfs = require("libs/libkoreader-lfs")
|
||||||
|
local util = require("util")
|
||||||
|
local _ = require("gettext")
|
||||||
|
|
||||||
|
local BookInfo = InputContainer:extend{
|
||||||
|
bookinfo_menu_title = _("Book information"),
|
||||||
|
}
|
||||||
|
|
||||||
|
function BookInfo:init()
|
||||||
|
if self.ui then -- only for Reader menu
|
||||||
|
self.ui.menu:registerToMainMenu(self)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function BookInfo:addToMainMenu(menu_items)
|
||||||
|
menu_items.book_info = {
|
||||||
|
text = self.bookinfo_menu_title,
|
||||||
|
callback = function()
|
||||||
|
-- Get them directly from ReaderUI's doc_settings
|
||||||
|
local doc_props = self.ui.doc_settings:readSetting("doc_props")
|
||||||
|
-- Make a copy, so we don't add "pages" to the original doc_props
|
||||||
|
-- that will be saved at some point by ReaderUI.
|
||||||
|
local book_props = {}
|
||||||
|
for k, v in pairs(doc_props) do
|
||||||
|
book_props[k] = v
|
||||||
|
end
|
||||||
|
book_props.pages = self.ui.doc_settings:readSetting("doc_pages")
|
||||||
|
self:show(self.document.file, book_props)
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function BookInfo:isSupported(file)
|
||||||
|
return lfs.attributes(file, "mode") == "file"
|
||||||
|
end
|
||||||
|
|
||||||
|
function BookInfo:show(file, book_props)
|
||||||
|
local kv_pairs = {}
|
||||||
|
|
||||||
|
local directory, filename = util.splitFilePathName(file)
|
||||||
|
local filename_without_suffix, filetype = util.splitFileNameSuffix(filename) -- luacheck: no unused
|
||||||
|
table.insert(kv_pairs, { _("Filename:"), filename })
|
||||||
|
table.insert(kv_pairs, { _("Format:"), filetype:upper() })
|
||||||
|
table.insert(kv_pairs, { _("Directory:"), filemanagerutil.abbreviate(directory) })
|
||||||
|
table.insert(kv_pairs, "----")
|
||||||
|
|
||||||
|
-- book_props may be provided if caller already has them available
|
||||||
|
-- but it may lack 'pages', that we may get from sidecar file
|
||||||
|
if not book_props or not book_props.pages then
|
||||||
|
local doc_settings = DocSettings:open(file)
|
||||||
|
if doc_settings then
|
||||||
|
if not book_props then
|
||||||
|
-- Files opened after 20170701 have a 'doc_props' setting with
|
||||||
|
-- complete metadata and 'doc_pages' with accurate nb of pages
|
||||||
|
book_props = doc_settings:readSetting('doc_props')
|
||||||
|
end
|
||||||
|
if not book_props then
|
||||||
|
-- File last opened before 20170701 may have a 'stats' setting
|
||||||
|
-- with partial metadata, or empty metadata if statistics plugin
|
||||||
|
-- was not enabled when book was read (we can guess that from
|
||||||
|
-- the fact that stats.page = 0)
|
||||||
|
local stats = doc_settings:readSetting('stats')
|
||||||
|
if stats and stats.pages ~= 0 then
|
||||||
|
-- Let's use them as is (which was what was done before), even if
|
||||||
|
-- incomplete, to avoid expensive book opening
|
||||||
|
book_props = stats
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- Files opened after 20170701 have an accurate 'doc_pages' setting
|
||||||
|
local doc_pages = doc_settings:readSetting('doc_pages')
|
||||||
|
if doc_pages and book_props then
|
||||||
|
book_props.pages = doc_pages
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If still no book_props (book never opened or empty 'stats'), open the
|
||||||
|
-- document to get them
|
||||||
|
if not book_props then
|
||||||
|
local pages
|
||||||
|
local document = DocumentRegistry:openDocument(file)
|
||||||
|
if document.loadDocument then -- needed for crengine
|
||||||
|
document:loadDocument()
|
||||||
|
-- document:render()
|
||||||
|
-- It would be needed to get nb of pages, but the nb obtained
|
||||||
|
-- by simply calling here document:getPageCount() is wrong,
|
||||||
|
-- often 2 to 3 times the nb of pages we see when opening
|
||||||
|
-- the document (may be some other cre settings should be applied
|
||||||
|
-- before calling render() ?)
|
||||||
|
else
|
||||||
|
-- for all others than crengine, we seem to get an accurate nb of pages
|
||||||
|
pages = document:getPageCount()
|
||||||
|
end
|
||||||
|
-- via pcall because picdocument:getProps() always fails (we could
|
||||||
|
-- check document.is_pic, but this way, we'll catch any other error)
|
||||||
|
local ok, props = pcall(document.getProps, document)
|
||||||
|
if ok then
|
||||||
|
book_props = props
|
||||||
|
else
|
||||||
|
book_props = {}
|
||||||
|
end
|
||||||
|
book_props.pages = pages
|
||||||
|
DocumentRegistry:closeDocument(file)
|
||||||
|
end
|
||||||
|
|
||||||
|
local title = book_props.title
|
||||||
|
if title == "" or title == nil then title = _("N/A") end
|
||||||
|
table.insert(kv_pairs, { _("Title:"), title })
|
||||||
|
|
||||||
|
local authors = book_props.authors
|
||||||
|
if authors == "" or authors == nil then authors = _("N/A") end
|
||||||
|
table.insert(kv_pairs, { _("Authors:"), authors })
|
||||||
|
|
||||||
|
local series = book_props.series
|
||||||
|
if series == "" or series == nil then series = _("N/A") end
|
||||||
|
table.insert(kv_pairs, { _("Series:"), series })
|
||||||
|
|
||||||
|
local pages = book_props.pages
|
||||||
|
if pages == "" or pages == nil then pages = _("N/A") end
|
||||||
|
table.insert(kv_pairs, { _("Pages:"), pages })
|
||||||
|
|
||||||
|
local language = book_props.language
|
||||||
|
if language == "" or language == nil then language = _("N/A") end
|
||||||
|
table.insert(kv_pairs, { _("Language:"), language })
|
||||||
|
|
||||||
|
local keywords = book_props.keywords
|
||||||
|
if keywords == "" or keywords == nil then keywords = _("N/A") end
|
||||||
|
table.insert(kv_pairs, { _("Keywords:"), keywords })
|
||||||
|
|
||||||
|
local description = book_props.description
|
||||||
|
if description == "" or description == nil then
|
||||||
|
description = _("N/A")
|
||||||
|
else
|
||||||
|
-- Description may (often in EPUB, but not always) or may not (rarely
|
||||||
|
-- in PDF) be HTML.
|
||||||
|
description = util.htmlToPlainTextIfHtml(book_props.description)
|
||||||
|
end
|
||||||
|
table.insert(kv_pairs, { _("Description:"), description })
|
||||||
|
|
||||||
|
-- Cover image
|
||||||
|
local viewCoverImage = function()
|
||||||
|
local widget
|
||||||
|
local document = DocumentRegistry:openDocument(file)
|
||||||
|
if document then
|
||||||
|
local cover_bb = document:getCoverPageImage()
|
||||||
|
if cover_bb then
|
||||||
|
widget = ImageViewer:new{
|
||||||
|
image = cover_bb,
|
||||||
|
with_title_bar = false,
|
||||||
|
fullscreen = true,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
DocumentRegistry:closeDocument(file)
|
||||||
|
end
|
||||||
|
if not widget then
|
||||||
|
widget = InfoMessage:new{
|
||||||
|
text = _("No cover image available"),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
UIManager:show(widget)
|
||||||
|
end
|
||||||
|
table.insert(kv_pairs, { _("Cover image:"), _("Tap to display"), callback=viewCoverImage })
|
||||||
|
|
||||||
|
local widget = KeyValuePage:new{
|
||||||
|
title = _("Book information"),
|
||||||
|
kv_pairs = kv_pairs,
|
||||||
|
}
|
||||||
|
UIManager:show(widget)
|
||||||
|
end
|
||||||
|
|
||||||
|
return BookInfo
|
@ -0,0 +1,34 @@
|
|||||||
|
--[[--
|
||||||
|
This module contains miscellaneous helper functions for FileManager
|
||||||
|
]]
|
||||||
|
|
||||||
|
local Device = require("device")
|
||||||
|
|
||||||
|
local filemanagerutil = {}
|
||||||
|
|
||||||
|
function filemanagerutil.getDefaultDir()
|
||||||
|
if Device:isKindle() then
|
||||||
|
return "/mnt/us/documents"
|
||||||
|
elseif Device:isKobo() then
|
||||||
|
return "/mnt/onboard"
|
||||||
|
elseif Device:isAndroid() then
|
||||||
|
return "/sdcard"
|
||||||
|
else
|
||||||
|
return "."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function filemanagerutil.abbreviate(path)
|
||||||
|
local home_dir_name = G_reader_settings:readSetting("home_dir_display_name")
|
||||||
|
if home_dir_name ~= nil then
|
||||||
|
local home_dir = G_reader_settings:readSetting("home_dir") or filemanagerutil.getDefaultDir()
|
||||||
|
local len = home_dir:len()
|
||||||
|
local start = path:sub(1, len)
|
||||||
|
if start == home_dir then
|
||||||
|
return home_dir_name .. path:sub(len+1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return path
|
||||||
|
end
|
||||||
|
|
||||||
|
return filemanagerutil
|
Loading…
Reference in New Issue