mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
OPDS: raw server filenames for download (#13230)
This commit is contained in:
@@ -136,4 +136,40 @@ function socketutil.file_sink(handle, io_err)
|
||||
end
|
||||
end
|
||||
|
||||
function socketutil.redact_headers(headers)
|
||||
local sensitive_headers = {
|
||||
["authorization"] = true,
|
||||
["cookie"] = true,
|
||||
["proxy-authorization"] = true,
|
||||
["set-cookie"] = true,
|
||||
}
|
||||
local safe_headers = {}
|
||||
for key, value in pairs(headers) do
|
||||
if sensitive_headers[key] then
|
||||
safe_headers[key] = "REDACTED"
|
||||
else
|
||||
safe_headers[key] = value
|
||||
end
|
||||
end
|
||||
return safe_headers
|
||||
end
|
||||
|
||||
function socketutil.redact_request(request)
|
||||
local sensitive_props = {
|
||||
["password"] = true,
|
||||
["user"] = true,
|
||||
}
|
||||
local safe_request = {}
|
||||
for key, value in pairs(request) do
|
||||
if sensitive_props[key] then
|
||||
safe_request[key] = "REDACTED"
|
||||
elseif key == "headers" then
|
||||
safe_request[key] = socketutil.redact_headers(value)
|
||||
else
|
||||
safe_request[key] = value
|
||||
end
|
||||
end
|
||||
return safe_request
|
||||
end
|
||||
|
||||
return socketutil
|
||||
|
||||
@@ -464,7 +464,7 @@ function InputText:initTextBox(text, char_added)
|
||||
padding = self.padding,
|
||||
padding_top = 0,
|
||||
padding_bottom = 0,
|
||||
margin = self.margin,
|
||||
margin = self.margin + self.bordersize,
|
||||
self._check_button,
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
local BD = require("ui/bidi")
|
||||
local ButtonDialog = require("ui/widget/buttondialog")
|
||||
local Cache = require("cache")
|
||||
local CheckButton = require("ui/widget/checkbutton")
|
||||
local ConfirmBox = require("ui/widget/confirmbox")
|
||||
local DocumentRegistry = require("document/documentregistry")
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
@@ -98,6 +99,7 @@ function OPDSBrowser:genItemTableFromRoot()
|
||||
url = server.url,
|
||||
username = server.username,
|
||||
password = server.password,
|
||||
raw_names = server.raw_names, -- use server raw filenames for download
|
||||
searchable = server.url:match("%%s") and true or false,
|
||||
})
|
||||
end
|
||||
@@ -132,7 +134,7 @@ function OPDSBrowser:addEditCatalog(item)
|
||||
title = _("Add OPDS catalog")
|
||||
end
|
||||
|
||||
local dialog
|
||||
local dialog, check_button_raw_names
|
||||
dialog = MultiInputDialog:new{
|
||||
title = title,
|
||||
fields = fields,
|
||||
@@ -148,13 +150,21 @@ function OPDSBrowser:addEditCatalog(item)
|
||||
{
|
||||
text = _("Save"),
|
||||
callback = function()
|
||||
self:editCatalogFromInput(dialog:getFields(), item)
|
||||
local new_fields = dialog:getFields()
|
||||
new_fields[5] = check_button_raw_names.checked or nil
|
||||
self:editCatalogFromInput(new_fields, item)
|
||||
UIManager:close(dialog)
|
||||
end,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
check_button_raw_names = CheckButton:new{
|
||||
text = _("Use server filenames"),
|
||||
checked = item and item.raw_names,
|
||||
parent = dialog,
|
||||
}
|
||||
dialog:addWidget(check_button_raw_names)
|
||||
UIManager:show(dialog)
|
||||
dialog:onShowKeyboard()
|
||||
end
|
||||
@@ -181,7 +191,8 @@ function OPDSBrowser:addSubCatalog(item_url)
|
||||
local name = dialog:getInputText()
|
||||
if name ~= "" then
|
||||
UIManager:close(dialog)
|
||||
local fields = {name, item_url, self.root_catalog_username, self.root_catalog_password}
|
||||
local fields = {name, item_url,
|
||||
self.root_catalog_username, self.root_catalog_password, self.root_catalog_raw_names}
|
||||
self:editCatalogFromInput(fields, false, true) -- no init, stay in the subcatalog
|
||||
end
|
||||
end,
|
||||
@@ -206,10 +217,11 @@ function OPDSBrowser:editCatalogFromInput(fields, item, no_init)
|
||||
else -- add new
|
||||
new_server = {}
|
||||
end
|
||||
new_server.title = fields[1]
|
||||
new_server.url = fields[2]:match("^%a+://") and fields[2] or "http://" .. fields[2]
|
||||
new_server.username = fields[3] ~= "" and fields[3] or nil
|
||||
new_server.password = fields[4]
|
||||
new_server.title = fields[1]
|
||||
new_server.url = fields[2]:match("^%a+://") and fields[2] or "http://" .. fields[2]
|
||||
new_server.username = fields[3] ~= "" and fields[3] or nil
|
||||
new_server.password = fields[4]
|
||||
new_server.raw_names = fields[5]
|
||||
if not item then
|
||||
table.insert(self.opds_servers, new_server)
|
||||
end
|
||||
@@ -245,12 +257,12 @@ function OPDSBrowser:fetchFeed(item_url, headers_only)
|
||||
user = self.root_catalog_username,
|
||||
password = self.root_catalog_password,
|
||||
}
|
||||
logger.dbg("Request:", request)
|
||||
logger.dbg("Request:", socketutil.redact_request(request))
|
||||
local code, headers, status = socket.skip(1, http.request(request))
|
||||
socketutil:reset_timeout()
|
||||
|
||||
if headers_only then
|
||||
return headers and headers["last-modified"]
|
||||
return headers
|
||||
end
|
||||
if code == 200 then
|
||||
local xml = table.concat(sink)
|
||||
@@ -284,7 +296,8 @@ end
|
||||
|
||||
-- Parses feed to catalog
|
||||
function OPDSBrowser:parseFeed(item_url)
|
||||
local feed_last_modified = self:fetchFeed(item_url, true) -- headers only
|
||||
local headers = self:fetchFeed(item_url, true)
|
||||
local feed_last_modified = headers and headers["last-modified"]
|
||||
local feed
|
||||
if feed_last_modified then
|
||||
local hash = "opds|catalog|" .. item_url .. "|" .. feed_last_modified
|
||||
@@ -307,6 +320,21 @@ function OPDSBrowser:parseFeed(item_url)
|
||||
end
|
||||
end
|
||||
|
||||
function OPDSBrowser:getServerFileName(item_url)
|
||||
local headers = self:fetchFeed(item_url, true)
|
||||
if headers then
|
||||
logger.dbg("OPDSBrowser: server file headers", socketutil.redact_headers(headers))
|
||||
local header = headers["content-disposition"]
|
||||
if header then
|
||||
return header:match('filename="*([^"]+)"*')
|
||||
end
|
||||
header = headers["location"]
|
||||
if header then
|
||||
return header:gsub(".*/", "")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Generates link to search in catalog
|
||||
function OPDSBrowser:getSearchTemplate(osd_url)
|
||||
-- parse search descriptor
|
||||
@@ -563,10 +591,13 @@ function OPDSBrowser:showDownloads(item)
|
||||
filename = item.author .. " - " .. filename
|
||||
end
|
||||
local filename_orig = filename
|
||||
if self.root_catalog_raw_names then
|
||||
filename = nil
|
||||
end
|
||||
|
||||
local function createTitle(path, file) -- title for ButtonDialog
|
||||
return T(_("Download folder:\n%1\n\nDownload filename:\n%2\n\nDownload file type:"),
|
||||
BD.dirpath(path), file)
|
||||
BD.dirpath(path), file or _("<server filename>"))
|
||||
end
|
||||
|
||||
local buttons = {} -- buttons for ButtonDialog
|
||||
@@ -611,7 +642,9 @@ function OPDSBrowser:showDownloads(item)
|
||||
table.insert(download_buttons, {
|
||||
text = text .. "\u{2B07}", -- append DOWNWARDS BLACK ARROW
|
||||
callback = function()
|
||||
self:downloadFile(filename .. "." .. string.lower(filetype), acquisition.href)
|
||||
local file = filename and filename .. "." .. string.lower(filetype)
|
||||
or self:getServerFileName(acquisition.href)
|
||||
self:downloadFile(file, acquisition.href)
|
||||
UIManager:close(self.download_dialog)
|
||||
end,
|
||||
})
|
||||
@@ -656,7 +689,7 @@ function OPDSBrowser:showDownloads(item)
|
||||
local dialog
|
||||
dialog = InputDialog:new{
|
||||
title = _("Enter filename"),
|
||||
input = filename,
|
||||
input = filename or filename_orig,
|
||||
input_hint = filename_orig,
|
||||
buttons = {
|
||||
{
|
||||
@@ -802,9 +835,10 @@ function OPDSBrowser:onMenuSelect(item)
|
||||
self:showDownloads(item)
|
||||
else -- catalog or Search item
|
||||
if #self.paths == 0 then -- root list
|
||||
self.root_catalog_title = item.text
|
||||
self.root_catalog_username = item.username
|
||||
self.root_catalog_password = item.password
|
||||
self.root_catalog_title = item.text
|
||||
self.root_catalog_username = item.username
|
||||
self.root_catalog_password = item.password
|
||||
self.root_catalog_raw_names = item.raw_names
|
||||
end
|
||||
local connect_callback
|
||||
if item.searchable then
|
||||
@@ -831,13 +865,6 @@ function OPDSBrowser:onMenuHold(item)
|
||||
title_align = "center",
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
text = _("Edit"),
|
||||
callback = function()
|
||||
UIManager:close(dialog)
|
||||
self:addEditCatalog(item)
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Delete"),
|
||||
callback = function()
|
||||
@@ -851,6 +878,13 @@ function OPDSBrowser:onMenuHold(item)
|
||||
})
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Edit"),
|
||||
callback = function()
|
||||
UIManager:close(dialog)
|
||||
self:addEditCatalog(item)
|
||||
end,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user