You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koreader/plugins/downloadtoepub.koplugin/main.lua

351 lines
12 KiB
Lua

--[[--
Download URLs as EPUBs
@module koplugin.DownloadToEPUB
--]]--
local BD = require("ui/bidi")
local Blitbuffer = require("ffi/blitbuffer")
local ConfirmBox = require("ui/widget/confirmbox")
local DataStorage = require("datastorage")
local Device = require("device")
local Dispatcher = require("dispatcher")
local Event = require("ui/event")
local FFIUtil = require("ffi/util")
local FileManager = require("apps/filemanager/filemanager")
local InfoMessage = require("ui/widget/infomessage")
local LuaSettings = require("frontend/luasettings")
local MultiConfirmBox = require("ui/widget/multiconfirmbox")
local NetworkMgr = require("ui/network/manager")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local VerticalGroup = require("ui/widget/verticalgroup")
local Screen = Device.screen
local Size = require("ui/size")
local filemanagerutil = require("apps/filemanager/filemanagerutil")
local logger = require("logger")
local util = require("frontend/util")
local T = FFIUtil.template
local _ = require("gettext")
-- Gazette Modules
local EpubBuildDirector = require("libs/gazette/epubbuilddirector")
local WebPage = require("libs/gazette/resources/webpage")
local ResourceAdapter = require("libs/gazette/resources/webpageadapter")
local Epub = require("libs/gazette/epub/epub")
local History = require("epubhistory")
local HistoryView = require("epubhistoryview")
local DownloadToEpub = WidgetContainer:new{
name = "Download to EPUB",
download_directory = ("%s/%s/"):format(DataStorage:getFullDataDir(), "EPUB Downloads")
}
local EpubBuilder = {
output_directory = nil,
}
function DownloadToEpub:init()
self.settings = self.readSettings()
if self.settings.data.download_directory then
self.download_directory = self.settings.data.download_directory
end
self:createDownloadDirectoryIfNotExists()
self.ui.menu:registerToMainMenu(self)
if self.ui and self.ui.link then
self.ui.link:addToExternalLinkDialog("30_downloadtoepub", function(this, link_url)
return {
text = _("Download to EPUB"),
callback = function()
UIManager:close(this.external_link_dialog)
this.ui:handleEvent(Event:new("DownloadEpubFromUrl", link_url))
end,
show_in_dialog_func = function()
return true
end
}
end)
end
end
function DownloadToEpub:addToMainMenu(menu_items)
menu_items.downloadtoepub = {
text = _("Download to EPUB"),
sorting_hint = "tools",
sub_item_table = {
{
text = _("Go to EPUB downloads"),
callback = function()
self:goToDownloadDirectory()
end,
},
{
text = _("Settings"),
sub_item_table = {
{
text_func = function()
local path = filemanagerutil.abbreviate(self.download_directory)
return T(_("Set download directory (%1)"), BD.dirpath(path))
end,
keep_menu_open = true,
callback = function() self:setDownloadDirectory() end,
},
}
},
{
text = _("About"),
keep_menu_open = true,
callback = function()
UIManager:show(InfoMessage:new{
text = "DownloadToEpub lets you download external links as EPUBs to your device."
})
end,
},
}
}
local history_view = HistoryView:new{}
local last_download_item = history_view:getLastDownloadButton(function(history_item)
self:maybeOpenEpub(history_item['download_path'])
end)
local history_menu_items = history_view:getMenuItems(function(history_item)
self:maybeOpenEpub(history_item['download_path'])
end)
if last_download_item then table.insert(menu_items.downloadtoepub.sub_item_table, 2, last_download_item) end
if history_menu_items then table.insert(menu_items.downloadtoepub.sub_item_table, 3, history_menu_items[1]) end
end
function DownloadToEpub:maybeOpenEpub(file_path)
if util.pathExists(file_path) then
logger.dbg("DownloadToEpub: Opening " .. file_path)
local Event = require("ui/event")
UIManager:broadcastEvent(Event:new("SetupShowReader"))
local ReaderUI = require("apps/reader/readerui")
ReaderUI:showReader(file_path)
else
logger.dbg("DownloadToEpub: Couldn't open " .. file_path .. ". It's been moved or deleted.")
self:showRedownloadPrompt(file_path)
end
end
function DownloadToEpub:readSettings()
local settings = LuaSettings:open(DataStorage:getSettingsDir() .. "downloadtoepub.lua")
if not settings.data.downloadtoepub then
settings.data.downloadtoepub = {}
end
return settings
end
function DownloadToEpub:saveSettings()
local temp_settings = {
download_directory = self.download_directory
}
self.settings:saveSetting("downloadtoepub", temp_settings)
self.settings:flush()
end
function DownloadToEpub:setDownloadDirectory()
local downloadmgr = require("ui/downloadmgr")
downloadmgr:new{
onConfirm = function(path)
self.download_directory = path
self:saveSettings()
end
}:chooseDir()
end
function DownloadToEpub:goToDownloadDirectory()
local FileManager = require("apps/filemanager/filemanager")
if self.ui.document then
self.ui:onClose()
end
if FileManager.instance then
FileManager.instance:reinit(self.download_directory)
else
FileManager:showFiles(self.download_directory)
end
end
function DownloadToEpub:createDownloadDirectoryIfNotExists()
if not util.pathExists(self.download_directory) then
logger.dbg("DownloadToEpub: Creating path (" .. self.download_directory .. ")")
lfs.mkdir(self.download_directory)
end
end
function DownloadToEpub:onDownloadEpubFromUrl(link_url)
local prompt
prompt = ConfirmBox:new{
text = T(_("Download to EPUB? \n\nLink: %1"), link_url),
ok_text = _("Yes"),
ok_callback = function()
UIManager:close(prompt)
self:downloadEpubWithUi(link_url, function(file_path, err)
if err then
UIManager:show(InfoMessage:new{ text = T(_("Error downloading EPUB: %1", err)) })
else
local history = History:new{}
history:init()
logger.dbg("DownloadToEpub: Maybe deleting from history " .. link_url)
history:remove(link_url) -- link might have already been downloaded. If so, remove the history item.
logger.dbg("DownloadToEpub: Adding to history " .. link_url .. " " .. file_path)
history:add(link_url, file_path)
logger.dbg("DownloadToEpub: Finished downloading epub to " .. file_path)
self:showReadPrompt(file_path)
end
end)
end,
}
UIManager:show(prompt)
end
function DownloadToEpub:downloadEpubWithUi(link_url, callback)
local info = InfoMessage:new{ text = ("Downloading... " .. link_url) }
UIManager:show(info)
UIManager:forceRePaint()
UIManager:close(info)
NetworkMgr:runWhenOnline(function()
local epub_builder = EpubBuilder:new{
output_directory = self.download_directory,
}
local file_path, err = epub_builder:buildFromUrl(link_url)
callback(file_path, err)
end)
end
function DownloadToEpub:showRedownloadPrompt(file_path) -- supply this with a directory?
local prompt
local history = History:new{}
history:init()
local history_item = history:find(file_path)
if history_item then
prompt = MultiConfirmBox:new{
text = T(_("Couldn't open EPUB! \n\nFile has been moved since download (%1)\n\nInitially downloaded from (%2)\n\nWhat would you like to do?"),
file_path,
history_item.url),
choice1_text = _("Redownload EPUB"),
choice1_callback = function()
logger.dbg("DownloadToEpub: Redownloading " .. history_item.url)
UIManager:close(prompt)
self:onDownloadEpubFromUrl(history_item.url)
end,
choice2_text = _("Delete from history"),
choice2_callback = function()
logger.dbg("DownloadToEpub: Deleting from history " .. history_item.url)
history:remove(history_item.url)
UIManager:close(prompt)
end,
}
else
prompt = InfoMessage:new{
text = _("Couldn't open EPUB! EPUB has been deleted or moved since being downloaded."),
show_icon = false,
timeout = 10,
}
end
UIManager:show(prompt)
end
function DownloadToEpub:showReadPrompt(file_path)
local prompt = ConfirmBox:new{
text = _("EPUB downloaded. Would you like to read it now?"),
ok_text = _("Open EPUB"),
ok_callback = function()
logger.dbg("DownloadToEpub: Opening " .. file_path)
local Event = require("ui/event")
UIManager:broadcastEvent(Event:new("SetupShowReader"))
UIManager:close(prompt)
local ReaderUI = require("apps/reader/readerui")
ReaderUI:showReader(file_path)
end,
}
UIManager:show(prompt)
end
function EpubBuilder:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
function EpubBuilder:buildFromUrl(url)
logger.dbg("DownloadToEpub: Begin download of " .. url .. " outputting to " .. self.output_directory)
local info = InfoMessage:new{ text = _("Getting webpage…") }
UIManager:show(info)
UIManager:forceRePaint()
UIManager:close(info)
local webpage, err = self:createWebpage(url)
if not webpage then
logger.dbg("DownloadToEpub: " .. err)
return false, err
end
info = InfoMessage:new{ text = _("Building EPUB…") }
UIManager:show(info)
UIManager:forceRePaint()
UIManager:close(info)
local epub = Epub:new{}
epub:addFromList(ResourceAdapter:new(webpage))
epub:setTitle(webpage.title)
epub:setAuthor("DownloadToEpub")
local epub_path = ("%s%s.epub"):format(self.output_directory, util.getSafeFilename(epub.title))
local build_director, err = self:createBuildDirector(epub_path)
if not build_director then
logger.dbg("DownloadToEpub: " .. err)
return false, err
end
info = InfoMessage:new{ text = _("Writing to device…") }
UIManager:show(info)
UIManager:forceRePaint()
UIManager:close(info)
logger.dbg("DownloadToEpub: Writing EPUB to " .. epub_path)
local path_to_epub, err = build_director:construct(epub)
if not path_to_epub then
logger.dbg("DownloadToEpub: " .. err)
return false, err
end
return path_to_epub
end
function EpubBuilder:createWebpage(url)
local webpage, err = WebPage:new({
url = url,
})
if err then
return false, err
end
webpage:build()
return webpage
end
function EpubBuilder:createBuildDirector(epub_path)
local build_director, err = EpubBuildDirector:new()
if not build_director then
return false, err
end
local success, err = build_director:setDestination(epub_path)
if not success then
return false, err
end
return build_director
end
return DownloadToEpub