From 15f5dbef83b84beb5ef3ddd8c21fc6b7f7c615fc Mon Sep 17 00:00:00 2001 From: hius07 <62179190+hius07@users.noreply.github.com> Date: Thu, 19 Dec 2024 09:41:19 +0200 Subject: [PATCH] Reader: inspect zip file content to choose provider (#12902) --- frontend/apps/filemanager/filemanager.lua | 7 +-- .../apps/reader/modules/readertypeset.lua | 14 +++++ frontend/apps/reader/readerui.lua | 56 ++++++++++++++++--- frontend/document/credocument.lua | 29 +--------- frontend/document/document.lua | 15 ----- plugins/docsettingtweak.koplugin/main.lua | 2 +- plugins/profiles.koplugin/main.lua | 3 +- 7 files changed, 68 insertions(+), 58 deletions(-) diff --git a/frontend/apps/filemanager/filemanager.lua b/frontend/apps/filemanager/filemanager.lua index 458d3b793..ed911e290 100644 --- a/frontend/apps/filemanager/filemanager.lua +++ b/frontend/apps/filemanager/filemanager.lua @@ -1549,9 +1549,8 @@ function FileManager:showOpenWithDialog(file) end function FileManager:openFile(file, provider, doc_caller_callback, aux_caller_callback) - if provider == nil then - provider = DocumentRegistry:getProvider(file, true) -- include auxiliary - end + local is_provider_forced = provider ~= nil + provider = provider or DocumentRegistry:getProvider(file, true) -- include auxiliary if provider and provider.order then -- auxiliary if aux_caller_callback then aux_caller_callback() @@ -1566,7 +1565,7 @@ function FileManager:openFile(file, provider, doc_caller_callback, aux_caller_ca doc_caller_callback() end local ReaderUI = require("apps/reader/readerui") - ReaderUI:showReader(file, provider) + ReaderUI:showReader(file, provider, nil, is_provider_forced) end end diff --git a/frontend/apps/reader/modules/readertypeset.lua b/frontend/apps/reader/modules/readertypeset.lua index 66928c93d..cd135d092 100644 --- a/frontend/apps/reader/modules/readertypeset.lua +++ b/frontend/apps/reader/modules/readertypeset.lua @@ -88,6 +88,20 @@ function ReaderTypeset:onReadSettings(config) self.ui.document:setNightmodeImages(self.configurable.nightmode_images == 1) end +function ReaderTypeset:onReaderReady() + -- Initial detection of fb2 may be wrong + local doc_format = self.ui.document:getDocumentFormat() + local is_fb2 = doc_format:sub(1, 11) == "FictionBook" + if self.ui.document.is_fb2 ~= is_fb2 then + self.ui.document.is_fb2 = is_fb2 + self.ui.document.default_css = is_fb2 and "./data/fb2.css" or "./data/epub.css" + if self.ui.document.is_new then + local css = G_reader_settings:readSetting(is_fb2 and "copt_fb2_css" or "copt_css") + self:setStyleSheet(css or self.ui.document.default_css) + end + end +end + function ReaderTypeset:onSaveSettings() self.ui.doc_settings:saveSetting("css", self.css) end diff --git a/frontend/apps/reader/readerui.lua b/frontend/apps/reader/readerui.lua index d0b39ed84..ecaaed3bf 100644 --- a/frontend/apps/reader/readerui.lua +++ b/frontend/apps/reader/readerui.lua @@ -124,6 +124,7 @@ function ReaderUI:init() end self.doc_settings = DocSettings:open(self.document.file) + self.document.is_new = self.doc_settings:readSetting("doc_props") == nil -- Handle local settings migration SettingsMigration:migrateSettings(self.doc_settings) @@ -590,10 +591,9 @@ end --- @note: Will sanely close existing FileManager/ReaderUI instance for you! --- This is the *only* safe way to instantiate a new ReaderUI instance! --- (i.e., don't look at the testsuite, which resorts to all kinds of nasty hacks). -function ReaderUI:showReader(file, provider, seamless) +function ReaderUI:showReader(file, provider, seamless, is_provider_forced) logger.dbg("show reader ui") - file = ffiUtil.realpath(file) if lfs.attributes(file, "mode") ~= "file" then UIManager:show(InfoMessage:new{ text = T(_("File '%1' does not exist."), BD.filepath(filemanagerutil.abbreviate(file))) @@ -601,20 +601,58 @@ function ReaderUI:showReader(file, provider, seamless) return end - if not DocumentRegistry:hasProvider(file) and provider == nil then + if provider == nil and DocumentRegistry:hasProvider(file) then + provider = DocumentRegistry:getProvider(file) + end + if provider ~= nil then + provider = self:extendProvider(file, provider, is_provider_forced) + end + if provider and provider.provider then + -- We can now signal the existing ReaderUI/FileManager instances that it's time to go bye-bye... + UIManager:broadcastEvent(Event:new("ShowingReader")) + self:showReaderCoroutine(file, provider, seamless) + else UIManager:show(InfoMessage:new{ text = T(_("File '%1' is not supported."), BD.filepath(filemanagerutil.abbreviate(file))) }) self:showFileManager(file) - return end +end - -- We can now signal the existing ReaderUI/FileManager instances that it's time to go bye-bye... - UIManager:broadcastEvent(Event:new("ShowingReader")) - provider = provider or DocumentRegistry:getProvider(file) - if provider.provider then - self:showReaderCoroutine(file, provider, seamless) +function ReaderUI:extendProvider(file, provider, is_provider_forced) + -- If file extension is single "zip", check the archive content and choose the appropriate provider, + -- except when the provider choice is forced in the "Open with" dialog. + -- Also pass to crengine is_fb2 property, based on the archive content (single "zip" extension), + -- or on the original file double extension ("fb2.zip" etc). + local _, file_type = filemanagerutil.splitFileNameType(file) -- supports double-extension + if file_type == "zip" then + -- read the content of zip-file and get extension of the 1st file + local std_out = io.popen("unzip -qql \"" .. file .. "\"") + if std_out then + local size, ext + for line in std_out:lines() do + size, ext = string.match(line, "%s+(%d+)%s+.+%.([^.]+)") + if size and ext then break end + end + std_out:close() + if ext ~= nil then + file_type = ext:lower() + end + end + if not is_provider_forced then + local providers = DocumentRegistry:getProviders("dummy." .. file_type) + if providers then + for _, p in ipairs(providers) do + if p.provider.provider == "crengine" or p.provider.provider == "mupdf" then -- only these can unzip + provider = p.provider + break + end + end + end + end end + provider.is_fb2 = file_type:sub(1, 2) == "fb" + return provider end function ReaderUI:showReaderCoroutine(file, provider, seamless) diff --git a/frontend/document/credocument.lua b/frontend/document/credocument.lua index 0219eae29..0dfa63a9b 100644 --- a/frontend/document/credocument.lua +++ b/frontend/document/credocument.lua @@ -67,7 +67,7 @@ local CreDocument = Document:extend{ "Noto Sans", }, - default_css = "./data/cr3.css", + default_css = nil, provider = "crengine", provider_name = "Cool Reader Engine", @@ -77,20 +77,6 @@ local CreDocument = Document:extend{ last_linear_page = nil, } --- NuPogodi, 20.05.12: inspect the zipfile content -function CreDocument:zipContentExt(fname) - local std_out = io.popen("unzip ".."-qql \""..fname.."\"") - if std_out then - local size, ext - for line in std_out:lines() do - size, ext = string.match(line, "%s+(%d+)%s+.+%.([^.]+)") - if size and ext then break end - end - std_out:close() - if ext then return string.lower(ext) end - end -end - function CreDocument:cacheInit() -- remove legacy cr3cache directory if lfs.attributes("./cr3cache", "mode") == "directory" then @@ -170,13 +156,6 @@ function CreDocument:init() self.flows = {} self.page_in_flow = {} - local file_type = string.lower(string.match(self.file, ".+%.([^.]+)") or "") - if file_type == "zip" then - -- NuPogodi, 20.05.12: read the content of zip-file - -- and return extension of the 1st file - file_type = self:zipContentExt(self.file) or "unknown" - end - -- June 2018: epub.css has been cleaned to be more conforming to HTML specs -- and to not include class name based styles (with conditional compatibility -- styles for previously opened documents). It should be usable on all @@ -184,11 +163,7 @@ function CreDocument:init() -- The other css files (htm.css, rtf.css...) have not been updated in the -- same way, and are kept as-is for when a previously opened document -- requests one of them. - self.default_css = "./data/epub.css" - if file_type == "fb2" or file_type == "fb3" then - self.default_css = "./data/fb2.css" - self.is_fb2 = true -- FB2 won't look good with any html-oriented stylesheet - end + self.default_css = self.is_fb2 and "./data/fb2.css" or "./data/epub.css" -- This mode must be the same as the default one set as ReaderView.view_mode self._view_mode = G_defaults:readSetting("DCREREADER_VIEW_MODE") == "scroll" and self.SCROLL_VIEW_MODE or self.PAGE_VIEW_MODE diff --git a/frontend/document/document.lua b/frontend/document/document.lua index f7b1e7e70..1308e0630 100644 --- a/frontend/document/document.lua +++ b/frontend/document/document.lua @@ -67,24 +67,9 @@ function Document:_init() self.info = { -- whether the document is pageable has_pages = false, - -- whether words can be provided - has_words = false, - -- whether hyperlinks can be provided - has_hyperlinks = false, - -- whether (native to format) annotations can be provided - has_annotations = false, - - -- whether pages can be rotated - is_rotatable = false, - number_of_pages = 0, -- if not pageable, length of the document in pixels doc_height = 0, - - -- other metadata - title = "", - author = "", - date = "" } -- Should be updated by a call to Document.updateColorRendering(self) in subclasses diff --git a/plugins/docsettingtweak.koplugin/main.lua b/plugins/docsettingtweak.koplugin/main.lua index a914be08f..bd4159e2a 100644 --- a/plugins/docsettingtweak.koplugin/main.lua +++ b/plugins/docsettingtweak.koplugin/main.lua @@ -91,7 +91,7 @@ end function DocSettingTweak:onDocSettingsLoad(doc_settings, document) -- check that the document has not been opened yet & and that we have defaults to customize - if doc_settings.data.doc_props == nil and directory_defaults.data ~= nil then + if document.is_new and directory_defaults.data ~= nil then local base = G_reader_settings:readSetting("home_dir") or filemanagerutil.getDefaultDir() local directory = FFIUtil.dirname(document.file) -- check if folder matches our defaults to override diff --git a/plugins/profiles.koplugin/main.lua b/plugins/profiles.koplugin/main.lua index 19c2dcdf2..13d0e51a3 100644 --- a/plugins/profiles.koplugin/main.lua +++ b/plugins/profiles.koplugin/main.lua @@ -2,7 +2,6 @@ local ConfirmBox = require("ui/widget/confirmbox") local DataStorage = require("datastorage") local Device = require("device") local Dispatcher = require("dispatcher") -local DocSettings = require("docsettings") local InfoMessage = require("ui/widget/infomessage") local InputDialog = require("ui/widget/inputdialog") local LuaSettings = require("luasettings") @@ -964,7 +963,7 @@ function Profiles:executeAutoExecDocConditional(event) for profile_name, conditions in pairs(self.autoexec[event]) do if self.data[profile_name] then local do_execute - if not conditions.is_new or not DocSettings:hasSidecarFile(self.document.file) then + if not conditions.is_new or self.document.is_new then for condition, trigger in pairs(conditions) do if condition == "orientation" then local mode = Screen:getRotationMode()