OPDS: raw server filenames for download (#13230)
Some checks are pending
macos / macOS 13 x86-64 🔨15.2 🎯10.15 (push) Waiting to run
macos / macOS 14 ARM64 🔨15.4 🎯11.0 (push) Waiting to run

This commit is contained in:
hius07
2025-02-11 14:10:57 +02:00
committed by GitHub
parent 48471eaa24
commit 41dd3d5d8a
3 changed files with 94 additions and 24 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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,
},
},
},
}