mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
Merge branch 'koreader:master' into footer-no-doc-pos
This commit is contained in:
@@ -1388,7 +1388,7 @@ function FileManagerCollection:searchCollections(coll_name)
|
||||
-- Fortunately, this is run in a subprocess, so we won't be affecting the
|
||||
-- main process's crengine state or any document opened in the main
|
||||
-- process (we furthermore prevent this feature when one is opened).
|
||||
-- To avoid creating half-rendered/invalide cache files, it's best to disable
|
||||
-- To avoid creating half-rendered/invalid cache files, it's best to disable
|
||||
-- crengine saving of such cache files.
|
||||
if not self.is_cre_cache_disabled then
|
||||
local cre = require("document/credocument"):engineInit()
|
||||
|
||||
@@ -486,7 +486,7 @@ function Document:renderPage(pageno, rect, zoom, rotation, gamma, hinting)
|
||||
-- Make the context match the rotation,
|
||||
-- by pointing at the rotated origin via coordinates offsets.
|
||||
-- NOTE: We rotate our *Screen* bb on rotation (SetRotationMode), not the document,
|
||||
-- so we hardly ever exercize this codepath...
|
||||
-- so we hardly ever exercise this codepath...
|
||||
-- AFAICT, the only thing that *ever* (attempted to) rotate the document was ReaderRotation's key bindings (RotationUpdate).
|
||||
--- @note: It was broken as all hell (it had likely never worked outside of its original implementation in KPV), and has been removed in #12658
|
||||
if rotation == 90 then
|
||||
|
||||
@@ -297,7 +297,7 @@ function KoptInterface:reflowPage(doc, pageno, bbox, background)
|
||||
kc:setPreCache()
|
||||
self.bg_thread = true
|
||||
end
|
||||
-- Caculate zoom.
|
||||
-- Calculate zoom.
|
||||
kc.zoom = (1.5 * kc.zoom * kc.quality * kc.dev_width) / bbox.x1
|
||||
-- Generate pixmap.
|
||||
local page = doc._document:openPage(pageno)
|
||||
@@ -1433,7 +1433,7 @@ end
|
||||
local function get_pattern_list(pattern, case_insensitive)
|
||||
-- pattern list of single words
|
||||
local plist = {}
|
||||
-- (as in util.splitToWords(), but only splitting on spaces, keeping punctuations)
|
||||
-- (as in util.splitToWords(), but only splitting on spaces, keeping punctuation marks)
|
||||
for word in util.gsplit(pattern, "%s+") do
|
||||
if util.hasCJKChar(word) then
|
||||
for char in util.gsplit(word, "[\192-\255][\128-\191]+", true) do
|
||||
|
||||
@@ -618,7 +618,7 @@ function BookMapRow:paintTo(bb, x, y)
|
||||
alt_bb = glyph.bb:rotatedCopy(indicator.rotation)
|
||||
end
|
||||
-- Glyph's bb fit the blackbox of the glyph, so there's no cropping
|
||||
-- or complicated positionning to do
|
||||
-- or complicated positioning to do
|
||||
-- By default, just center the glyph at x
|
||||
local d_x_pct = indicator.shift_x_pct or 0.5
|
||||
local d_x = math.floor(glyph.bb:getWidth() * d_x_pct)
|
||||
@@ -759,7 +759,7 @@ function BookMapWidget:init()
|
||||
}
|
||||
end
|
||||
|
||||
-- No real need for any explicite edge and inter-row padding:
|
||||
-- No real need for any explicit edge and inter-row padding:
|
||||
-- we use the scrollbar width on both sides for balance (we may put a start
|
||||
-- page number on the left space), and each BookMapRow will have itself some
|
||||
-- blank space at bottom below page slots (where we may put hanging markers
|
||||
|
||||
@@ -643,7 +643,7 @@ function InputDialog:toggleKeyboard(force_toggle)
|
||||
-- Remember the *current* visibility, as the following close will reset it
|
||||
local visible = self:isKeyboardVisible()
|
||||
|
||||
-- When we forcibly close the keyboard, remember its current visiblity state, so that we can properly restore it later.
|
||||
-- When we forcibly close the keyboard, remember its current visibility state, so that we can properly restore it later.
|
||||
-- (This is used by some buttons in fullscreen mode, where we might want to keep the original keyboard hidden when popping up a new one for another InputDialog).
|
||||
if force_toggle == false then
|
||||
-- NOTE: visible will be nil between our own init and a show of the keyboard, which is precisely what happens when we *hide* the keyboard.
|
||||
|
||||
@@ -352,7 +352,7 @@ function AutoWarmth:scheduleMidnightUpdate(from_resume)
|
||||
self.current_times_h[1] = nil -- Solar midnight prev. day
|
||||
self.current_times_h[2] = nil -- Astronomical dawn
|
||||
self.current_times_h[3] = nil -- Nautical dawn
|
||||
self.current_times_h[6] = nil -- Solar noon
|
||||
-- self.current_times_h[6] = nil -- Solar noon
|
||||
self.current_times_h[9] = nil -- Nautical dusk
|
||||
self.current_times_h[10] = nil -- Astronomical dusk
|
||||
self.current_times_h[11] = nil -- Solar midnight
|
||||
@@ -642,7 +642,7 @@ function AutoWarmth:getSubMenuItems()
|
||||
return self.activate ~= 0
|
||||
end,
|
||||
text = Device:hasNaturalLight() and _("Warmth and night mode settings") or _("Night mode settings"),
|
||||
sub_item_table = self:getWarmthMenu(),
|
||||
sub_item_table_func = function() return self:getWarmthMenu() end,
|
||||
},
|
||||
self:getFlOffDuringDayMenu(),
|
||||
self:getTimesMenu(_("Currently active parameters")),
|
||||
@@ -1148,7 +1148,7 @@ function AutoWarmth:getWarmthMenu()
|
||||
text = Device:hasNaturalLight() and _("Set warmth and night mode for:") or _("Set night mode for:"),
|
||||
enabled = false,
|
||||
},
|
||||
getWarmthMenuEntry(_("Solar noon"), 6, false),
|
||||
getWarmthMenuEntry(_("Solar noon"), 6),
|
||||
getWarmthMenuEntry(_("Sunset and sunrise"), 5),
|
||||
getWarmthMenuEntry(_("Darkest time of civil twilight"), 4),
|
||||
getWarmthMenuEntry(_("Darkest time of nautical twilight"), 3, false),
|
||||
@@ -1247,7 +1247,7 @@ function AutoWarmth:showTimesInfo(title, location, activator, request_easy)
|
||||
local face = Font:getFace("scfont")
|
||||
UIManager:show(InfoMessage:new{
|
||||
face = face,
|
||||
width = math.floor(Screen:getWidth() * (self.easy_mode and 0.75 or 0.90)),
|
||||
width = math.floor(Screen:getWidth() * (self.easy_mode and 0.85 or 0.90)),
|
||||
text = title .. location_string .. ":\n\n" ..
|
||||
info_line(0, _("Solar midnight:"), times[1], 1, face, request_easy) ..
|
||||
add_line(2, _("Dawn"), request_easy) ..
|
||||
@@ -1258,8 +1258,8 @@ function AutoWarmth:showTimesInfo(title, location, activator, request_easy)
|
||||
add_line(2, _("Dawn"), request_easy) ..
|
||||
info_line(0, _("Sunrise:"), times[5], 5, face) ..
|
||||
"\n" ..
|
||||
info_line(0, _("Solar noon:"), times[6], 6, face, request_easy) ..
|
||||
add_line(0, "", request_easy) ..
|
||||
info_line(0, _("Solar noon:"), times[6], 6, face) ..
|
||||
"\n" ..
|
||||
info_line(0, _("Sunset:"), times[7], 7, face) ..
|
||||
add_line(2, _("Dusk"), request_easy) ..
|
||||
info_line(request_easy and 0 or 4,
|
||||
|
||||
@@ -18,6 +18,7 @@ local TextViewer = require("ui/widget/textviewer")
|
||||
local Trapper = require("ui/trapper")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local http = require("socket.http")
|
||||
local ffiUtil = require("ffi/util")
|
||||
local lfs = require("libs/libkoreader-lfs")
|
||||
local logger = require("logger")
|
||||
local ltn12 = require("ltn12")
|
||||
@@ -27,7 +28,7 @@ local url = require("socket.url")
|
||||
local util = require("util")
|
||||
local _ = require("gettext")
|
||||
local N_ = _.ngettext
|
||||
local T = require("ffi/util").template
|
||||
local T = ffiUtil.template
|
||||
|
||||
-- cache catalog parsed from feed xml
|
||||
local CatalogCache = Cache:new{
|
||||
@@ -42,6 +43,7 @@ local OPDSBrowser = Menu:extend{
|
||||
acquisition_rel = "^http://opds%-spec%.org/acquisition",
|
||||
borrow_rel = "http://opds-spec.org/acquisition/borrow",
|
||||
stream_rel = "http://vaemendis.net/opds-pse/stream",
|
||||
facet_rel = "http://opds-spec.org/facet",
|
||||
image_rel = {
|
||||
["http://opds-spec.org/image"] = true,
|
||||
["http://opds-spec.org/cover"] = true, -- ManyBooks.net, not in spec
|
||||
@@ -56,6 +58,7 @@ local OPDSBrowser = Menu:extend{
|
||||
root_catalog_title = nil,
|
||||
root_catalog_username = nil,
|
||||
root_catalog_password = nil,
|
||||
facet_groups = nil, -- Stores OPDS facet groups
|
||||
|
||||
title_shrink_font_to_fit = true,
|
||||
}
|
||||
@@ -67,6 +70,7 @@ function OPDSBrowser:init()
|
||||
self.onLeftButtonTap = function()
|
||||
self:showOPDSMenu()
|
||||
end
|
||||
self.facet_groups = nil -- Initialize facet groups storage
|
||||
Menu.init(self) -- call parent's init()
|
||||
end
|
||||
|
||||
@@ -135,6 +139,74 @@ function OPDSBrowser:showOPDSMenu()
|
||||
UIManager:show(dialog)
|
||||
end
|
||||
|
||||
-- Shows facet menu for OPDS catalogs with facets/search support
|
||||
function OPDSBrowser:showFacetMenu()
|
||||
local buttons = {}
|
||||
local dialog
|
||||
local catalog_url = self.paths[#self.paths].url
|
||||
|
||||
-- Add sub-catalog to bookmarks option first
|
||||
table.insert(buttons, {{
|
||||
text = "\u{f067} " .. _("Add catalog"),
|
||||
callback = function()
|
||||
UIManager:close(dialog)
|
||||
self:addSubCatalog(catalog_url)
|
||||
end,
|
||||
align = "left",
|
||||
}})
|
||||
table.insert(buttons, {}) -- separator
|
||||
|
||||
-- Add search option if available
|
||||
if self.search_url then
|
||||
table.insert(buttons, {{
|
||||
text = "\u{f002} " .. _("Search"),
|
||||
callback = function()
|
||||
UIManager:close(dialog)
|
||||
self:searchCatalog(self.search_url)
|
||||
end,
|
||||
align = "left",
|
||||
}})
|
||||
table.insert(buttons, {}) -- separator
|
||||
end
|
||||
|
||||
-- Add facet groups
|
||||
if self.facet_groups then
|
||||
for group_name, facets in ffiUtil.orderedPairs(self.facet_groups) do
|
||||
table.insert(buttons, {
|
||||
{ text = "\u{f0b0} " .. group_name, enabled = false, align = "left" }
|
||||
})
|
||||
|
||||
for __, link in ipairs(facets) do
|
||||
local facet_text = link.title
|
||||
if link["thr:count"] then
|
||||
facet_text = T(_("%1 (%2)"), facet_text, link["thr:count"])
|
||||
end
|
||||
if link["opds:activeFacet"] == "true" then
|
||||
facet_text = "✓ " .. facet_text
|
||||
end
|
||||
table.insert(buttons, {{
|
||||
text = facet_text,
|
||||
callback = function()
|
||||
UIManager:close(dialog)
|
||||
self:updateCatalog(url.absolute(catalog_url, link.href))
|
||||
end,
|
||||
align = "left",
|
||||
}})
|
||||
end
|
||||
table.insert(buttons, {}) -- separator between groups
|
||||
end
|
||||
end
|
||||
|
||||
dialog = ButtonDialog:new{
|
||||
buttons = buttons,
|
||||
shrink_unneeded_width = true,
|
||||
anchor = function()
|
||||
return self.title_bar.left_button.image.dimen
|
||||
end,
|
||||
}
|
||||
UIManager:show(dialog)
|
||||
end
|
||||
|
||||
|
||||
local function buildRootEntry(server)
|
||||
local icons = ""
|
||||
@@ -430,13 +502,18 @@ function OPDSBrowser:genItemTableFromURL(item_url)
|
||||
return self:genItemTableFromCatalog(catalog, item_url)
|
||||
end
|
||||
|
||||
-- Generates catalog item table and processes OPDS facets/search links
|
||||
function OPDSBrowser:genItemTableFromCatalog(catalog, item_url)
|
||||
local item_table = {}
|
||||
self.facet_groups = nil -- Reset facets
|
||||
self.search_url = nil -- Reset search URL
|
||||
|
||||
if not catalog then
|
||||
return item_table
|
||||
end
|
||||
|
||||
local feed = catalog.feed or catalog
|
||||
self.facet_groups = {} -- Initialize table to store facet groups
|
||||
|
||||
local function build_href(href)
|
||||
return url.absolute(item_url, href)
|
||||
@@ -456,24 +533,24 @@ function OPDSBrowser:genItemTableFromCatalog(catalog, item_url)
|
||||
-- OpenSearch
|
||||
if link.type:find(self.search_type) then
|
||||
if link.href then
|
||||
table.insert(item_table, { -- the first item in each subcatalog
|
||||
text = "\u{f002} " .. _("Search"), -- append SEARCH icon
|
||||
url = build_href(self:getSearchTemplate(build_href(link.href))),
|
||||
searchable = true,
|
||||
})
|
||||
self.search_url = build_href(self:getSearchTemplate(build_href(link.href)))
|
||||
has_opensearch = true
|
||||
end
|
||||
end
|
||||
-- Calibre search (also matches the actual template for OpenSearch!)
|
||||
if link.type:find(self.search_template_type) and link.rel and link.rel:find("search") then
|
||||
if link.href and not has_opensearch then
|
||||
table.insert(item_table, {
|
||||
text = "\u{f002} " .. _("Search"),
|
||||
url = build_href(link.href:gsub("{searchTerms}", "%%s")),
|
||||
searchable = true,
|
||||
})
|
||||
self.search_url = build_href(link.href:gsub("{searchTerms}", "%%s"))
|
||||
end
|
||||
end
|
||||
-- Process OPDS facets
|
||||
if link.rel == self.facet_rel then
|
||||
local group_name = link["opds:facetGroup"] or _("Filters")
|
||||
if not self.facet_groups[group_name] then
|
||||
self.facet_groups[group_name] = {}
|
||||
end
|
||||
table.insert(self.facet_groups[group_name], link)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -591,13 +668,16 @@ function OPDSBrowser:genItemTableFromCatalog(catalog, item_url)
|
||||
item.content = entry.content or entry.summary
|
||||
table.insert(item_table, item)
|
||||
end
|
||||
|
||||
if next(self.facet_groups) == nil then self.facet_groups = nil end -- Clear if empty
|
||||
|
||||
return item_table
|
||||
end
|
||||
|
||||
-- Requests and shows updated list of catalog entries
|
||||
function OPDSBrowser:updateCatalog(item_url, paths_updated)
|
||||
local menu_table = self:genItemTableFromURL(item_url)
|
||||
if #menu_table > 0 then
|
||||
if #menu_table > 0 or self.facet_groups or self.search_url then
|
||||
if not paths_updated then
|
||||
table.insert(self.paths, {
|
||||
url = item_url,
|
||||
@@ -605,10 +685,20 @@ function OPDSBrowser:updateCatalog(item_url, paths_updated)
|
||||
})
|
||||
end
|
||||
self:switchItemTable(self.catalog_title, menu_table)
|
||||
self:setTitleBarLeftIcon("plus")
|
||||
self.onLeftButtonTap = function()
|
||||
self:addSubCatalog(item_url)
|
||||
|
||||
-- Set appropriate title bar icon based on content
|
||||
if self.facet_groups or self.search_url then
|
||||
self:setTitleBarLeftIcon("appbar.menu")
|
||||
self.onLeftButtonTap = function()
|
||||
self:showFacetMenu()
|
||||
end
|
||||
else
|
||||
self:setTitleBarLeftIcon("plus")
|
||||
self.onLeftButtonTap = function()
|
||||
self:addSubCatalog(item_url)
|
||||
end
|
||||
end
|
||||
|
||||
if self.page_num <= 1 then
|
||||
-- Request more content, but don't change the page
|
||||
self:onNextPage(true)
|
||||
@@ -620,11 +710,8 @@ end
|
||||
function OPDSBrowser:appendCatalog(item_url)
|
||||
local menu_table = self:genItemTableFromURL(item_url)
|
||||
if #menu_table > 0 then
|
||||
for _, item in ipairs(menu_table) do
|
||||
-- Don't append multiple search entries
|
||||
if not item.searchable then
|
||||
table.insert(self.item_table, item)
|
||||
end
|
||||
for __, item in ipairs(menu_table) do
|
||||
table.insert(self.item_table, item)
|
||||
end
|
||||
self.item_table.hrefs = menu_table.hrefs
|
||||
self:switchItemTable(self.catalog_title, self.item_table, -1)
|
||||
|
||||
@@ -6,6 +6,7 @@ This plugin provides a terminal emulator (VT52 (+some ANSI and some VT100))
|
||||
|
||||
local Device = require("device")
|
||||
local logger = require("logger")
|
||||
local buffer = require("string.buffer")
|
||||
local util = require("util")
|
||||
local ffi = require("ffi")
|
||||
local C = ffi.C
|
||||
@@ -135,8 +136,7 @@ function Terminal:init()
|
||||
self:onDispatcherRegisterActions()
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
|
||||
self.chunk_size = CHUNK_SIZE
|
||||
self.chunk = ffi.new('uint8_t[?]', self.chunk_size)
|
||||
self.chunk = buffer.new(CHUNK_SIZE)
|
||||
|
||||
self.terminal_data = DataStorage:getDataDir()
|
||||
lfs.mkdir(self.terminal_data .. "/scripts")
|
||||
@@ -272,23 +272,21 @@ function Terminal:spawnShell(cols, rows)
|
||||
end
|
||||
|
||||
function Terminal:receive()
|
||||
local last_result = ""
|
||||
local ptr = self.chunk:reset():ref()
|
||||
local free = CHUNK_SIZE
|
||||
repeat
|
||||
C.tcdrain(self.ptmx)
|
||||
local count = tonumber(C.read(self.ptmx, self.chunk, self.chunk_size))
|
||||
if count > 0 then
|
||||
last_result = last_result .. string.sub(ffi.string(self.chunk), 1, count)
|
||||
local count = tonumber(C.read(self.ptmx, ptr, free))
|
||||
if count <= 0 then
|
||||
break
|
||||
end
|
||||
until count <= 0 or #last_result >= self.chunk_size - 1
|
||||
return last_result
|
||||
ptr = ptr + count
|
||||
free = free - count
|
||||
until free == 0
|
||||
return self.chunk:commit(CHUNK_SIZE - free):get()
|
||||
end
|
||||
|
||||
function Terminal:refresh(reset)
|
||||
if reset then
|
||||
self.refresh_time = 1/32
|
||||
UIManager:unschedule(Terminal.refresh)
|
||||
end
|
||||
|
||||
function Terminal:refresh()
|
||||
local next_text = self:receive()
|
||||
if next_text ~= "" then
|
||||
self.input_widget:interpretAnsiSeq(next_text)
|
||||
@@ -314,7 +312,11 @@ end
|
||||
|
||||
function Terminal:transmit(chars)
|
||||
C.write(self.ptmx, chars, #chars)
|
||||
self:refresh(true)
|
||||
self.refresh_time = 1/32
|
||||
UIManager:unschedule(Terminal.refresh)
|
||||
UIManager:tickAfterNext(function()
|
||||
UIManager:scheduleIn(self.refresh_time, Terminal.refresh, self)
|
||||
end)
|
||||
end
|
||||
|
||||
--- kills a running shell
|
||||
|
||||
@@ -186,6 +186,39 @@ One Thousand Mythological Characters Briefly Described
|
||||
</feed>
|
||||
]]
|
||||
|
||||
-- https://www.gutenberg.org/catalog/osd-books.xml
|
||||
local opensearch_sample = [[
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
|
||||
<LongName>Project Gutenberg</LongName>
|
||||
<ShortName>Gutenberg</ShortName>
|
||||
<Description>Search the Project Gutenberg ebook catalog.</Description>
|
||||
<Tags>free ebooks books public domain</Tags>
|
||||
<Developer>Marcello Perathoner</Developer>
|
||||
<Contact>webmaster@gutenberg.org</Contact>
|
||||
|
||||
<Url type="text/html"
|
||||
template="http://www.gutenberg.org/ebooks/search/?query={searchTerms}"/>
|
||||
|
||||
<Url type="application/atom+xml"
|
||||
template="http://m.gutenberg.org/ebooks/search.opds/?query={searchTerms}"/>
|
||||
|
||||
<Url type="application/x-suggestions+json"
|
||||
rel="suggestions"
|
||||
template="http://www.gutenberg.org/ebooks/suggest/?query={searchTerms}"/>
|
||||
|
||||
<Query role="example" searchTerms="shakespeare hamlet" />
|
||||
<Query role="example" searchTerms="doyle detective" />
|
||||
<Query role="example" searchTerms="love stories" />
|
||||
|
||||
<Attribution>Search Data Copyright 1971-2012, Project Gutenberg, All Rights Reserved.</Attribution>
|
||||
<SyndicationRight>open</SyndicationRight>
|
||||
<Language>en-us</Language>
|
||||
<OutputEncoding>UTF-8</OutputEncoding>
|
||||
<InputEncoding>UTF-8</InputEncoding>
|
||||
</OpenSearchDescription>
|
||||
]]
|
||||
|
||||
local popular_new_sample = [[
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xml:lang="en" xmlns:app="http://www.w3.org/2007/app" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:opds="http://opds-spec.org/2010/catalog">
|
||||
@@ -320,38 +353,70 @@ describe("OPDS module", function()
|
||||
end)
|
||||
|
||||
describe("OPDS browser module", function()
|
||||
before_each(function()
|
||||
local Cache = require("cache")
|
||||
stub(Cache, "check", function() return nil end)
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
local Cache = require("cache")
|
||||
if Cache.check.revert then
|
||||
Cache.check:revert()
|
||||
end
|
||||
end)
|
||||
|
||||
describe("URL generation", function()
|
||||
it("should generate search item #internet", function()
|
||||
local catalog = OPDSParser:parse(navigation_sample)
|
||||
local item_table = OPDSBrowser:genItemTableFromCatalog(catalog, "https://www.gutenberg.org/ebooks.opds/?format=opds")
|
||||
it("should generate search url and catalog items #internet", function()
|
||||
local fetch_feed_stub = stub(OPDSBrowser, "getSearchTemplate", function(self, osd_url)
|
||||
local search_descriptor = OPDSParser:parse(opensearch_sample)
|
||||
if search_descriptor and search_descriptor.OpenSearchDescription and search_descriptor.OpenSearchDescription.Url then
|
||||
for _, candidate in ipairs(search_descriptor.OpenSearchDescription.Url) do
|
||||
if candidate.type and candidate.template and candidate.type:find(self.search_template_type) then
|
||||
return candidate.template:gsub("{searchTerms}", "%%s")
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end)
|
||||
|
||||
local main_catalog = OPDSParser:parse(navigation_sample)
|
||||
local item_table = OPDSBrowser:genItemTableFromCatalog(main_catalog, "https://www.gutenberg.org/ebooks.opds/?format=opds")
|
||||
|
||||
assert.truthy(OPDSBrowser.search_url)
|
||||
assert.are.same("http://m.gutenberg.org/ebooks/search.opds/?query=%s", OPDSBrowser.search_url)
|
||||
|
||||
assert.truthy(item_table)
|
||||
assert.are.same(item_table[1].text, "\u{f002} " .. "Search")
|
||||
assert.are.same(3, #item_table)
|
||||
assert.are.same("Popular", item_table[1].title)
|
||||
assert.are.same("Latest", item_table[2].title)
|
||||
assert.are.same("Random", item_table[3].title)
|
||||
|
||||
fetch_feed_stub:revert()
|
||||
end)
|
||||
it("should generate URL on rel=subsection #internet", function()
|
||||
local catalog = OPDSParser:parse(navigation_sample)
|
||||
local item_table = OPDSBrowser:genItemTableFromCatalog(catalog, "https://www.gutenberg.org/ebooks.opds/?format=opds")
|
||||
|
||||
assert.truthy(item_table)
|
||||
assert.are.same(item_table[2].title, "Popular")
|
||||
assert.are.same(item_table[2].url, "https://www.gutenberg.org/ebooks/search.opds/?sort_order=downloads")
|
||||
assert.are.same(item_table[1].title, "Popular")
|
||||
assert.are.same(item_table[1].url, "https://www.gutenberg.org/ebooks/search.opds/?sort_order=downloads")
|
||||
end)
|
||||
it("should generate URL on rel=popular and rel=new #internet", function()
|
||||
local catalog = OPDSParser:parse(popular_new_sample)
|
||||
local item_table = OPDSBrowser:genItemTableFromCatalog(catalog, "http://www.feedbooks.com/publicdomain/catalog.atom")
|
||||
|
||||
assert.truthy(item_table)
|
||||
assert.are.same(item_table[2].title, "Most popular")
|
||||
assert.are.same(item_table[2].url, "https://catalog.feedbooks.com/publicdomain/browse/top.atom?lang=en")
|
||||
assert.are.same(item_table[3].title, "Recently added")
|
||||
assert.are.same(item_table[3].url, "https://catalog.feedbooks.com/publicdomain/browse/recent.atom?lang=en")
|
||||
assert.are.same(item_table[1].title, "Most popular")
|
||||
assert.are.same(item_table[1].url, "https://catalog.feedbooks.com/publicdomain/browse/top.atom?lang=en")
|
||||
assert.are.same(item_table[2].title, "Recently added")
|
||||
assert.are.same(item_table[2].url, "https://catalog.feedbooks.com/publicdomain/browse/recent.atom?lang=en")
|
||||
end)
|
||||
it("should use the main URL for faceted links as long as faceted links aren't properly supported #internet", function()
|
||||
local catalog = OPDSParser:parse(facet_sample)
|
||||
local item_table = OPDSBrowser:genItemTableFromCatalog(catalog, "http://flibusta.is/opds")
|
||||
|
||||
assert.truthy(item_table)
|
||||
assert.are.same(item_table[2].url, "http://flibusta.is/opds/author/75357")
|
||||
assert.are.same(item_table[1].url, "http://flibusta.is/opds/author/75357")
|
||||
end)
|
||||
end)
|
||||
|
||||
@@ -360,7 +425,7 @@ describe("OPDS module", function()
|
||||
local item_table = OPDSBrowser:genItemTableFromCatalog(catalog, "http://flibusta.is/opds")
|
||||
|
||||
assert.truthy(item_table)
|
||||
assert.are_not.same(item_table[2].image, "http://flibusta.is/opds/author/75357")
|
||||
assert.are_not.same(item_table[1].image, "http://flibusta.is/opds/author/75357")
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user