mirror of
https://github.com/koreader/koreader
synced 2024-11-04 12:00:25 +00:00
bc0a55f093
Changed: - select multiple targets and export to them in a single click. - local targets (html, json and text) now are timestamped. Exporting booknotes on already exported documents will generate a new file with all the highlights present at export time. Previous files won't be deleted. Fixed: - chapters are now correctly represented in html output. - json issues when exporting the whole history. - joplin and readwise crashes when they're unable to reach the server - joplin update notes mechanism. - joplin is able to recreate the notebook if the user deletes or renames its current one. - highlights of read-only documents are also added when exporting the whole history (affects mostly android, might affect desktop targets) Co-authored-by: Utsob Roy <roy@utsob.me>
136 lines
4.5 KiB
Lua
136 lines
4.5 KiB
Lua
local InputDialog = require("ui/widget/inputdialog")
|
|
local UIManager = require("ui/uimanager")
|
|
local http = require("socket.http")
|
|
local json = require("json")
|
|
local logger = require("logger")
|
|
local ltn12 = require("ltn12")
|
|
local socket = require("socket")
|
|
local socketutil = require("socketutil")
|
|
local _ = require("gettext")
|
|
|
|
-- readwise exporter
|
|
local ReadwiseExporter = require("base"):new {
|
|
name = "readwise",
|
|
is_remote = true,
|
|
}
|
|
|
|
local function makeRequest(endpoint, method, request_body, token)
|
|
local sink = {}
|
|
local request_body_json = json.encode(request_body)
|
|
local source = ltn12.source.string(request_body_json)
|
|
socketutil:set_timeout(socketutil.LARGE_BLOCK_TIMEOUT, socketutil.LARGE_TOTAL_TIMEOUT)
|
|
local request = {
|
|
url = "https://readwise.io/api/v2/" .. endpoint,
|
|
method = method,
|
|
sink = ltn12.sink.table(sink),
|
|
source = source,
|
|
headers = {
|
|
["Content-Length"] = #request_body_json,
|
|
["Content-Type"] = "application/json",
|
|
["Authorization"] = "Token " .. token
|
|
},
|
|
}
|
|
local code, _, status = socket.skip(1, http.request(request))
|
|
socketutil:reset_timeout()
|
|
|
|
if code ~= 200 then
|
|
logger.warn("Readwise: HTTP response code <> 200. Response status: ", status)
|
|
return nil, status
|
|
end
|
|
|
|
local response = json.decode(sink[1])
|
|
return response
|
|
end
|
|
|
|
function ReadwiseExporter:isReadyToExport()
|
|
if self.settings.token then return true end
|
|
return false
|
|
end
|
|
|
|
function ReadwiseExporter:getMenuTable()
|
|
return {
|
|
text = _("Readwise"),
|
|
checked_func = function() return self:isEnabled() end,
|
|
sub_item_table = {
|
|
{
|
|
text = _("Set authorization token"),
|
|
keep_menu_open = true,
|
|
callback = function()
|
|
local auth_dialog
|
|
auth_dialog = InputDialog:new {
|
|
title = _("Set authorization token for Readwise"),
|
|
input = self.settings.token,
|
|
buttons = {
|
|
{
|
|
{
|
|
text = _("Cancel"),
|
|
callback = function()
|
|
UIManager:close(auth_dialog)
|
|
end
|
|
},
|
|
{
|
|
text = _("Set token"),
|
|
callback = function()
|
|
self.settings.token = auth_dialog:getInputText()
|
|
self:saveSettings()
|
|
UIManager:close(auth_dialog)
|
|
end
|
|
}
|
|
}
|
|
}
|
|
}
|
|
UIManager:show(auth_dialog)
|
|
auth_dialog:onShowKeyboard()
|
|
end
|
|
},
|
|
{
|
|
text = _("Export to Readwise"),
|
|
checked_func = function() return self:isEnabled() end,
|
|
callback = function() self:toggleEnabled() end,
|
|
},
|
|
|
|
}
|
|
}
|
|
end
|
|
|
|
function ReadwiseExporter:createHighlights(booknotes)
|
|
local highlights = {}
|
|
for _, chapter in ipairs(booknotes) do
|
|
for _, clipping in ipairs(chapter) do
|
|
local highlight = {
|
|
text = clipping.text,
|
|
title = booknotes.title,
|
|
author = booknotes.author ~= "" and booknotes.author or nil, -- optional author
|
|
source_type = "koreader",
|
|
category = "books",
|
|
note = clipping.note,
|
|
location = clipping.page,
|
|
location_type = "page",
|
|
highlighted_at = os.date("!%Y-%m-%dT%TZ", clipping.time),
|
|
}
|
|
table.insert(highlights, highlight)
|
|
end
|
|
end
|
|
|
|
local result, err = makeRequest("highlights", "POST", { highlights = highlights }, self.settings.token)
|
|
if not result then
|
|
logger.warn("error creating highlights", err)
|
|
return false
|
|
end
|
|
|
|
logger.dbg("createHighlights result", result)
|
|
return true
|
|
end
|
|
|
|
function ReadwiseExporter:export(t)
|
|
if not self:isReadyToExport() then return false end
|
|
|
|
for _, booknotes in ipairs(t) do
|
|
local ok = self:createHighlights(booknotes)
|
|
if not ok then return false end
|
|
end
|
|
return true
|
|
end
|
|
|
|
return ReadwiseExporter
|