mirror of https://github.com/koreader/koreader
Cloud storage - dropbox and ftp integration (#2424)
parent
c662ca4cc8
commit
187598deb2
@ -0,0 +1,370 @@
|
||||
local UIManager = require("ui/uimanager")
|
||||
local Screen = require("device").screen
|
||||
local _ = require("gettext")
|
||||
local Menu = require("ui/widget/menu")
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local ButtonDialog = require("ui/widget/buttondialog")
|
||||
local DropBox = require("frontend/apps/cloudstorage/dropbox")
|
||||
local LuaSettings = require("luasettings")
|
||||
local DataStorage = require("datastorage")
|
||||
local Ftp = require("frontend/apps/cloudstorage/ftp")
|
||||
local ConfirmBox = require("ui/widget/confirmbox")
|
||||
local lfs = require("libs/libkoreader-lfs")
|
||||
local ButtonDialogTitle = require("ui/widget/buttondialogtitle")
|
||||
|
||||
local CloudStorage = Menu:extend{
|
||||
cloud_servers = {
|
||||
{
|
||||
text = "Add new cloud storage",
|
||||
title = "Choose type of cloud",
|
||||
url = "add",
|
||||
editable = false,
|
||||
},
|
||||
},
|
||||
width = Screen:getWidth(),
|
||||
height = Screen:getHeight(),
|
||||
no_title = false,
|
||||
show_parent = nil,
|
||||
is_popout = false,
|
||||
is_borderless = true,
|
||||
}
|
||||
|
||||
function CloudStorage:init()
|
||||
self.cs_settings = self:readSettings()
|
||||
self.menu_select = nil
|
||||
self.title = "Cloud Storage"
|
||||
self.show_parent = self
|
||||
self.item_table = self:genItemTableFromRoot()
|
||||
Menu.init(self)
|
||||
end
|
||||
|
||||
function CloudStorage:genItemTableFromRoot()
|
||||
local item_table = {}
|
||||
table.insert(item_table, {
|
||||
text = _("Add new cloud storage"),
|
||||
callback = function()
|
||||
self:selectCloudType()
|
||||
end,
|
||||
})
|
||||
local added_servers = self.cs_settings:readSetting("cs_servers") or {}
|
||||
for _, server in ipairs(added_servers) do
|
||||
table.insert(item_table, {
|
||||
text = server.name,
|
||||
address = server.address,
|
||||
username = server.username,
|
||||
password = server.password,
|
||||
type = server.type,
|
||||
editable = true,
|
||||
url = server.url,
|
||||
callback = function()
|
||||
self.type = server.type
|
||||
self.password = server.password
|
||||
self.address = server.address
|
||||
self.username = server.username
|
||||
self:openCloudServer(server.url)
|
||||
end,
|
||||
})
|
||||
end
|
||||
return item_table
|
||||
end
|
||||
|
||||
function CloudStorage:selectCloudType()
|
||||
local buttons = {
|
||||
{
|
||||
{
|
||||
text = _("Dropbox"),
|
||||
callback = function()
|
||||
UIManager:close(self.cloud_dialog)
|
||||
self:configCloud("dropbox")
|
||||
end,
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
text = _("FTP"),
|
||||
callback = function()
|
||||
UIManager:close(self.cloud_dialog)
|
||||
self:configCloud("ftp")
|
||||
end,
|
||||
},
|
||||
},
|
||||
}
|
||||
self.cloud_dialog = ButtonDialogTitle:new{
|
||||
title = _("Choose cloud storage type"),
|
||||
title_align = "center",
|
||||
buttons = buttons,
|
||||
}
|
||||
|
||||
UIManager:show(self.cloud_dialog)
|
||||
return true
|
||||
end
|
||||
|
||||
function CloudStorage:openCloudServer(url)
|
||||
local tbl
|
||||
if self.type == "dropbox" then
|
||||
tbl = DropBox:run(url, self.password)
|
||||
elseif self.type == "ftp" then
|
||||
tbl = Ftp:run(self.address, self.username, self.password, url)
|
||||
end
|
||||
if tbl and #tbl > 0 then
|
||||
self:swithItemTable(url, tbl)
|
||||
return true
|
||||
elseif not tbl then
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("Cannot fetch list folder!\nCheck configuration or network connection."),
|
||||
timeout = 3,
|
||||
})
|
||||
table.remove(self.paths)
|
||||
return false
|
||||
else
|
||||
UIManager:show(InfoMessage:new{text = _("Empty folder") })
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function CloudStorage:onMenuSelect(item)
|
||||
if item.callback then
|
||||
if item.url ~= nil then
|
||||
table.insert(self.paths, {
|
||||
url = item.url,
|
||||
})
|
||||
end
|
||||
item.callback()
|
||||
elseif item.type == "file" then
|
||||
self:downloadFile(item)
|
||||
else
|
||||
table.insert(self.paths, {
|
||||
url = item.url,
|
||||
})
|
||||
if not self:openCloudServer(item.url) then
|
||||
table.remove(self.paths)
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function CloudStorage:downloadFile(item)
|
||||
local lastdir = G_reader_settings:readSetting("lastdir")
|
||||
local cs_settings = self:readSettings()
|
||||
local download_dir = cs_settings:readSetting("download_dir") or lastdir
|
||||
local path = download_dir .. '/' .. item.text
|
||||
if lfs.attributes(path) then
|
||||
UIManager:show(ConfirmBox:new{
|
||||
text = _("File exist! Would you like to override it?"),
|
||||
ok_callback = function()
|
||||
self:cloudFile(item, path)
|
||||
end
|
||||
})
|
||||
else
|
||||
self:cloudFile(item, path)
|
||||
end
|
||||
end
|
||||
|
||||
function CloudStorage:cloudFile(item, path)
|
||||
local path_dir = path
|
||||
local buttons = {
|
||||
{
|
||||
{
|
||||
text = _("Download file"),
|
||||
callback = function()
|
||||
if self.type == "dropbox" then
|
||||
local callback_close = function()
|
||||
self:onClose()
|
||||
end
|
||||
UIManager:scheduleIn(1, function()
|
||||
DropBox:downloadFile(item, self.password, path_dir, callback_close)
|
||||
end)
|
||||
UIManager:close(self.download_dialog)
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("Downloading may take several minutes..."),
|
||||
timeout = 1,
|
||||
})
|
||||
elseif self.type == "ftp" then
|
||||
local callback_close = function()
|
||||
self:onClose()
|
||||
end
|
||||
UIManager:scheduleIn(1, function()
|
||||
Ftp:downloadFile(item, self.address, self.username, self.password, path_dir, callback_close)
|
||||
end)
|
||||
UIManager:close(self.download_dialog)
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("Downloading may take several minutes..."),
|
||||
timeout = 1,
|
||||
})
|
||||
end
|
||||
end,
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
text = _("Set download directory"),
|
||||
callback = function()
|
||||
require("ui/downloadmgr"):new{
|
||||
title = _("Choose download directory"),
|
||||
onConfirm = function(path_download)
|
||||
self.cs_settings:saveSetting("download_dir", path_download)
|
||||
self.cs_settings:flush()
|
||||
path_dir = path_download .. '/' .. item.text
|
||||
end,
|
||||
}:chooseDir()
|
||||
end,
|
||||
},
|
||||
},
|
||||
}
|
||||
self.download_dialog = ButtonDialog:new{
|
||||
buttons = buttons
|
||||
}
|
||||
UIManager:show(self.download_dialog)
|
||||
end
|
||||
|
||||
function CloudStorage:onMenuHold(item)
|
||||
if item.editable then
|
||||
local cs_server_dialog
|
||||
cs_server_dialog = ButtonDialog:new{
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
text = _("Info"),
|
||||
enabled = true,
|
||||
callback = function()
|
||||
UIManager:close(cs_server_dialog)
|
||||
self:infoServer(item)
|
||||
end
|
||||
},
|
||||
{
|
||||
text = _("Edit"),
|
||||
enabled = true,
|
||||
callback = function()
|
||||
UIManager:close(cs_server_dialog)
|
||||
self:editCloudServer(item)
|
||||
|
||||
end
|
||||
},
|
||||
{
|
||||
text = _("Delete"),
|
||||
enabled = true,
|
||||
callback = function()
|
||||
UIManager:close(cs_server_dialog)
|
||||
self:deleteCloudServer(item)
|
||||
end
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
UIManager:show(cs_server_dialog)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function CloudStorage:configCloud(type)
|
||||
local callbackAdd = function(fields)
|
||||
local cs_settings = self:readSettings()
|
||||
local cs_servers = cs_settings:readSetting("cs_servers") or {}
|
||||
if type == "dropbox" then
|
||||
table.insert(cs_servers,{
|
||||
name = fields[1],
|
||||
password = fields[2],
|
||||
type = "dropbox",
|
||||
url = "/"
|
||||
})
|
||||
elseif type == "ftp" then
|
||||
table.insert(cs_servers,{
|
||||
name = fields[1],
|
||||
address = fields[2],
|
||||
username = fields[3],
|
||||
password = fields[4],
|
||||
type = "ftp",
|
||||
url = "/"
|
||||
})
|
||||
end
|
||||
cs_settings:saveSetting("cs_servers", cs_servers)
|
||||
cs_settings:flush()
|
||||
self:init()
|
||||
end
|
||||
if type == "dropbox" then
|
||||
DropBox:config(nil, callbackAdd)
|
||||
end
|
||||
if type == "ftp" then
|
||||
Ftp:config(nil, callbackAdd)
|
||||
end
|
||||
end
|
||||
|
||||
function CloudStorage:editCloudServer(item)
|
||||
local callbackEdit = function(updated_config, fields)
|
||||
local cs_settings = self:readSettings()
|
||||
local cs_servers = cs_settings:readSetting("cs_servers") or {}
|
||||
if item.type == "dropbox" then
|
||||
for i, server in ipairs(cs_servers) do
|
||||
if server.name == updated_config.text and server.password == updated_config.password then
|
||||
server.name = fields[1]
|
||||
server.password = fields[2]
|
||||
cs_servers[i] = server
|
||||
break
|
||||
end
|
||||
end
|
||||
elseif item.type == "ftp" then
|
||||
for i, server in ipairs(cs_servers) do
|
||||
if server.name == updated_config.text and server.address == updated_config.address then
|
||||
server.name = fields[1]
|
||||
server.address = fields[2]
|
||||
server.username = fields[3]
|
||||
server.password = fields[4]
|
||||
cs_servers[i] = server
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
cs_settings:saveSetting("cs_servers", cs_servers)
|
||||
cs_settings:flush()
|
||||
self:init()
|
||||
end
|
||||
if item.type == "dropbox" then
|
||||
DropBox:config(item, callbackEdit)
|
||||
elseif item.type == "ftp" then
|
||||
Ftp:config(item, callbackEdit)
|
||||
end
|
||||
end
|
||||
|
||||
function CloudStorage:deleteCloudServer(item)
|
||||
local cs_settings = self:readSettings()
|
||||
local cs_servers = cs_settings:readSetting("cs_servers") or {}
|
||||
for i, server in ipairs(cs_servers) do
|
||||
if server.name == item.text and server.password == item.password and server.type == item.type then
|
||||
table.remove(cs_servers, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
cs_settings:saveSetting("cs_servers", cs_servers)
|
||||
cs_settings:flush()
|
||||
self:init()
|
||||
end
|
||||
|
||||
function CloudStorage:infoServer(item)
|
||||
if item.type == "dropbox" then
|
||||
DropBox:info(item.password)
|
||||
elseif item.type == "ftp" then
|
||||
Ftp:info(item)
|
||||
end
|
||||
end
|
||||
|
||||
function CloudStorage:readSettings()
|
||||
self.cs_settings = LuaSettings:open(DataStorage:getSettingsDir().."/cloudstorage.lua")
|
||||
return self.cs_settings
|
||||
end
|
||||
|
||||
function CloudStorage:onReturn()
|
||||
if #self.paths > 0 then
|
||||
table.remove(self.paths)
|
||||
local path = self.paths[#self.paths]
|
||||
if path then
|
||||
-- return to last path
|
||||
self:openCloudServer(path.url)
|
||||
else
|
||||
-- return to root path
|
||||
self:init()
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
return CloudStorage
|
@ -0,0 +1,129 @@
|
||||
local DropBoxApi = require("frontend/apps/cloudstorage/dropboxapi")
|
||||
local ConfirmBox = require("ui/widget/confirmbox")
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local MultiInputDialog = require("ui/widget/multiinputdialog")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local _ = require("gettext")
|
||||
local T = require("ffi/util").template
|
||||
local ReaderUI = require("apps/reader/readerui")
|
||||
local Screen = require("device").screen
|
||||
|
||||
local DropBox = {
|
||||
}
|
||||
|
||||
function DropBox:run(url, password)
|
||||
return DropBoxApi:listFolder(url, password)
|
||||
end
|
||||
|
||||
function DropBox:downloadFile(item, password, path, close)
|
||||
local code_response = DropBoxApi:downloadFile(item.url, password, path)
|
||||
if code_response == 200 then
|
||||
UIManager:show(ConfirmBox:new{
|
||||
text = T(_("File saved to:\n %1\nWould you like to read the downloaded book now?"),
|
||||
path),
|
||||
ok_callback = function()
|
||||
close()
|
||||
ReaderUI:showReader(path)
|
||||
end
|
||||
})
|
||||
else
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("Could not save file to:\n") .. path,
|
||||
timeout = 3,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
function DropBox:config(item, callback)
|
||||
local text_info = "How to generate Access Token:\n"..
|
||||
"1. Open the following URL in your Browser, and log in using your account: https://www.dropbox.com/developers/apps.\n"..
|
||||
"2. Click on >>Create App<<, then select >>Dropbox API app<<.\n"..
|
||||
"3. Now go on with the configuration, choosing the app permissions and access restrictions to your DropBox folder.\n"..
|
||||
"4. Enter the >>App Name<< that you prefer (e.g. KOReader).\n"..
|
||||
"5. Now, click on the >>Create App<< button.\n" ..
|
||||
"6. When your new App is successfully created, please click on the Generate button.\n"..
|
||||
"7. Under the 'Generated access token' section, then enter code in Dropbox token field."
|
||||
local hint_top = _("Your Dropbox name")
|
||||
local text_top = ""
|
||||
local hint_bottom = _("Dropbox token\n\n\n\n ")
|
||||
local text_bottom = ""
|
||||
local title
|
||||
local text_button_right = _("Add")
|
||||
if item then
|
||||
title = _("Edit Dropbox account")
|
||||
text_button_right = _("Apply")
|
||||
text_top = item.text
|
||||
text_bottom = item.password
|
||||
else
|
||||
title = _("Add Dropbox account")
|
||||
end
|
||||
self.settings_dialog = MultiInputDialog:new {
|
||||
title = title,
|
||||
fields = {
|
||||
{
|
||||
text = text_top,
|
||||
hint = hint_top ,
|
||||
},
|
||||
{
|
||||
text = text_bottom,
|
||||
hint = hint_bottom,
|
||||
scroll = false,
|
||||
},
|
||||
},
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
text = _("Cancel"),
|
||||
callback = function()
|
||||
self.settings_dialog:onClose()
|
||||
UIManager:close(self.settings_dialog)
|
||||
end
|
||||
},
|
||||
{
|
||||
text = _("Info"),
|
||||
callback = function()
|
||||
UIManager:show(InfoMessage:new{text = text_info })
|
||||
end
|
||||
},
|
||||
{
|
||||
text = text_button_right,
|
||||
callback = function()
|
||||
local fields = MultiInputDialog:getFields()
|
||||
if fields[1] ~= "" and fields[2] ~= "" then
|
||||
if item then
|
||||
--edit
|
||||
callback(item, fields)
|
||||
else
|
||||
-- add new
|
||||
callback(fields)
|
||||
end
|
||||
self.settings_dialog:onClose()
|
||||
UIManager:close(self.settings_dialog)
|
||||
else
|
||||
UIManager:show(InfoMessage:new{text = "Please fill in all fields." })
|
||||
end
|
||||
end
|
||||
},
|
||||
},
|
||||
},
|
||||
width = Screen:getWidth() * 0.95,
|
||||
height = Screen:getHeight() * 0.2,
|
||||
input_type = "text",
|
||||
}
|
||||
self.settings_dialog:onShowKeyboard()
|
||||
UIManager:show(self.settings_dialog)
|
||||
end
|
||||
|
||||
function DropBox:info(token)
|
||||
local info = DropBoxApi:fetchInfo(token)
|
||||
local info_text
|
||||
if info and info.name then
|
||||
info_text = T(_"Type: %1\nName: %2\nEmail: %3\nCounty: %4",
|
||||
"Dropbox",info.name.display_name, info.email, info.country)
|
||||
else
|
||||
info_text = _("No information available")
|
||||
end
|
||||
UIManager:show(InfoMessage:new{text = info_text})
|
||||
end
|
||||
|
||||
return DropBox
|
@ -0,0 +1,135 @@
|
||||
local url = require('socket.url')
|
||||
local socket = require('socket')
|
||||
local http = require('socket.http')
|
||||
local https = require('ssl.https')
|
||||
local ltn12 = require('ltn12')
|
||||
local _ = require("gettext")
|
||||
local JSON = require("json")
|
||||
local DocumentRegistry = require("document/documentregistry")
|
||||
|
||||
local DropBoxApi = {
|
||||
}
|
||||
|
||||
local API_URL_INFO = "https://api.dropboxapi.com/2/users/get_current_account"
|
||||
local API_LIST_FOLDER = "https://api.dropboxapi.com/2/files/list_folder"
|
||||
local API_DOWNLOAD_FILE = "https://content.dropboxapi.com/2/files/download"
|
||||
|
||||
function DropBoxApi:fetchInfo(token)
|
||||
local request, sink = {}, {}
|
||||
local parsed = url.parse(API_URL_INFO)
|
||||
request['url'] = API_URL_INFO
|
||||
request['method'] = 'POST'
|
||||
local headers = { ["Authorization"] = "Bearer ".. token }
|
||||
request['headers'] = headers
|
||||
request['sink'] = ltn12.sink.table(sink)
|
||||
http.TIMEOUT = 5
|
||||
https.TIMEOUT = 5
|
||||
local httpRequest = parsed.scheme == 'http' and http.request or https.request
|
||||
local headers_request = socket.skip(1, httpRequest(request))
|
||||
local result_response = table.concat(sink)
|
||||
if headers_request == nil then
|
||||
return nil
|
||||
end
|
||||
if result_response ~= "" then
|
||||
local _, result = pcall(JSON.decode, result_response)
|
||||
return result
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
function DropBoxApi:fetchListFolders(path, token)
|
||||
local request, sink = {}, {}
|
||||
if path == nil or path == "/" then path = "" end
|
||||
local parsed = url.parse(API_LIST_FOLDER)
|
||||
request['url'] = API_LIST_FOLDER
|
||||
request['method'] = 'POST'
|
||||
local data = "{\"path\": \"" .. path .. "\",\"recursive\": false,\"include_media_info\": false,"..
|
||||
"\"include_deleted\": false,\"include_has_explicit_shared_members\": false}"
|
||||
local headers = { ["Authorization"] = "Bearer ".. token,
|
||||
["Content-Type"] = "application/json" ,
|
||||
["Content-Length"] = #data}
|
||||
request['headers'] = headers
|
||||
request['source'] = ltn12.source.string(data)
|
||||
request['sink'] = ltn12.sink.table(sink)
|
||||
http.TIMEOUT = 5
|
||||
https.TIMEOUT = 5
|
||||
local httpRequest = parsed.scheme == 'http' and http.request or https.request
|
||||
local headers_request = socket.skip(1, httpRequest(request))
|
||||
if headers_request == nil then
|
||||
return nil
|
||||
end
|
||||
local result_response = table.concat(sink)
|
||||
if result_response ~= "" then
|
||||
local ret, result = pcall(JSON.decode, result_response)
|
||||
if ret then
|
||||
return result
|
||||
else
|
||||
return nil
|
||||
end
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
function DropBoxApi:downloadFile(path, token, local_path)
|
||||
local parsed = url.parse(API_DOWNLOAD_FILE)
|
||||
local url_api = API_DOWNLOAD_FILE
|
||||
local data1 = "{\"path\": \"" .. path .. "\"}"
|
||||
local headers = { ["Authorization"] = "Bearer ".. token,
|
||||
["Dropbox-API-Arg"] = data1}
|
||||
http.TIMEOUT = 5
|
||||
https.TIMEOUT = 5
|
||||
local httpRequest = parsed.scheme == 'http' and http.request or https.request
|
||||
local _, code_return, _ = httpRequest{
|
||||
url = url_api,
|
||||
method = 'GET',
|
||||
headers = headers,
|
||||
sink = ltn12.sink.file(io.open(local_path, "w"))
|
||||
}
|
||||
return code_return
|
||||
end
|
||||
|
||||
function DropBoxApi:listFolder(path, token)
|
||||
local dropbox_list = {}
|
||||
local dropbox_file = {}
|
||||
local tag, text
|
||||
local ls_dropbox = self:fetchListFolders(path, token)
|
||||
if ls_dropbox == nil then return false end
|
||||
for _, files in ipairs(ls_dropbox.entries) do
|
||||
text = files.name
|
||||
tag = files[".tag"]
|
||||
if tag == "folder" then
|
||||
text = text .. "/"
|
||||
table.insert(dropbox_list, {
|
||||
text = text,
|
||||
url = files.path_display,
|
||||
type = tag
|
||||
})
|
||||
--show only file with supported formats
|
||||
elseif tag == "file" and DocumentRegistry:getProvider(text) then
|
||||
table.insert(dropbox_file, {
|
||||
text = text,
|
||||
url = files.path_display,
|
||||
type = tag
|
||||
})
|
||||
end
|
||||
end
|
||||
--sort
|
||||
table.sort(dropbox_list, function(v1,v2)
|
||||
return v1.text < v2.text
|
||||
end)
|
||||
table.sort(dropbox_file, function(v1,v2)
|
||||
return v1.text < v2.text
|
||||
end)
|
||||
for _, files in ipairs(dropbox_file) do
|
||||
table.insert(dropbox_list, {
|
||||
text = files.text,
|
||||
url = files.url,
|
||||
type = files.type
|
||||
})
|
||||
end
|
||||
return dropbox_list
|
||||
end
|
||||
|
||||
return DropBoxApi
|
@ -0,0 +1,152 @@
|
||||
local FtpApi = require("frontend/apps/cloudstorage/ftpapi")
|
||||
local ConfirmBox = require("ui/widget/confirmbox")
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local MultiInputDialog = require("ui/widget/multiinputdialog")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local _ = require("gettext")
|
||||
local T = require("ffi/util").template
|
||||
local ReaderUI = require("apps/reader/readerui")
|
||||
local Screen = require("device").screen
|
||||
|
||||
local Ftp = {
|
||||
}
|
||||
local function generateUrl(address, user, pass)
|
||||
local colon_sign = ""
|
||||
local at_sign = ""
|
||||
if user ~= "" then
|
||||
at_sign = "@"
|
||||
end
|
||||
if pass ~= "" then
|
||||
colon_sign = ":"
|
||||
end
|
||||
local replace = "://" .. user .. colon_sign .. pass .. at_sign
|
||||
local url = string.gsub(address, "://", replace)
|
||||
return url
|
||||
end
|
||||
|
||||
function Ftp:run(address, user, pass, path)
|
||||
local url = generateUrl(address, user, pass) .. path
|
||||
return FtpApi:listFolder(url)
|
||||
end
|
||||
|
||||
function Ftp:downloadFile(item, address, user, pass, path, close)
|
||||
local url = generateUrl(address, user, pass) .. item.url
|
||||
local response = FtpApi:downloadFile(url)
|
||||
if response ~= nil then
|
||||
local file = io.open(path, "w")
|
||||
file:write(response)
|
||||
file:close()
|
||||
UIManager:show(ConfirmBox:new{
|
||||
text = T(_("File saved to:\n %1\nWould you like to read the downloaded book now?"),
|
||||
path),
|
||||
ok_callback = function()
|
||||
close()
|
||||
ReaderUI:showReader(path)
|
||||
end
|
||||
})
|
||||
else
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("Could not save file to:\n") .. path,
|
||||
timeout = 3,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
function Ftp:config(item, callback)
|
||||
local text_info = "FTP address must be in the format ftp://example.domian.com\n"..
|
||||
"Also supported is format with IP e.g: ftp://10.10.10.1\n"..
|
||||
"Username and password are optional."
|
||||
local hint_name = _("Your FTP name")
|
||||
local text_name = ""
|
||||
local hint_address = _("FTP address eg ftp://example.com")
|
||||
local text_address = ""
|
||||
local hint_username = _("FTP username")
|
||||
local text_username = ""
|
||||
local hint_password = _("FTP password")
|
||||
local text_password = ""
|
||||
local title
|
||||
local text_button_right = _("Add")
|
||||
if item then
|
||||
title = _("Edit FTP account")
|
||||
text_button_right = _("Apply")
|
||||
text_name = item.text
|
||||
text_address = item.address
|
||||
text_username = item.username
|
||||
text_password = item.password
|
||||
else
|
||||
title = _("Add FTP account")
|
||||
end
|
||||
self.settings_dialog = MultiInputDialog:new {
|
||||
title = title,
|
||||
fields = {
|
||||
{
|
||||
text = text_name,
|
||||
input_type = "string",
|
||||
hint = hint_name ,
|
||||
},
|
||||
{
|
||||
text = text_address,
|
||||
input_type = "string",
|
||||
hint = hint_address ,
|
||||
},
|
||||
{
|
||||
text = text_username,
|
||||
input_type = "string",
|
||||
hint = hint_username,
|
||||
},
|
||||
{
|
||||
text = text_password,
|
||||
input_type = "string",
|
||||
hint = hint_password,
|
||||
},
|
||||
},
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
text = _("Cancel"),
|
||||
callback = function()
|
||||
self.settings_dialog:onClose()
|
||||
UIManager:close(self.settings_dialog)
|
||||
end
|
||||
},
|
||||
{
|
||||
text = _("Info"),
|
||||
callback = function()
|
||||
UIManager:show(InfoMessage:new{text = text_info })
|
||||
end
|
||||
},
|
||||
{
|
||||
text = text_button_right,
|
||||
callback = function()
|
||||
local fields = MultiInputDialog:getFields()
|
||||
if fields[1] ~= "" and fields[2] ~= "" then
|
||||
if item then
|
||||
-- edit
|
||||
callback(item, fields)
|
||||
else
|
||||
-- add new
|
||||
callback(fields)
|
||||
end
|
||||
self.settings_dialog:onClose()
|
||||
UIManager:close(self.settings_dialog)
|
||||
else
|
||||
UIManager:show(InfoMessage:new{text = "Please fill in all fields." })
|
||||
end
|
||||
end
|
||||
},
|
||||
},
|
||||
},
|
||||
width = Screen:getWidth() * 0.95,
|
||||
height = Screen:getHeight() * 0.2,
|
||||
input_type = "text",
|
||||
}
|
||||
self.settings_dialog:onShowKeyboard()
|
||||
UIManager:show(self.settings_dialog)
|
||||
end
|
||||
|
||||
function Ftp:info(item)
|
||||
local info_text = T(_"Type: %1\nName: %2\nAddress: %3", "FTP", item.text, item.address)
|
||||
UIManager:show(InfoMessage:new{text = info_text})
|
||||
end
|
||||
|
||||
return Ftp
|
@ -0,0 +1,70 @@
|
||||
local ftp = require("socket.ftp")
|
||||
local ltn12 = require("ltn12")
|
||||
local url = require("socket.url")
|
||||
local DocumentRegistry = require("document/documentregistry")
|
||||
|
||||
local FtpApi = {
|
||||
}
|
||||
|
||||
function FtpApi:nlst(u)
|
||||
local t = {}
|
||||
local p = url.parse(u)
|
||||
p.command = "nlst"
|
||||
p.sink = ltn12.sink.table(t)
|
||||
local r, e = ftp.get(p)
|
||||
return r and table.concat(t), e
|
||||
end
|
||||
|
||||
function FtpApi:listFolder(address_path)
|
||||
local ftp_list = {}
|
||||
local ftp_file = {}
|
||||
local type
|
||||
local extension
|
||||
local file_name
|
||||
local ls_ftp = self:nlst(address_path)
|
||||
if ls_ftp == nil then return false end
|
||||
for item in (ls_ftp..'\n'):gmatch'(.-)\r?\n' do
|
||||
if item ~= '' then
|
||||
file_name = item:match("([^/]+)$")
|
||||
extension = item:match("^.+(%..+)$")
|
||||
item = "/" .. item
|
||||
if not extension then
|
||||
type = "folder"
|
||||
table.insert(ftp_list, {
|
||||
text = file_name .. "/",
|
||||
url = item,
|
||||
type = type,
|
||||
})
|
||||
--show only file with supported formats
|
||||
elseif extension and DocumentRegistry:getProvider(item) then
|
||||
type = "file"
|
||||
table.insert(ftp_file, {
|
||||
text = file_name,
|
||||
url = item,
|
||||
type = type,
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
--sort
|
||||
table.sort(ftp_list, function(v1,v2)
|
||||
return v1.text < v2.text
|
||||
end)
|
||||
table.sort(ftp_file, function(v1,v2)
|
||||
return v1.text < v2.text
|
||||
end)
|
||||
for _, files in ipairs(ftp_file) do
|
||||
table.insert(ftp_list, {
|
||||
text = files.text,
|
||||
url = files.url,
|
||||
type = files.type
|
||||
})
|
||||
end
|
||||
return ftp_list
|
||||
end
|
||||
|
||||
function FtpApi:downloadFile(file_path)
|
||||
return ftp.get(file_path ..";type=i")
|
||||
end
|
||||
|
||||
return FtpApi
|
Loading…
Reference in New Issue