diff --git a/frontend/apps/reader/modules/readerlink.lua b/frontend/apps/reader/modules/readerlink.lua index 157c095c7..81142ee40 100644 --- a/frontend/apps/reader/modules/readerlink.lua +++ b/frontend/apps/reader/modules/readerlink.lua @@ -666,6 +666,11 @@ function ReaderLink:onGotoLink(link, neglect_current_location, allow_footnote_po return true end + -- Check for local WikiReader links + if link_url:find("^kolocalwiki://") ~= nil then + self.ui:handleEvent(Event:new("OpenLocalWikiPage", link_url)) -- Parsing of the URL handled in the plugin + return true + end -- Not supported UIManager:show(InfoMessage:new{ text = T(_("Invalid or external link:\n%1"), BD.url(link_url)), diff --git a/plugins/wikireader.koplugin/main.lua b/plugins/wikireader.koplugin/main.lua index 1310937ab..e83e8803f 100644 --- a/plugins/wikireader.koplugin/main.lua +++ b/plugins/wikireader.koplugin/main.lua @@ -10,6 +10,7 @@ local UIManager = require("ui/uimanager") local InfoMessage = require("ui/widget/infomessage") local PathChooser = require("ui/widget/pathchooser") local Device = require("device") +local escape = require("turbo.escape") local util = require("util") local _ = require("gettext") @@ -29,24 +30,38 @@ local function file_exists(name) if f~=nil then io.close(f) return true else return false end end -function WikiReader:startInstance() - -- Maybe a bit ugly with this global variable, but it works - if WikiReaderInstance == nil then - -- Add instance of this to self.ui - log("START: starting with binding to ui") - WikiReaderInstance = WikiReader:start() - else - local w = WikiReaderInstance.widget - w:gotoTitle(w.history[#w.history]) +function WikiReader:onOpenLocalWikiPage(url) + log("Caught onLookupWikipedia", url) + local poundLocation = url:find("#") + if url:find("^kolocalwiki://") == nil or poundLocation == nil then UIManager:show(InfoMessage:new{ - text = _("Re-opened WikiReader"), - timeout = 5 + text = _("Got passed an invalid WikiReader URL"), + timeout = 2 }) + return end + local encoded_db_path = url:sub(15, poundLocation - 1) + local db_path = escape.base64_decode(encoded_db_path) + local title = url:sub(poundLocation + 1) + local widget = self:startWidget(db_path) + widget:gotoTitle(title) end function WikiReader:start() - local wikireader_db_path = G_reader_settings:readSetting("wikireader_db_path") + self:startWidget(nil, "Ebook") +end + +function WikiReader:startWidget(db_path, title) + log("Start widget with:", db_path, title, G_reader_settings:readSetting("wikireader_db_path")) + + if self.widget ~= nil then + if title ~= nil then + self.widget:gotoTitle(title) + end + return self.widget + end + -- Init a new widget because we lost a reference to the old one + local wikireader_db_path = db_path or G_reader_settings:readSetting("wikireader_db_path") if wikireader_db_path == nil then UIManager:show(InfoMessage:new{ text = _("Could not find database, set it in the plugin menu first"), @@ -61,8 +76,9 @@ function WikiReader:start() log("Got wikireader_db_path: ", wikireader_db_path) local db_file = wikireader_db_path if file_exists(db_file) then - self.widget = WikiReaderWidget:new(db_file, "EPUB") - return self + local widget = WikiReaderWidget:new(db_file, title) + self.widget = widget + return widget else UIManager:show(InfoMessage:new{ text = _("Did not find database at: ") .. db_file, @@ -73,26 +89,22 @@ function WikiReader:start() end function WikiReader:onSearchRequest () - local delay = 0.1 - if WikiReaderInstance == nil then - WikiReader:startInstance() - delay = 1 - end - - UIManager:scheduleIn(delay, function() - if WikiReaderInstance ~= nil then - WikiReaderInstance.widget:showSearchBox() - end - end) + local widget = self:startWidget() + widget:showSearchBox() end function WikiReader:showDBfilePicker() local home_dir = G_reader_settings:readSetting("home_dir") or Device.home_dir or "/" - + local path_chooser = PathChooser:new{ title = _("Find and long press zim_articles.db"), select_directory = false, select_file = true, + file_filter = function(filename) + local suffix = util.getFileNameSuffix(filename) + return suffix == 'db' + end, + path = home_dir, onConfirm = function(path) G_reader_settings:saveSetting("wikireader_db_path", path) @@ -110,35 +122,26 @@ function WikiReader:getFavoritesTable () text = _("Add current page to favorites"), separator = true, callback = function(touchmenu_instance) - if WikiReaderInstance == nil then + if self.widget == nil then UIManager:show(InfoMessage:new{ text = "WikiReader is not openend", timeout = 2 }) else - WikiReaderInstance.widget:addCurrentTitleToFavorites() + self.widget:addCurrentTitleToFavorites() end - end + end }} local favorite_titles = G_reader_settings:readSetting("wikireader-favorites") or {} - for i = 1, #favorite_titles do + for i = 1, #favorite_titles do local title = favorite_titles[i] table.insert(favorites_table, { text = title, - callback = function() - local delay = 0.1 - if WikiReaderInstance == nil then - WikiReader:startInstance() - delay = 1 - end - - UIManager:scheduleIn(delay, function() - if WikiReaderInstance ~= nil then - WikiReaderInstance.widget:gotoTitle(title) - end - end) + callback = function() + local widget = self:startWidget() + widget:gotoTitle(title) end }) end @@ -150,21 +153,21 @@ end function WikiReader:addToMainMenu(menu_items) log("WIKI: Adding to menu: " .. _("WikiReader")) - + menu_items.wikireader = { text = _("WikiReader (Unstable)"), sorting_hint = "tools", { text = _("Open WikiReader"), - callback = WikiReader.startInstance, + callback = function () WikiReader:start() end, }, { text = _("Search WikiReader"), - callback = WikiReader.onSearchRequest, + callback = function () WikiReader:onSearchRequest() end, }, { text = _("Select database"), - callback = WikiReader.showDBfilePicker, + callback = function () WikiReader:showDBfilePicker() end, }, { text = _("Favorites"), @@ -182,6 +185,6 @@ function WikiReader:addToMainMenu(menu_items) } } end - + return WikiReader diff --git a/plugins/wikireader.koplugin/reader-widget.lua b/plugins/wikireader.koplugin/reader-widget.lua index 5255bece8..9bcf6fe45 100644 --- a/plugins/wikireader.koplugin/reader-widget.lua +++ b/plugins/wikireader.koplugin/reader-widget.lua @@ -1,24 +1,20 @@ -local Geom = require("ui/geometry") -local ConfirmBox = require("ui/widget/confirmbox") local logger = require("logger") local log = logger.dbg -local Device = require("device") local UIManager = require("ui/uimanager") local SQ3 = require("lua-ljsqlite3/init") local InfoMessage = require("ui/widget/infomessage") local InputDialog = require("ui/widget/inputdialog") -local TouchMenu = require("ui/widget/touchmenu") local Screen = require("device").screen local Menu = require("ui/widget/menu") local zstd = require("ffi/zstd") local ffi = require("ffi") +local escape = require("turbo.escape") local DataStorage = require("datastorage") local ReaderUI = require("apps/reader/readerui") local FileConverter = require("apps/filemanager/filemanagerconverter") -local ReaderLink = require("apps/reader/modules/readerlink") local ReadHistory = require("readhistory") local BaseUtil = require("ffi/util") local _ = require("gettext") @@ -27,10 +23,15 @@ local WikiReaderWidget = { name = "wikireader-widget", db_conn = nil, input_dialog = nil, - css = '', - history = {}, + db_path = nil, + history = {} } +local function replace(haystack, needle, replacement) + local escapedReplacement = replacement:gsub("[%(%)%.%%%+%-%*%?%[%]%^%$]", function(c) return "%" .. c end) + return haystack:gsub(needle, escapedReplacement) +end + function WikiReaderWidget:addCurrentTitleToFavorites() local currentTitle = self.history[#self.history] local favorites = G_reader_settings:readSetting("wikireader-favorites") or {} @@ -41,55 +42,34 @@ function WikiReaderWidget:addCurrentTitleToFavorites() log("saved favorites:", newFavorites) end -function WikiReaderWidget:overrideLinkHandler() - if ReaderUI.instance == nil then - log("Got nil readerUI instance, canceling") - return - end - ReaderUI.postInitCallback = {} -- To make ReaderLink shut up - local ui_link_module_instance = ReaderLink:new{ - dialog = ReaderUI.instance.dialog, - view = ReaderUI.instance.view, - ui = ReaderUI.instance, - document = ReaderUI.instance.document, - } - - ReaderLink.original_onGotoLink = ReaderLink.onGotoLink - - function ReaderLink:onGotoLink (link, neglect_current_location, allow_footnote_popup) - local link_uri = link["xpointer"] - if (link_uri:find("^WikiReader:") ~= nil) then - -- This is a wiki reader URL, handle it here - local article_title = link_uri:sub(12) -- Remove prefix - WikiReaderWidget:gotoTitle(article_title) - return true -- Don't propagate - else - log("Passing forward to original handler") - self:original_onGotoLink(link, neglect_current_location, allow_footnote_popup) - end - end - - ReaderUI:registerModule("link", ui_link_module_instance) - ReaderUI.postInitCallback = nil -end - function WikiReaderWidget:new(db_file, first_page_title) UIManager:show(InfoMessage:new{ text = _("Opening db: ") .. db_file, - timeout = 2 + timeout = 2 }) - - self.db_conn = SQ3.open(db_file) - -- Load css - self:loadCSS() + self.db_path = db_file -- First load the first page - self:gotoTitle(first_page_title) - UIManager:scheduleIn(0.1, function() - self:overrideLinkHandler() - end) + if first_page_title ~= nil then + self:gotoTitle(first_page_title) + end + return self end +function WikiReaderWidget:getDBconn(db_path) + if self.db_conn then + return self.db_conn + end + if self.db_path == nil and db_path == nil then + log("No db specified") + end + if db_path ~= nil then + self.db_path = db_path + end + self.db_conn = SQ3.open(self.db_path) + return self.db_conn +end + function WikiReaderWidget:showArticle(id, html) local html_dir = DataStorage:getDataDir() .. "/cache/" local article_filename = ("%s/wikireader-%s.html"):format(html_dir, id) @@ -103,32 +83,17 @@ function WikiReaderWidget:showArticle(id, html) ReadHistory:removeItemByPath(article_filename) end -function WikiReaderWidget:loadCSS() - -- Curently not supported properly - do return end - local get_css_stmt = self.db_conn:prepare( - "SELECT content_zstd FROM css LIMIT 1;" - ) - local css_row = get_css_stmt:bind():step() - local cssBlob = css_row[1] - local css_data, css_size = zstd.zstd_uncompress(cssBlob[1], cssBlob[2]) - local css = ffi.string(css_data, css_size) - self.css = css -end - -function WikiReaderWidget:gotoTitle(new_title) - local new_title = new_title:gsub("_", " ") +function WikiReaderWidget:gotoTitle(new_title, db_path) + new_title = new_title:gsub("_", " ") UIManager:show(InfoMessage:new{ text = _("Searching for title: ") .. new_title, timeout = 1 }) - - local get_title_stmt = self.db_conn:prepare( - "SELECT id FROM title_2_id WHERE title_lower_case = ?;" - ) + local db_conn = self:getDBconn(db_path) + local get_title_stmt = db_conn:prepare("SELECT id FROM title_2_id WHERE title_lower_case = ?;") local title_row = get_title_stmt:bind(new_title:lower()):step() - + log("Got title row ", title_row) if title_row == nil then UIManager:show(InfoMessage:new{ @@ -138,7 +103,8 @@ function WikiReaderWidget:gotoTitle(new_title) else local id = title_row[1] -- Try to get the html from the row using the id - local get_page_content_stmt = self.db_conn:prepare("SELECT id, title, page_content_zstd FROM articles WHERE id = ?;") + local get_page_content_stmt = db_conn:prepare( + "SELECT id, title, page_content_zstd FROM articles WHERE id = ?;") local article_row = get_page_content_stmt:bind(id):step() log("Got article_row row ", article_row) if article_row == nil then @@ -167,34 +133,37 @@ function WikiReaderWidget:gotoTitle(new_title) -- We are going to the last page, so remove the title from the history table.remove(self.history, #self.history) end - else + else table.insert(self.history, new_title) end if new_title == current_title then -- Not sure how, but we are going to the same page. remove the same title from history table.remove(self.history, #self.history) end - local actual_previous_title = self.history[#self.history - 1] - if actual_previous_title then - local go_back_anchor = "

Go back to ") .. actual_previous_title:gsub("_", " ") .. "

" - html = html:gsub("", "" .. go_back_anchor, 1) - end - log("replacing href's") - html = html:gsub('") - if head_index ~= nil and self.css ~= nil and false then - html = html:sub(1, head_index - 1) .. "" .. html:sub(head_index) - end - + html = self:transformHTML(html) self:showArticle(id, html) log("History after load ", self.history) end end end +function WikiReaderWidget:transformHTML(html) + local actual_previous_title = self.history[#self.history - 1] + if actual_previous_title then + local go_back_anchor = "

Go back to ") .. + actual_previous_title:gsub("_", " ") .. "

" + html = html:gsub("", "" .. go_back_anchor, 1) + end + + -- Encode the db path in the URL, URL escaping doesn't work for some reason, so use base64 + local prefix = "kolocalwiki://" .. escape.base64_encode(self.db_path) .. "#" -- Title will be after the hashtag + log("replacing href's", prefix) + html = replace(html, '