Plugin manager (#4159)

Also adds descriptions to all plugins.
pull/4172/head
Robert 6 years ago committed by poire-z
parent cd37535056
commit 4428ecb422

@ -4,6 +4,7 @@ local ConfirmBox = require("ui/widget/confirmbox")
local Device = require("device")
local FileSearcher = require("apps/filemanager/filemanagerfilesearcher")
local InputContainer = require("ui/widget/container/inputcontainer")
local PluginLoader = require("pluginloader")
local Search = require("apps/filemanager/filemanagersearch")
local SetDefaults = require("apps/filemanager/filemanagersetdefaults")
local UIManager = require("ui/uimanager")
@ -160,6 +161,11 @@ function FileManagerMenu:setUpdateItemTable()
SetDefaults:ConfirmSave()
end,
}
self.menu_items.plugin_management = {
text = _("Plugin management"),
sub_item_table = PluginLoader:genPluginManagerSubItem()
}
self.menu_items.opds_catalog = {
text = _("OPDS catalog"),
callback = function()

@ -155,6 +155,12 @@ function ReaderMenu:setUpdateItemTable()
table.remove(self.menu_items.screensaver.sub_item_table, 9)
table.insert(self.menu_items.screensaver.sub_item_table, ss_book_settings)
end
local PluginLoader = require("pluginloader")
self.menu_items.plugin_management = {
text = _("Plugin management"),
sub_item_table = PluginLoader:genPluginManagerSubItem()
}
-- main menu tab
-- insert common info
for id, common_setting in pairs(require("ui/elements/common_info_menu_table")) do

@ -2,8 +2,9 @@ local lfs = require("libs/libkoreader-lfs")
local logger = require("logger")
local DEFAULT_PLUGIN_PATH = "plugins"
local OBSOLETE_PLUGINS = {
storagestat = true
}
local function sandboxPluginEventHandlers(plugin)
for key, value in pairs(plugin) do
@ -22,12 +23,15 @@ local function sandboxPluginEventHandlers(plugin)
end
local PluginLoader = {}
local PluginLoader = {
show_info = true,
}
function PluginLoader:loadPlugins()
if self.plugins then return self.plugins end
if self.enabled_plugins then return self.enabled_plugins, self.disabled_plugins end
self.plugins = {}
self.enabled_plugins = {}
self.disabled_plugins = {}
local lookup_path_list = { DEFAULT_PLUGIN_PATH }
local extra_paths = G_reader_settings:readSetting("extra_plugin_paths")
if extra_paths then
@ -54,16 +58,17 @@ function PluginLoader:loadPlugins()
if type(plugins_disabled) ~= "table" then
plugins_disabled = {}
end
--permanent remove storage stats plugin (#2926)
plugins_disabled["storagestat"] = true
--disable obsolete plugins
for element in pairs(OBSOLETE_PLUGINS) do
plugins_disabled[element] = true
end
for _,lookup_path in ipairs(lookup_path_list) do
logger.info('Loading plugins from directory:', lookup_path)
for entry in lfs.dir(lookup_path) do
local plugin_root = lookup_path.."/"..entry
local mode = lfs.attributes(plugin_root, "mode")
-- valid koreader plugin directory
if mode == "directory" and entry:find(".+%.koplugin$")
and not (plugins_disabled and plugins_disabled[entry:sub(1, -10)]) then
if mode == "directory" and entry:find(".+%.koplugin$") then
local mainfile = plugin_root.."/main.lua"
package.path = string.format("%s/?.lua;%s", plugin_root, package_path)
package.cpath = string.format("%s/lib/?.so;%s", plugin_root, package_cpath)
@ -73,8 +78,12 @@ function PluginLoader:loadPlugins()
elseif type(plugin_module.disabled) ~= "boolean" or not plugin_module.disabled then
plugin_module.path = plugin_root
plugin_module.name = plugin_module.name or plugin_root:match("/(.-)%.koplugin")
sandboxPluginEventHandlers(plugin_module)
table.insert(self.plugins, plugin_module)
if (plugins_disabled and plugins_disabled[entry:sub(1, -10)]) then
table.insert(self.disabled_plugins, plugin_module)
else
sandboxPluginEventHandlers(plugin_module)
table.insert(self.enabled_plugins, plugin_module)
end
else
logger.info("Plugin ", mainfile, " has been disabled.")
end
@ -85,14 +94,74 @@ function PluginLoader:loadPlugins()
end
-- set package path for all loaded plugins
for _,plugin in ipairs(self.plugins) do
for _,plugin in ipairs(self.enabled_plugins) do
package.path = string.format("%s;%s/?.lua", package.path, plugin.path)
package.cpath = string.format("%s;%s/lib/?.so", package.cpath, plugin.path)
end
table.sort(self.plugins, function(v1,v2) return v1.path < v2.path end)
table.sort(self.enabled_plugins, function(v1,v2) return v1.path < v2.path end)
return self.enabled_plugins, self.disabled_plugins
end
function PluginLoader:genPluginManagerSubItem()
local enabled_plugins, disabled_plugins = {}, {}
if self.all_plugins == nil then
self.all_plugins = {}
enabled_plugins, disabled_plugins = self:loadPlugins()
end
for _, plugin in ipairs(enabled_plugins) do
local element = {}
element.fullname = plugin.fullname or plugin.name
element.name = plugin.name
element.description = plugin.description
element.enable = true
table.insert(self.all_plugins, element)
end
for _, plugin in ipairs(disabled_plugins) do
local element = {}
element.fullname = plugin.fullname or plugin.name
element.name = plugin.name
element.description = plugin.description
element.enable = false
if not OBSOLETE_PLUGINS[element.name] then
table.insert(self.all_plugins, element)
end
end
table.sort(self.all_plugins, function(v1, v2) return v1.fullname < v2.fullname end)
return self.plugins
local plugin_table = {}
for __, plugin in ipairs(self.all_plugins) do
table.insert(plugin_table, {
text = plugin.fullname,
checked_func = function()
return plugin.enable
end,
callback = function()
local InfoMessage = require("ui/widget/infomessage")
local UIManager = require("ui/uimanager")
local _ = require("gettext")
local plugins_disabled = G_reader_settings:readSetting("plugins_disabled") or {}
plugin.enable = not plugin.enable
if plugin.enable then
plugins_disabled[plugin.name] = nil
else
plugins_disabled[plugin.name] = true
end
G_reader_settings:saveSetting("plugins_disabled", plugins_disabled)
if self.show_info then
UIManager:show(InfoMessage:new{
text = _("This will take effect on next restart."),
})
self.show_info = false
end
end,
help_text = plugin.description,
})
end
return plugin_table
end
function PluginLoader:createPluginInstance(plugin, attr)

@ -58,6 +58,7 @@ local order = {
"text_editor",
"----------------------------",
"more_plugins",
"plugin_management",
"----------------------------",
"advanced_settings",
"developer_options",

@ -79,6 +79,7 @@ local order = {
"text_editor",
"----------------------------",
"more_plugins",
"plugin_management",
},
more_plugins = {
"auto_frontlight",

@ -20,6 +20,8 @@ end
local SSH = WidgetContainer:new{
name = 'SSH',
fullname = _("SSH"),
description = _([[Connect and transfer files to the device using SSH.]]),
is_doc_only = false,
}

@ -88,7 +88,9 @@ end
AutoFrontlight:init()
local AutoFrontlightWidget = WidgetContainer:new{
name = "AutoFrontlight",
name = "autofrontlight",
fullname = _("Auto frontlight"),
description = _([[Automatically turns the frontlight on and off once brightness in the environment reaches a certain level.]]),
}
function AutoFrontlightWidget:init()

@ -111,7 +111,9 @@ end
AutoSuspend:init()
local AutoSuspendWidget = WidgetContainer:new{
name = "AutoSuspend",
name = "autosuspend",
fullname = _("Auto suspend"),
description = _([[Suspends the device after a period of inactivity.]]),
}
function AutoSuspendWidget:onInputEvent()

@ -3,6 +3,7 @@ local PluginShare = require("pluginshare")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local logger = require("logger")
local _ = require("gettext")
-- BackgroundRunner is an experimental feature to execute non-critical jobs in
-- background. A job is defined as a table in PluginShare.backgroundJobs table.
@ -238,6 +239,8 @@ BackgroundRunner:_schedule()
local BackgroundRunnerWidget = WidgetContainer:new{
name = "backgroundrunner",
fullname = _("Background runner"),
description = _([[Service to other plugins: allows tasks to run regularly in the background.]]),
runner = BackgroundRunner,
}

@ -282,6 +282,8 @@ BatteryStat:init()
local BatteryStatWidget = WidgetContainer:new{
name = "batterystat",
fullname = _("Battery statistics"),
description = _([[Collects and displays battery statistics.]]),
}
function BatteryStatWidget:init()

@ -23,6 +23,8 @@ require("ffi/zeromq_h")
--]]
local CalibreCompanion = InputContainer:new{
name = "calibrecompanion",
fullname = _("Calibre companion"),
description = _([[Send documents from calibre library directly to device via Wi-Fi connection]]),
-- calibre companion local port
port = 8134,
-- calibre broadcast ports used to find calibre server

@ -41,7 +41,11 @@ local init_done = false
local filemanager_display_mode = false -- not initialized yet
local history_display_mode = false -- not initialized yet
local CoverBrowser = InputContainer:new{}
local CoverBrowser = InputContainer:new{
name = "coverbrowser",
fullname = _("Cover browser"),
description = _([[Alternative display modes for file browser and history.]]),
}
function CoverBrowser:init()
self.full_featured = true

@ -18,6 +18,8 @@ local realpath = require("ffi/util").realpath
local EvernoteExporter = InputContainer:new{
name = "evernote",
fullname = _("Evernote"),
description = _([[Exports hightlights and notes to the Evernote cloud.]]),
login_title = _("Login to Evernote"),
notebook_name = _("KOReader Notes"),
evernote_domain = nil,

@ -9,6 +9,9 @@ local _ = require("gettext")
local NetworkMgr = require("ui/network/manager")
local Goodreads = InputContainer:new {
name = "goodreads",
fullname = _("Goodreads"),
description = _([[Allows browsing and searching the Goodreads database of books.]]),
goodreads_key = "",
goodreads_secret = "",
}

@ -9,7 +9,9 @@ local WidgetContainer = require("ui/widget/container/widgetcontainer")
local _ = require("gettext")
local Hello = WidgetContainer:new{
name = 'Hello',
name = 'hello',
fullname = _("Hello"),
description = _([[This is a debugging plugin.]]),
is_doc_only = false,
}

@ -61,6 +61,8 @@ end
local KeepAlive = WidgetContainer:new{
name = "keepalive",
fullname = _("Keep alive"),
description = _([[Keeps the device awake to prevent automatic Wi-Fi disconnects.]]),
}
function KeepAlive:init()

@ -22,6 +22,8 @@ local swipe_touch_zone_ratio_warmth = { x = 7/8, y = 1/8, w = 1/8, h = 7/8, }
local KoboLight = WidgetContainer:new{
name = 'kobolight',
fullname = _("Frontlight gesture controller"),
description = _([[Controls the frontlight with gestures on the left border of screen.]]),
gestureScale = nil, -- initialized in self:resetLayout()
}

@ -20,6 +20,8 @@ end
local KOSync = InputContainer:new{
name = "kosync",
fullname = _("Progress sync"),
description = _([[Synchronizes your reading progess to a server across your KOReader devices.]]),
is_doc_only = true,
title = _("Register/login to KOReader server"),

@ -15,7 +15,11 @@ local util = require("util")
local _ = require("gettext")
local T = FFIUtil.template
local NewsDownloader = WidgetContainer:new{}
local NewsDownloader = WidgetContainer:new{
name = "newsdownloader",
fullname = _("News downloader"),
description = _([[Retrieves RSS and Atom news entries and saves them as HTML files.]]),
}
local initialized = false
local wifi_enabled_before_action = true

@ -15,7 +15,9 @@ local Blitbuffer = require("ffi/blitbuffer")
local PerceptionExpander = Widget:extend{
is_enabled = nil,
name = "perception_expander",
name = "perceptionexpander",
fullname = _("Perception expander"),
description = _([[Improves your reading speed with the help of two vertical lines over the text.]]),
page_counter = 0,
shift_each_pages = 100,
margin = 0.1,

@ -7,6 +7,8 @@ local _ = require("gettext")
local ReadTimer = WidgetContainer:new{
name = "readtimer",
fullname = _("Read timer"),
description = _([[Shows an alarm after a specified amount of time.]]),
time = 0, -- The expected time of alarm if enabled, or 0.
}

@ -15,7 +15,11 @@ local util = require("util")
local _ = require("gettext")
local T = FFIUtil.template
local Send2Ebook = WidgetContainer:new{}
local Send2Ebook = WidgetContainer:new{
name = "send2ebook",
fullname = _("Send to eBook"),
description = _([[Receives articles sent with the Send2Ebook PC/Android application.]]),
}
local initialized = false
local wifi_enabled_before_action = true

@ -28,6 +28,9 @@ local DEFAULT_MIN_READ_SEC = 5
local DEFAULT_MAX_READ_SEC = 120
local ReaderStatistics = Widget:extend{
name = "statistics",
fullname = _("Reader statistics"),
description = _([[Keeps and displays your reading statistics.]]),
page_min_read_sec = DEFAULT_MIN_READ_SEC,
page_max_read_sec = DEFAULT_MAX_READ_SEC,
start_current_period = 0,

@ -240,6 +240,8 @@ SystemStat:init()
local SystemStatWidget = WidgetContainer:new{
name = "systemstat",
fullname = _("System statistics"),
description = _([[Shows system statistics.]]),
}
function SystemStatWidget:init()

@ -11,6 +11,8 @@ local Screen = require("device").screen
local Terminal = WidgetContainer:new{
name = "terminal",
fullname = _("Terminal"),
description = _([[Executes simple commands and shows their output.]]),
dump_file = util.realpath(DataStorage:getDataDir()) .. "/terminal_output.txt",
command = "",
}

@ -17,7 +17,9 @@ local Screen = require("device").screen
local T = ffiutil.template
local TextEditor = WidgetContainer:new{
name = "text_editor",
name = "texteditor",
fullname = _("Text editor"),
description = _([[A basic text editor for making small changes to plain text files.]]),
settings_file = DataStorage:getSettingsDir() .. "/text_editor.lua",
settings = nil, -- loaded only when needed
-- how many to display in menu (10x3 pages minus our 3 default menu items):

@ -19,6 +19,8 @@ local NetworkMgr = require("ui/network/manager")
local TimeSync = WidgetContainer:new{
name = "timesync",
fullname = _("Time sync"),
description = _([[Synchronizes the device time with NTP servers.]]),
}
local function currentTime()

@ -15,6 +15,8 @@ int rmdir(const char *);
require("ffi/zeromq_h")
local ZSync = InputContainer:new{
name = "zsync",
fullname = _("Zsync"),
description = _([[Devices in the same Wi-Fi network can transfer documents between each other directly.]]),
is_doc_only = true,
}

Loading…
Cancel
Save