2017-08-13 10:57:19 +00:00
|
|
|
local DocumentRegistry = require("document/documentregistry")
|
|
|
|
local JSON = require("json")
|
2021-03-15 00:25:10 +00:00
|
|
|
local http = require("socket.http")
|
2022-01-04 11:29:08 +00:00
|
|
|
local lfs = require("libs/libkoreader-lfs")
|
2021-05-05 18:44:44 +00:00
|
|
|
local logger = require("logger")
|
2021-03-15 00:25:10 +00:00
|
|
|
local ltn12 = require("ltn12")
|
|
|
|
local socket = require("socket")
|
|
|
|
local socketutil = require("socketutil")
|
2022-01-04 11:29:08 +00:00
|
|
|
local util = require("util")
|
|
|
|
local BaseUtil = require("ffi/util")
|
2016-12-20 07:34:00 +00:00
|
|
|
local _ = require("gettext")
|
|
|
|
|
|
|
|
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"
|
2022-01-04 11:29:08 +00:00
|
|
|
local API_UPLOAD_FILE = "https://content.dropboxapi.com/2/files/upload"
|
|
|
|
local API_CREATE_FOLDER = "https://api.dropboxapi.com/2/files/create_folder_v2"
|
2021-05-05 18:44:44 +00:00
|
|
|
local API_LIST_ADD_FOLDER = "https://api.dropboxapi.com/2/files/list_folder/continue"
|
2016-12-20 07:34:00 +00:00
|
|
|
|
|
|
|
function DropBoxApi:fetchInfo(token)
|
2021-03-15 00:25:10 +00:00
|
|
|
local sink = {}
|
|
|
|
socketutil:set_timeout()
|
|
|
|
local request = {
|
|
|
|
url = API_URL_INFO,
|
|
|
|
method = "POST",
|
|
|
|
headers = {
|
|
|
|
["Authorization"] = "Bearer " .. token,
|
|
|
|
},
|
|
|
|
sink = ltn12.sink.table(sink),
|
|
|
|
}
|
|
|
|
local headers_request = socket.skip(1, http.request(request))
|
|
|
|
socketutil:reset_timeout()
|
2016-12-20 07:34:00 +00:00
|
|
|
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)
|
|
|
|
if path == nil or path == "/" then path = "" end
|
|
|
|
local data = "{\"path\": \"" .. path .. "\",\"recursive\": false,\"include_media_info\": false,"..
|
|
|
|
"\"include_deleted\": false,\"include_has_explicit_shared_members\": false}"
|
2021-03-15 00:25:10 +00:00
|
|
|
local sink = {}
|
|
|
|
socketutil:set_timeout()
|
|
|
|
local request = {
|
|
|
|
url = API_LIST_FOLDER,
|
|
|
|
method = "POST",
|
|
|
|
headers = {
|
|
|
|
["Authorization"] = "Bearer ".. token,
|
|
|
|
["Content-Type"] = "application/json",
|
|
|
|
["Content-Length"] = #data,
|
|
|
|
},
|
|
|
|
source = ltn12.source.string(data),
|
|
|
|
sink = ltn12.sink.table(sink),
|
|
|
|
}
|
|
|
|
local headers_request = socket.skip(1, http.request(request))
|
|
|
|
socketutil:reset_timeout()
|
2016-12-20 07:34:00 +00:00
|
|
|
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
|
2021-05-05 18:44:44 +00:00
|
|
|
-- Check if more results, and then get them
|
|
|
|
if result.has_more then
|
|
|
|
logger.dbg("Found additional files")
|
|
|
|
result = self:fetchAdditionalFolders(result, token)
|
|
|
|
end
|
|
|
|
|
2016-12-20 07:34:00 +00:00
|
|
|
return result
|
|
|
|
else
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
else
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function DropBoxApi:downloadFile(path, token, local_path)
|
|
|
|
local data1 = "{\"path\": \"" .. path .. "\"}"
|
2021-03-15 00:25:10 +00:00
|
|
|
socketutil:set_timeout(socketutil.FILE_BLOCK_TIMEOUT, socketutil.FILE_TOTAL_TIMEOUT)
|
2021-06-12 19:11:53 +00:00
|
|
|
local code, _, status = socket.skip(1, http.request{
|
2021-03-15 00:25:10 +00:00
|
|
|
url = API_DOWNLOAD_FILE,
|
|
|
|
method = "GET",
|
|
|
|
headers = {
|
|
|
|
["Authorization"] = "Bearer ".. token,
|
|
|
|
["Dropbox-API-Arg"] = data1,
|
|
|
|
},
|
|
|
|
sink = ltn12.sink.file(io.open(local_path, "w")),
|
|
|
|
})
|
|
|
|
socketutil:reset_timeout()
|
2021-06-12 19:11:53 +00:00
|
|
|
if code ~= 200 then
|
|
|
|
logger.warn("DropBoxApi: Download failure:", status or code or "network unreachable")
|
|
|
|
end
|
|
|
|
return code
|
2016-12-20 07:34:00 +00:00
|
|
|
end
|
|
|
|
|
2022-01-04 11:29:08 +00:00
|
|
|
function DropBoxApi:uploadFile(path, token, file_path)
|
|
|
|
local data = "{\"path\": \"" .. path .. "/" .. BaseUtil.basename(file_path) ..
|
|
|
|
"\",\"mode\": \"add\",\"autorename\": true,\"mute\": false,\"strict_conflict\": false}"
|
|
|
|
socketutil:set_timeout(socketutil.FILE_BLOCK_TIMEOUT, socketutil.FILE_TOTAL_TIMEOUT)
|
|
|
|
local code, _, status = socket.skip(1, http.request{
|
|
|
|
url = API_UPLOAD_FILE,
|
|
|
|
method = "POST",
|
|
|
|
headers = {
|
|
|
|
["Authorization"] = "Bearer ".. token,
|
|
|
|
["Dropbox-API-Arg"] = data,
|
|
|
|
["Content-Type"] = "application/octet-stream",
|
|
|
|
["Content-Length"] = lfs.attributes(file_path, "size"),
|
|
|
|
},
|
|
|
|
source = ltn12.source.file(io.open(file_path, "r")),
|
|
|
|
})
|
|
|
|
socketutil:reset_timeout()
|
|
|
|
if code ~= 200 then
|
|
|
|
logger.warn("DropBoxApi: Upload failure:", status or code or "network unreachable")
|
|
|
|
end
|
|
|
|
return code
|
|
|
|
end
|
|
|
|
|
|
|
|
function DropBoxApi:createFolder(path, token, folder_name)
|
|
|
|
local data = "{\"path\": \"" .. path .. "/" .. folder_name .. "\",\"autorename\": false}"
|
|
|
|
socketutil:set_timeout()
|
|
|
|
local code, _, status = socket.skip(1, http.request{
|
|
|
|
url = API_CREATE_FOLDER,
|
|
|
|
method = "POST",
|
|
|
|
headers = {
|
|
|
|
["Authorization"] = "Bearer ".. token,
|
|
|
|
["Content-Type"] = "application/json",
|
|
|
|
["Content-Length"] = #data,
|
|
|
|
},
|
|
|
|
source = ltn12.source.string(data),
|
|
|
|
})
|
|
|
|
socketutil:reset_timeout()
|
|
|
|
if code ~= 200 then
|
|
|
|
logger.warn("DropBoxApi: Folder creation failure:", status or code or "network unreachable")
|
|
|
|
end
|
|
|
|
return code
|
|
|
|
end
|
|
|
|
|
2019-11-18 17:39:45 +00:00
|
|
|
-- folder_mode - set to true when we want to see only folder.
|
|
|
|
-- We see also extra folder "Long-press to select current directory" at the beginning.
|
|
|
|
function DropBoxApi:listFolder(path, token, folder_mode)
|
2016-12-20 07:34:00 +00:00
|
|
|
local dropbox_list = {}
|
|
|
|
local dropbox_file = {}
|
|
|
|
local tag, text
|
|
|
|
local ls_dropbox = self:fetchListFolders(path, token)
|
2017-08-13 10:57:19 +00:00
|
|
|
if ls_dropbox == nil or ls_dropbox.entries == nil then return false end
|
2016-12-20 07:34:00 +00:00
|
|
|
for _, files in ipairs(ls_dropbox.entries) do
|
|
|
|
text = files.name
|
|
|
|
tag = files[".tag"]
|
|
|
|
if tag == "folder" then
|
|
|
|
text = text .. "/"
|
2019-11-18 17:39:45 +00:00
|
|
|
if folder_mode then tag = "folder_long_press" end
|
2016-12-20 07:34:00 +00:00
|
|
|
table.insert(dropbox_list, {
|
|
|
|
text = text,
|
|
|
|
url = files.path_display,
|
2018-02-10 17:36:18 +00:00
|
|
|
type = tag,
|
2016-12-20 07:34:00 +00:00
|
|
|
})
|
|
|
|
--show only file with supported formats
|
2019-07-21 19:45:02 +00:00
|
|
|
elseif tag == "file" and (DocumentRegistry:hasProvider(text)
|
2019-11-18 17:39:45 +00:00
|
|
|
or G_reader_settings:isTrue("show_unsupported")) and not folder_mode then
|
2016-12-20 07:34:00 +00:00
|
|
|
table.insert(dropbox_file, {
|
|
|
|
text = text,
|
2022-01-04 11:29:08 +00:00
|
|
|
mandatory = util.getFriendlySize(files.size),
|
2016-12-20 07:34:00 +00:00
|
|
|
url = files.path_display,
|
2018-02-10 17:36:18 +00:00
|
|
|
type = tag,
|
2016-12-20 07:34:00 +00:00
|
|
|
})
|
|
|
|
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)
|
2019-11-18 17:39:45 +00:00
|
|
|
-- Add special folder.
|
|
|
|
if folder_mode then
|
|
|
|
table.insert(dropbox_list, 1, {
|
2021-08-24 20:19:07 +00:00
|
|
|
text = _("Long-press to choose current folder"),
|
2019-11-18 17:39:45 +00:00
|
|
|
url = path,
|
|
|
|
type = "folder_long_press",
|
|
|
|
})
|
|
|
|
end
|
2016-12-20 07:34:00 +00:00
|
|
|
for _, files in ipairs(dropbox_file) do
|
|
|
|
table.insert(dropbox_list, {
|
|
|
|
text = files.text,
|
2022-01-04 11:29:08 +00:00
|
|
|
mandatory = files.mandatory,
|
2016-12-20 07:34:00 +00:00
|
|
|
url = files.url,
|
2018-02-10 17:36:18 +00:00
|
|
|
type = files.type,
|
2016-12-20 07:34:00 +00:00
|
|
|
})
|
|
|
|
end
|
|
|
|
return dropbox_list
|
|
|
|
end
|
|
|
|
|
2019-11-18 17:39:45 +00:00
|
|
|
function DropBoxApi:showFiles(path, token)
|
|
|
|
local dropbox_files = {}
|
|
|
|
local tag, text
|
|
|
|
local ls_dropbox = self:fetchListFolders(path, token)
|
|
|
|
if ls_dropbox == nil or ls_dropbox.entries == nil then return false end
|
|
|
|
for _, files in ipairs(ls_dropbox.entries) do
|
|
|
|
text = files.name
|
|
|
|
tag = files[".tag"]
|
|
|
|
if tag == "file" and (DocumentRegistry:hasProvider(text) or G_reader_settings:isTrue("show_unsupported")) then
|
|
|
|
table.insert(dropbox_files, {
|
|
|
|
text = text,
|
|
|
|
url = files.path_display,
|
|
|
|
size = files.size,
|
|
|
|
})
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return dropbox_files
|
|
|
|
end
|
|
|
|
|
2021-05-05 18:44:44 +00:00
|
|
|
function DropBoxApi:fetchAdditionalFolders(response, token)
|
|
|
|
local out = response
|
|
|
|
local cursor = response.cursor
|
|
|
|
|
|
|
|
repeat
|
|
|
|
local data = "{\"cursor\": \"" .. cursor .. "\"}"
|
|
|
|
|
|
|
|
local sink = {}
|
|
|
|
socketutil:set_timeout()
|
|
|
|
local request = {
|
|
|
|
url = API_LIST_ADD_FOLDER,
|
|
|
|
method = "POST",
|
|
|
|
headers = {
|
|
|
|
["Authorization"] = "Bearer ".. token,
|
|
|
|
["Content-Type"] = "application/json",
|
|
|
|
["Content-Length"] = #data,
|
|
|
|
},
|
|
|
|
source = ltn12.source.string(data),
|
|
|
|
sink = ltn12.sink.table(sink),
|
|
|
|
}
|
|
|
|
local headers_request = socket.skip(1, http.request(request))
|
|
|
|
socketutil:reset_timeout()
|
|
|
|
if headers_request == nil then
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
|
|
|
|
local result_response = table.concat(sink)
|
|
|
|
local ret, result = pcall(JSON.decode, result_response)
|
|
|
|
|
|
|
|
if not ret then
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
|
|
|
|
for __, v in ipairs(result.entries) do
|
|
|
|
table.insert(out.entries, v)
|
|
|
|
end
|
|
|
|
|
|
|
|
if result.has_more then
|
|
|
|
cursor = result.cursor
|
|
|
|
end
|
|
|
|
until not result.has_more
|
|
|
|
|
|
|
|
return out
|
|
|
|
end
|
2016-12-20 07:34:00 +00:00
|
|
|
return DropBoxApi
|