From 4643d40d67948f7ae05b166f5e67b2ce9800cb42 Mon Sep 17 00:00:00 2001 From: Bart Grosman Date: Tue, 20 Sep 2022 10:40:32 +0200 Subject: [PATCH 1/3] Add WikiReader plugin --- plugins/wikireader.koplugin/_meta.lua | 6 + plugins/wikireader.koplugin/main.lua | 187 +++++++++++ plugins/wikireader.koplugin/reader-widget.lua | 311 ++++++++++++++++++ 3 files changed, 504 insertions(+) create mode 100644 plugins/wikireader.koplugin/_meta.lua create mode 100644 plugins/wikireader.koplugin/main.lua create mode 100644 plugins/wikireader.koplugin/reader-widget.lua diff --git a/plugins/wikireader.koplugin/_meta.lua b/plugins/wikireader.koplugin/_meta.lua new file mode 100644 index 000000000..a09d70d72 --- /dev/null +++ b/plugins/wikireader.koplugin/_meta.lua @@ -0,0 +1,6 @@ +local _ = require("gettext") +return { + name = "wikireader", + fullname = _("WikiReader"), + description = _([[Reads wikipedia articles from the local storage]]), +} diff --git a/plugins/wikireader.koplugin/main.lua b/plugins/wikireader.koplugin/main.lua new file mode 100644 index 000000000..1310937ab --- /dev/null +++ b/plugins/wikireader.koplugin/main.lua @@ -0,0 +1,187 @@ +--[[-- +This plugin reads wikipedia articles from the local storage. + +@module koplugin.wikireader +--]]-- + +local WidgetContainer = require("ui/widget/container/widgetcontainer") +local WikiReaderWidget = dofile('./plugins/wikireader.koplugin/reader-widget.lua') +local UIManager = require("ui/uimanager") +local InfoMessage = require("ui/widget/infomessage") +local PathChooser = require("ui/widget/pathchooser") +local Device = require("device") +local util = require("util") + +local _ = require("gettext") +local logger = require("logger") +local log = logger.dbg +local WikiReader = WidgetContainer:new{ + name = "wikireader", + widget = nil +} + +function WikiReader:init() + self.ui.menu:registerToMainMenu(self) +end + +local function file_exists(name) + local f=io.open(name,"r") + 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]) + UIManager:show(InfoMessage:new{ + text = _("Re-opened WikiReader"), + timeout = 5 + }) + end +end + +function WikiReader:start() + local wikireader_db_path = 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"), + timeout = 2 + }) + elseif wikireader_db_path:match('%.db$') == nil then + UIManager:show(InfoMessage:new{ + text = _("Invalid database path (does not end in .db), please set it"), + timeout = 2 + }) + else + 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 + else + UIManager:show(InfoMessage:new{ + text = _("Did not find database at: ") .. db_file, + timeout = 5 + }) + end + end +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) +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, + path = home_dir, + onConfirm = function(path) + G_reader_settings:saveSetting("wikireader_db_path", path) + UIManager:show(InfoMessage:new{ + text = _("Set WikiReader database path to: ") .. path, + }) + end + } + UIManager:show(path_chooser) + +end + +function WikiReader:getFavoritesTable () + local favorites_table = {{ + text = _("Add current page to favorites"), + separator = true, + callback = function(touchmenu_instance) + if WikiReaderInstance == nil then + UIManager:show(InfoMessage:new{ + text = "WikiReader is not openend", + timeout = 2 + }) + else + WikiReaderInstance.widget:addCurrentTitleToFavorites() + end + end + }} + + local favorite_titles = G_reader_settings:readSetting("wikireader-favorites") or {} + + 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) + end + }) + end + log("Got favorites table:", favorites_table) + return favorites_table +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, + }, + { + text = _("Search WikiReader"), + callback = WikiReader.onSearchRequest, + }, + { + text = _("Select database"), + callback = WikiReader.showDBfilePicker, + }, + { + text = _("Favorites"), + sub_item_table_func = function () return WikiReader:getFavoritesTable() end + }, + { + text = _("About"), + callback = function () + UIManager:show(InfoMessage:new{ + text = _("WikiReader allows KOReader to read an offline webpages database, most commonly for WikiPedia.\n" .. + "This database is a converted ZIM file, as it is used by for example the Kiwix software.\n\n" .. + "Build by Bart Grosman") + }) + end + } + } +end + + +return WikiReader diff --git a/plugins/wikireader.koplugin/reader-widget.lua b/plugins/wikireader.koplugin/reader-widget.lua new file mode 100644 index 000000000..5255bece8 --- /dev/null +++ b/plugins/wikireader.koplugin/reader-widget.lua @@ -0,0 +1,311 @@ +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 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") + +local WikiReaderWidget = { + name = "wikireader-widget", + db_conn = nil, + input_dialog = nil, + css = '', + history = {}, +} + +function WikiReaderWidget:addCurrentTitleToFavorites() + local currentTitle = self.history[#self.history] + local favorites = G_reader_settings:readSetting("wikireader-favorites") or {} + table.insert(favorites, currentTitle) + G_reader_settings:saveSetting("wikireader-favorites", favorites) + + local newFavorites = G_reader_settings:readSetting("wikireader-favorites") + 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 + }) + + self.db_conn = SQ3.open(db_file) + -- Load css + self:loadCSS() + -- First load the first page + self:gotoTitle(first_page_title) + UIManager:scheduleIn(0.1, function() + self:overrideLinkHandler() + end) + return self +end + +function WikiReaderWidget:showArticle(id, html) + local html_dir = DataStorage:getDataDir() .. "/cache/" + local article_filename = ("%s/wikireader-%s.html"):format(html_dir, id) + FileConverter:writeStringToFile(html, article_filename) + + ReaderUI:showReader(article_filename) + UIManager:scheduleIn(1, function() + local absolute_article_path = BaseUtil.realpath(article_filename) + ReadHistory:removeItemByPath(absolute_article_path) -- Remove from history again + end) + 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("_", " ") + + 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 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{ + text = "Page: " .. new_title .. " not indexed", + timeout = 2 + }) + 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 article_row = get_page_content_stmt:bind(id):step() + log("Got article_row row ", article_row) + if article_row == nil then + UIManager:show(InfoMessage:new{ + text = _("Page: ") .. new_title .. _(" not found"), + timeout = 2 + }) + else + UIManager:show(InfoMessage:new{ + text = _("Loading page: ") .. new_title, + timeout = 1 + }) + local htmlBlob = article_row[3] + local html_data, html_size = zstd.zstd_uncompress(htmlBlob[1], htmlBlob[2]) + local html = ffi.string(html_data, html_size) + + log("History before load ", self.history) + local current_title = self.history[#self.history] + local previous_title = self.history[#self.history - 1] + + if current_title ~= nil then + if new_title ~= previous_title then + -- Add new title to the history + table.insert(self.history, new_title) + else + -- We are going to the last page, so remove the title from the history + table.remove(self.history, #self.history) + end + 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 + + self:showArticle(id, html) + log("History after load ", self.history) + end + end +end + + +function WikiReaderWidget:createInputDialog(title, buttons) + self.input_dialog = InputDialog:new{ + title = title, + input = "", + input_hint = "", + input_type = "text", + buttons = { + buttons, + { + { + text = _("Cancel"), + id = "close", + callback = function() + UIManager:close(self.input_dialog) + end, + }, + }, + } + } +end + +function WikiReaderWidget:showSearchResultsMenu(search_results) + local menu_items = {} + + for i = 1, #search_results do + local search_result = search_results[i] + local new_table_item = { + text = search_result.title, + callback = function () + if self.searchResultMenu ~= nil then + self.searchResultMenu:onClose() + self.searchResultMenu = nil + end + self:gotoTitle(search_result.title) + end + } + + table.insert(menu_items, new_table_item) + end + + self.searchResultMenu = Menu:new{ + title = _("Search Results"), + item_table = menu_items, + is_enable_shortcut = false, + width = Screen:getWidth(), + height = Screen:getHeight(), + } + UIManager:show(self.searchResultMenu) +end + + + +function WikiReaderWidget:exhaustiveSearch(title, max_num_search_results) + local title = title:gsub("_", " ") + local lowercase_title = title:lower() + max_num_search_results = max_num_search_results or 50 + + local full_db_search_sql = [[ + SELECT id, title_lower_case FROM title_2_id WHERE title_lower_case LIKE "%" || ? || "%" + LIMIT ?; + ]] + + log("Got title:", lowercase_title) + + local get_title_stmt = self.db_conn:prepare(full_db_search_sql) + local get_title_binding = get_title_stmt:bind(lowercase_title, max_num_search_results) + + local search_results = {} + for i = 1, max_num_search_results do + local title_row = get_title_binding:step() + if title_row then + table.insert(search_results, { + id = title_row[1], + title = title_row[2] + }) + end + end + self:showSearchResultsMenu(search_results) +end + +function WikiReaderWidget:showSearchBox() + local search_callback = function(is_exhaustive) + if self.input_dialog:getInputText() == "" then return end + + UIManager:close(self.input_dialog) + local title = self.input_dialog:getInputText() + if title and title ~= "" then + if is_exhaustive then + self:exhaustiveSearch(title) + else + self:gotoTitle(title) + end + end + end + + local buttons = { + { + text = _("Search"), + callback = function() search_callback(false) end + }, + { + text = _("Exhaustive Search (slow)"), + callback = function() search_callback(true) end + } + } + + self:createInputDialog(_("Search Wikipedia"), buttons) + + UIManager:show(self.input_dialog) + self.input_dialog:onShowKeyboard() +end + +return WikiReaderWidget \ No newline at end of file From debe6668c86a189a8d6c554ff923508c47d1bc3e Mon Sep 17 00:00:00 2001 From: Bart Grosman Date: Mon, 26 Sep 2022 13:59:19 +0200 Subject: [PATCH 2/3] Cleanup: Do not use global instance anymore, instead just remember last widget instance in local variable. Patch the readerlink to emit events if it caught a "kolocalwiki://" prefixed URL And add listener for this in plugin --- frontend/apps/reader/modules/readerlink.lua | 5 + plugins/wikireader.koplugin/main.lua | 97 ++++----- plugins/wikireader.koplugin/reader-widget.lua | 198 ++++++++---------- 3 files changed, 137 insertions(+), 163 deletions(-) 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, ' Date: Mon, 26 Sep 2022 14:38:11 +0200 Subject: [PATCH 3/3] typo: tab -> 4 spaces --- plugins/wikireader.koplugin/reader-widget.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/wikireader.koplugin/reader-widget.lua b/plugins/wikireader.koplugin/reader-widget.lua index 9bcf6fe45..15a3961e9 100644 --- a/plugins/wikireader.koplugin/reader-widget.lua +++ b/plugins/wikireader.koplugin/reader-widget.lua @@ -28,7 +28,7 @@ local WikiReaderWidget = { } local function replace(haystack, needle, replacement) - local escapedReplacement = replacement:gsub("[%(%)%.%%%+%-%*%?%[%]%^%$]", function(c) return "%" .. c end) + local escapedReplacement = replacement:gsub("[%(%)%.%%%+%-%*%?%[%]%^%$]", function(c) return "%" .. c end) return haystack:gsub(needle, escapedReplacement) end