[plugin] Remove GoodReads plugin (#7943)

Deprecated half a year ago in <https://github.com/koreader/koreader/pull/7101>.

Any potential remaining users whose API key hasn't yet automatically expired through inactivity can copy it over from an older release if desired.

Discussed in <https://github.com/koreader/koreader/discussions/7898#discussioncomment-976475>.
pull/7958/head
Frans de Jonge 3 years ago committed by GitHub
parent 4d9d599a6a
commit f411035d7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -137,7 +137,6 @@ local order = {
"find_book_in_calibre_catalog",
"find_file",
"----------------------------",
"goodreads",
"opds",
},
main = {

@ -179,8 +179,6 @@ local order = {
"----------------------------",
"translation_settings",
"----------------------------",
"goodreads",
"----------------------------",
"find_book_in_calibre_catalog",
"fulltext_search",
},

@ -1,7 +0,0 @@
local _ = require("gettext")
return {
name = "goodreads",
fullname = _("Goodreads"),
description = _([[Allows browsing and searching the Goodreads database of books.]]),
deprecated = "The Goodreads API has been discontinued. Some keys might still work, but this plugin will be removed soon.",
}

@ -1,449 +0,0 @@
local BD = require("ui/bidi")
local Blitbuffer = require("ffi/blitbuffer")
local BottomContainer = require("ui/widget/container/bottomcontainer")
local Button = require("ui/widget/button")
local CloseButton = require("ui/widget/closebutton")
local DataStorage = require("datastorage")
local Device = require("device")
local Font = require("ui/font")
local FrameContainer = require("ui/widget/container/framecontainer")
local Geom = require("ui/geometry")
local GestureRange = require("ui/gesturerange")
local GoodreadsApi = require("goodreadsapi")
local HorizontalGroup = require("ui/widget/horizontalgroup")
local HorizontalSpan = require("ui/widget/horizontalspan")
local InfoMessage = require("ui/widget/infomessage")
local InputContainer = require("ui/widget/container/inputcontainer")
local LeftContainer = require("ui/widget/container/topcontainer")
local LineWidget = require("ui/widget/linewidget")
local LuaSettings = require("luasettings")
local OverlapGroup = require("ui/widget/overlapgroup")
local Size = require("ui/size")
local TextWidget = require("ui/widget/textwidget")
local UIManager = require("ui/uimanager")
local VerticalGroup = require("ui/widget/verticalgroup")
local VerticalSpan = require("ui/widget/verticalspan")
local _ = require("gettext")
local Input = Device.input
local Screen = Device.screen
local T = require("ffi/util").template
local DoubleKeyValueTitle = VerticalGroup:new{
kv_page = nil,
title = "",
tface = Font:getFace("tfont"),
align = "left",
use_top_page_count = false,
}
function DoubleKeyValueTitle:init()
self.close_button = CloseButton:new{ window = self }
local btn_width = self.close_button:getSize().w
-- title and close button
table.insert(self, OverlapGroup:new{
dimen = { w = self.width },
TextWidget:new{
text = self.title,
max_width = self.width - btn_width,
face = self.tface,
},
self.close_button,
})
-- page count and separation line
self.title_bottom = OverlapGroup:new{
dimen = { w = self.width, h = Screen:scaleBySize(2) },
LineWidget:new{
dimen = Geom:new{ w = self.width, h = Screen:scaleBySize(2) },
background = Blitbuffer.COLOR_DARK_GRAY,
style = "solid",
},
}
if self.use_top_page_count then
self.page_cnt = FrameContainer:new{
padding = Size.padding.default,
margin = 0,
bordersize = 0,
background = Blitbuffer.COLOR_WHITE,
-- overlap offset x will be updated in setPageCount method
overlap_offset = {0, -15},
TextWidget:new{
text = "", -- page count
fgcolor = Blitbuffer.COLOR_DARK_GRAY,
face = Font:getFace("smallffont"),
},
}
table.insert(self.title_bottom, self.page_cnt)
end
table.insert(self, self.title_bottom)
table.insert(self, VerticalSpan:new{ width = Screen:scaleBySize(5) })
end
function DoubleKeyValueTitle:setPageCount(curr, total)
if total == 1 then
-- remove page count if there is only one page
table.remove(self.title_bottom, 2)
return
end
self.page_cnt[1]:setText(curr .. "/" .. total)
self.page_cnt.overlap_offset[1] = (self.width - self.page_cnt:getSize().w - 10)
self.title_bottom[2] = self.page_cnt
end
function DoubleKeyValueTitle:onClose()
self.kv_page:onClose()
return true
end
local DoubleKeyValueItem = InputContainer:new{
key = nil,
value = nil,
cface_up = Font:getFace("smallinfofont"),
cface_down = Font:getFace("xx_smallinfofont"),
width = nil,
height = nil,
align = "left",
}
function DoubleKeyValueItem:init()
self.dimen = Geom:new{align = "left", w = self.width, h = self.height}
if self.callback and Device:isTouchDevice() then
self.ges_events.Tap = {
GestureRange:new{
ges = "tap",
range = self.dimen,
}
}
end
local padding = Screen:scaleBySize(20)
local max_width = self.width - 2*padding
local h = self.dimen.h / 2
local w = self.dimen.w
self[1] = FrameContainer:new{
padding = padding,
bordersize = 0,
width = self.width,
height = self.height,
VerticalGroup:new{
LeftContainer:new{
padding = 0,
dimen = Geom:new{ h = h, w = w },
TextWidget:new{
text = self.value,
max_width = max_width,
face = self.cface_up,
}
},
LeftContainer:new{
padding = 0,
dimen = Geom:new{ h = h, w = w },
TextWidget:new{
text = self.key,
max_width = max_width,
face = self.cface_down,
}
}
}
}
end
function DoubleKeyValueItem:onTap()
if self.callback then
local info = InfoMessage:new{text = _("Please wait…")}
UIManager:show(info)
if G_reader_settings:isFalse("flash_ui") then
UIManager:forceRePaint()
self.callback()
UIManager:close(info)
else
self[1].invert = true
UIManager:widgetRepaint(self[1], self[1].dimen.x, self[1].dimen.y)
UIManager:setDirty(nil, function()
return "fast", self[1].dimen
end)
UIManager:tickAfterNext(function()
self.callback()
UIManager:close(info)
self[1].invert = false
UIManager:widgetRepaint(self[1], self[1].dimen.x, self[1].dimen.y)
UIManager:setDirty(nil, function()
return "ui", self[1].dimen
end)
end)
end
end
return true
end
local DoubleKeyValuePage = InputContainer:new{
title = "",
width = nil,
height = nil,
show_page = 1,
use_top_page_count = false,
text_input = "",
pages = 1,
goodreads_key = "",
}
function DoubleKeyValuePage:readGRSettings()
self.gr_settings = LuaSettings:open(DataStorage:getSettingsDir().."/goodreadssettings.lua")
return self.gr_settings
end
function DoubleKeyValuePage:saveGRSettings(setting)
if not self.gr_settings then self:readGRSettings() end
self.gr_settings:saveSetting("goodreads", setting)
self.gr_settings:flush()
end
function DoubleKeyValuePage:init()
self.screen_width = Screen:getSize().w
self.screen_height = Screen:getSize().h
local gr_sett = self:readGRSettings().data
if gr_sett.goodreads then
self.goodreads_key = gr_sett.goodreads.key
self.goodreads_secret = gr_sett.goodreads.secret
end
self.kv_pairs = GoodreadsApi:showData(self.text_input, self.search_type, 1, self.goodreads_key)
self.total_res = GoodreadsApi:getTotalResults()
if self.total_res == nil then
self.total_res = 0
end
self.total_res = tonumber(self.total_res)
if self.kv_pairs == nil then
self.kv_pairs = {}
end
self.dimen = Geom:new{
w = self.width or self.screen_width,
h = self.height or self.screen_height,
}
if Device:hasKeys() then
self.key_events = {
Close = { {"Back"}, doc = "close page" },
NextPage = {{Input.group.PgFwd}, doc = "next page"},
PrevPage = {{Input.group.PgBack}, doc = "prev page"},
}
end
if Device:isTouchDevice() then
self.ges_events.Swipe = {
GestureRange:new{
ges = "swipe",
range = self.dimen,
}
}
end
self.page_info_text = Button:new{
text = "",
bordersize = 0,
margin = Screen:scaleBySize(20),
text_font_face = "pgfont",
text_font_bold = false,
}
-- group for page info
local chevron_left = "chevron.left"
local chevron_right = "chevron.right"
if BD.mirroredUILayout() then
chevron_left, chevron_right = chevron_right, chevron_left
end
self.page_info_left_chev = Button:new{
icon = chevron_left,
callback = function() self:prevPage() end,
bordersize = 0,
show_parent = self,
}
self.page_info_right_chev = Button:new{
icon = chevron_right,
callback = function() self:nextPage() end,
bordersize = 0,
show_parent = self,
}
self.page_info_spacer = HorizontalSpan:new{
width = Screen:scaleBySize(32),
}
self.page_info_left_chev:hide()
self.page_info_right_chev:hide()
self.page_info = HorizontalGroup:new{
self.page_info_left_chev,
self.page_info_text,
self.page_info_right_chev,
}
local footer = BottomContainer:new{
dimen = self.dimen:copy(),
self.page_info,
}
local padding = Screen:scaleBySize(10)
self.item_width = self.dimen.w - 2 * padding
self.item_height = Screen:scaleBySize(55)
-- setup title bar
self.title_bar = DoubleKeyValueTitle:new{
title = self.title,
width = self.item_width,
height = self.item_height,
use_top_page_count = self.use_top_page_count,
kv_page = self,
}
-- setup main content
self.item_margin = self.item_height / 6
local line_height = self.item_height + 2 * self.item_margin
local content_height = self.dimen.h - self.title_bar:getSize().h - self.page_info:getSize().h
self.max_loaded_pages = 1
self.items_per_page = math.floor(content_height / line_height)
self.pages = math.ceil(self.total_res / self.items_per_page)
self.main_content = VerticalGroup:new{}
self:_populateItems()
local content = OverlapGroup:new{
dimen = self.dimen:copy(),
VerticalGroup:new{
align = "left",
self.title_bar,
self.main_content,
},
footer,
}
-- assemble page
self[1] = FrameContainer:new{
height = self.dimen.h,
padding = padding,
bordersize = 0,
background = Blitbuffer.COLOR_WHITE,
content,
}
end
function DoubleKeyValuePage:nextPage()
local new_page = math.min(self.show_page + 1, self.pages)
if (new_page * self.items_per_page > #self.kv_pairs) and (self.max_loaded_pages < new_page)
and #self.kv_pairs < self.total_res then
local api_page = math.floor(new_page * self.items_per_page / 20 ) + 1
-- load new portion of data
local new_pair = GoodreadsApi:showData(self.text_input, self.search_type, api_page, self.goodreads_key )
if new_pair == nil then return end
for _, v in pairs(new_pair) do
table.insert(self.kv_pairs, v)
end
end
if new_page > self.show_page then
if self.max_loaded_pages == self.show_page then
self.max_loaded_pages = self.max_loaded_pages + 1
end
self.show_page = new_page
self:_populateItems()
end
end
function DoubleKeyValuePage:prevPage()
local new_page = math.max(self.show_page - 1, 1)
if new_page < self.show_page then
self.show_page = new_page
self:_populateItems()
end
end
-- make sure self.item_margin and self.item_height are set before calling this
function DoubleKeyValuePage:_populateItems()
self.page_info:resetLayout()
self.main_content:clear()
local idx_offset = (self.show_page - 1) * self.items_per_page
for idx = 1, self.items_per_page do
local entry = self.kv_pairs[idx_offset + idx]
if entry == nil then break end
table.insert(self.main_content,
VerticalSpan:new{ align = "left", width = self.item_margin })
if type(entry) == "table" then
table.insert(
self.main_content,
DoubleKeyValueItem:new{
height = self.item_height,
width = self.item_width,
key = entry[1],
value = entry[2],
align = "left",
callback = entry.callback,
show_parent = self,
}
)
elseif type(entry) == "string" then
local c = string.sub(entry, 1, 1)
if c == "-" then
table.insert(self.main_content, LineWidget:new{
background = Blitbuffer.COLOR_LIGHT_GRAY,
dimen = Geom:new{
w = self.item_width,
h = Screen:scaleBySize(2)
},
style = "solid",
})
end
end
table.insert(self.main_content,
VerticalSpan:new{ width = self.item_margin })
end
self.page_info_text:setText(T(_("Page %1 of %2"), self.show_page, self.pages))
self.page_info_left_chev:showHide(self.pages > 1)
self.page_info_right_chev:showHide(self.pages > 1)
self.page_info_left_chev:enableDisable(self.show_page > 1)
self.page_info_right_chev:enableDisable(self.show_page < self.pages)
UIManager:setDirty(self, function()
return "ui", self.dimen
end)
end
function DoubleKeyValuePage:_nextPage()
local new_page = math.min(self.show_page + 1, self.pages)
if (new_page * self.items_per_page > #self.kv_pairs) and (self.max_loaded_pages < new_page)
and #self.kv_pairs < self.total_res then
local info = InfoMessage:new{text = _("Please wait…")}
UIManager:show(info)
UIManager:forceRePaint()
self:nextPage()
UIManager:close(info)
else
self:nextPage()
end
end
function DoubleKeyValuePage:onNextPage()
self:_nextPage()
return true
end
function DoubleKeyValuePage:onPrevPage()
self:prevPage()
return true
end
function DoubleKeyValuePage:onSwipe(arg, ges_ev)
local direction = BD.flipDirectionIfMirroredUILayout(ges_ev.direction)
if direction == "west" then
self:_nextPage()
return true
elseif direction == "east" then
self:prevPage()
return true
elseif direction == "south" then
-- Allow easier closing with swipe down
self:onClose()
elseif direction == "north" then
-- no use for now
do end -- luacheck: ignore 541
else -- diagonal swipe
-- trigger full refresh
UIManager:setDirty(nil, "full")
-- a long diagonal swipe may also be used for taking a screenshot,
-- so let it propagate
return false
end
end
function DoubleKeyValuePage:onClose()
UIManager:close(self)
return true
end
return DoubleKeyValuePage

@ -1,190 +0,0 @@
local InputContainer = require("ui/widget/container/inputcontainer")
local GoodreadsBook = require("goodreadsbook")
local InfoMessage = require("ui/widget/infomessage")
local UIManager = require("ui/uimanager")
local http = require("socket.http")
local ltn12 = require("ltn12")
local socket = require("socket")
local socketutil = require("socketutil")
local _ = require("gettext")
local GoodreadsApi = InputContainer:new {
goodreads_key = "",
goodreads_secret = "",
total_result = 0,
}
function GoodreadsApi:init()
end
local function genSearchURL(text_search, userApi, search_type, npage)
if (text_search) then
text_search = string.gsub (text_search, "\n", "\r\n")
text_search = string.gsub (text_search, "([^%w %-%_%.%~])",
function (c) return string.format ("%%%02X", string.byte(c)) end)
text_search = string.gsub (text_search, " ", "+")
end
return (string.format(
"https://www.goodreads.com/search?q=%s&search[field]=%s&format=xml&key=%s&page=%s",
text_search,
search_type,
userApi,
npage
))
end
local function genIdUrl(id, userApi)
return (string.format(
"https://www.goodreads.com/book/show/%s?format=xml&key=%s",
id,
userApi
))
end
function GoodreadsApi:fetchXml(s_url)
local sink = {}
socketutil:set_timeout()
local request = {
url = s_url,
method = "GET",
sink = ltn12.sink.table(sink),
}
local headers = socket.skip(2, http.request(request))
socketutil:reset_timeout()
if headers == nil then
return nil
end
local xml = table.concat(sink)
if xml ~= "" then
return xml
end
end
function GoodreadsApi:showSearchTable(data)
local books = {}
if data == nil then
UIManager:show(InfoMessage:new{text =_("Network problem.\nCheck connection.")})
return books
end
self.total_result = data:match("<total[-]results>(.*)</total[-]results>")
for work in data:gmatch("<work>(.-)</work>") do
local book = work:match("<best_book[^>]+>(.*)</best_book>")
local id = book:match("<id[^>]+>([^<]+)</id>")
local title = book:match("<title>([^<]+)</title>"):gsub(" %(.*#%d+%)$", "")
local author = book:match("<name>([^<]+)</name>")
table.insert(books, {
author = author,
title = title,
id = id,
})
end
if #books == 0 then
UIManager:show(InfoMessage:new{text =_("Search not found!")})
end
return books
end
function GoodreadsApi:getTotalResults()
return self.total_result
end
local function showIdTable(data)
if data == nil then
UIManager:show(InfoMessage:new{text =_("Network problem.\nCheck connection.")})
return {}
end
local data1 = data:match("<book>(.*)</reviews_widget>")
local title_all = data1:match("<title>(.*)</title>"):gsub("<![[]CDATA[[]", ""):gsub("]]>$", "")
local title = title_all:gsub(" %(.*#%d+%)$", "")
local average_rating = data1:match("<average_rating>([^<]+)</average_rating>")
local series = title_all:match("%(.*#%d+%)$")
if series ~= nil then
series = series:match("[(](.*)[)]")
else
series = _("N/A")
end
local num_pages = data1:match("<num_pages>(.*)</num_pages>"):gsub("<![[]CDATA[[]", ""):gsub("]]>$", "")
if num_pages == nil or num_pages =="" then
num_pages = _("N/A")
end
local id = data1:match("<id>([^<]+)</id>"):gsub("<![[]CDATA[[]", ""):gsub("]]>$", "")
local author = data1:match("<name>([^<]+)</name>")
local description = data1:match("<description>(.*)</description>")
description = string.gsub(description, "<!%[CDATA%[(.*)%]%]>", "%1")
description = string.gsub(description, "%-%-", "%—")
--change format from medium to large
local image = data1:match("<image_url>([^<]+)</image_url>"):gsub("([0-9]+)m/", "%1l/")
local day = data1:match("<original_publication_day[^>]+>([^<]+)</original_publication_day>")
local month = data1:match("<original_publication_month[^>]+>([^<]+)</original_publication_month>")
local year = data1:match("<original_publication_year[^>]+>([^<]+)</original_publication_year>")
local release = {}
if (year) then
table.insert(release, year)
end
if (month) then
table.insert(release, string.format("%02d", month))
end
if (day) then
table.insert(release, string.format("%02d", day))
end
release = table.concat(release, "-")
if release == "" then
release = _("N/A")
end
local book_info = {
title = title,
author = author,
series = series,
rating = average_rating,
pages = num_pages,
release = release,
description = description,
image = image,
id = id,
}
if id == nil then
UIManager:show(InfoMessage:new{text = _("Search not found!")})
end
return book_info
end
-- search_type = all - search all
-- search_type = author - serch book by author
-- search_type = title - search book by title
function GoodreadsApi:showData(search_text, search_type, page, goodreads_key)
local stats = {}
local gen_url = genSearchURL(search_text, goodreads_key, search_type, page)
local gen_xml = self:fetchXml(gen_url)
local tbl = self:showSearchTable(gen_xml)
if #tbl == 0 then
return nil
end
for _, v in pairs(tbl) do
local author = v.author
local title = v.title
local id = v.id
table.insert(stats, { author,
title,
callback = function()
local dates = self:showIdData(id, goodreads_key)
if dates.id ~= nil then
UIManager:show(GoodreadsBook:new{
dates = dates,
})
end
end,
})
end
return stats
end
function GoodreadsApi:showIdData(id, goodreads_key)
local gen_url = genIdUrl(id, goodreads_key)
local gen_xml = self:fetchXml(gen_url)
local tbl = showIdTable(gen_xml)
return tbl
end
return GoodreadsApi

@ -1,267 +0,0 @@
local Blitbuffer = require("ffi/blitbuffer")
local CenterContainer = require("ui/widget/container/centercontainer")
local CloseButton = require("ui/widget/closebutton")
local FrameContainer = require("ui/widget/container/framecontainer")
local Geom = require("ui/geometry")
local Font = require("ui/font")
local HorizontalGroup = require("ui/widget/horizontalgroup")
local HorizontalSpan = require("ui/widget/horizontalspan")
local ImageWidget = require("ui/widget/imagewidget")
local InputContainer = require("ui/widget/container/inputcontainer")
local LeftContainer = require("ui/widget/container/leftcontainer")
local LineWidget = require("ui/widget/linewidget")
local OverlapGroup = require("ui/widget/overlapgroup")
local RenderImage = require("ui/renderimage")
local ScrollHtmlWidget = require("ui/widget/scrollhtmlwidget")
local Size = require("ui/size")
local TextBoxWidget = require("ui/widget/textboxwidget")
local TextWidget = require("ui/widget/textwidget")
local UIManager = require("ui/uimanager")
local VerticalGroup = require("ui/widget/verticalgroup")
local VerticalSpan = require("ui/widget/verticalspan")
local https = require("ssl.https")
local _ = require("gettext")
local Screen = require("device").screen
local T = require("ffi/util").template
local GoodreadsBook = InputContainer:new{
padding = Size.padding.fullscreen,
}
function GoodreadsBook:init()
self.small_font_face = Font:getFace("smallffont")
self.medium_font_face = Font:getFace("ffont")
self.large_font_face = Font:getFace("largeffont")
self.screen_width = Screen:getWidth()
self.screen_height = Screen:getHeight()
UIManager:setDirty(self, function()
return "ui", self.dimen
end)
self[1] = FrameContainer:new{
width = self.screen_width,
height = self.screen_height,
background = Blitbuffer.COLOR_WHITE,
bordersize = 0,
padding = 0,
self:getStatusContent(self.screen_width),
}
end
function GoodreadsBook:getStatusContent(width)
return VerticalGroup:new{
align = "left",
OverlapGroup:new{
dimen = Geom:new{ w = width, h = Size.item.height_default },
CloseButton:new{ window = self },
},
self:genHeader(_("Book info")),
self:genBookInfoGroup(),
self:genHeader(_("Review")),
self:bookReview(),
}
end
function GoodreadsBook:genHeader(title)
local header_title = TextWidget:new{
text = title,
face = self.medium_font_face,
fgcolor = Blitbuffer.COLOR_WEB_GRAY,
}
local padding_span = HorizontalSpan:new{ width = self.padding}
local line_width = (self.screen_width - header_title:getSize().w) / 2 - self.padding * 2
local line_container = LeftContainer:new{
dimen = Geom:new{ w = line_width, h = self.screen_height / 25 },
LineWidget:new{
background = Blitbuffer.COLOR_LIGHT_GRAY,
dimen = Geom:new{
w = line_width,
h = Size.line.thick,
}
}
}
return VerticalGroup:new{
VerticalSpan:new{ width = Size.span.vertical_large },
HorizontalGroup:new{
align = "center",
padding_span,
line_container,
padding_span,
header_title,
padding_span,
line_container,
padding_span,
},
VerticalSpan:new{ width = Size.span.vertical_large },
}
end
function GoodreadsBook:genBookInfoGroup()
local split_span_width = math.floor(self.screen_width * 0.05)
local img_width, img_height
if Screen:getScreenMode() == "landscape" then
img_width = Screen:scaleBySize(132)
img_height = Screen:scaleBySize(184)
else
img_width = Screen:scaleBySize(132 * 1.5)
img_height = Screen:scaleBySize(184 * 1.5)
end
local height = img_height
local width = self.screen_width - 1.5 * split_span_width - img_width
-- title
local book_meta_info_group = VerticalGroup:new{
align = "center",
TextBoxWidget:new{
text = self.dates.title,
face = self.medium_font_face,
padding = Size.padding.small,
alignment = "center",
width = width,
},
}
-- author
local text_author = TextBoxWidget:new{
text = self.dates.author,
width = width,
face = self.large_font_face,
alignment = "center",
}
table.insert(book_meta_info_group,
CenterContainer:new{
dimen = Geom:new{ w = width, h = text_author:getSize().h },
text_author
}
)
--span
local span_author = VerticalSpan:new{ width = math.floor(height * 0.1) }
table.insert(book_meta_info_group,
CenterContainer:new{
dimen = Geom:new{ w = width, h = Screen:scaleBySize(10) },
span_author
}
)
-- series
local text_series = TextWidget:new{
text = T(_("Series: %1"), self.dates.series),
face = self.small_font_face,
padding = Size.padding.small,
}
table.insert(book_meta_info_group,
CenterContainer:new{
dimen = Geom:new{ w = width, h = text_series:getSize().h },
text_series
}
)
-- rating
local text_rating = TextWidget:new{
text = T(_("Rating: %1"), self.dates.rating),
face = self.small_font_face,
padding = Size.padding.small,
}
table.insert(book_meta_info_group,
CenterContainer:new{
dimen = Geom:new{ w = width, h = text_rating:getSize().h },
text_rating
}
)
-- pages
local text_pages = TextWidget:new{
text = T(_("Pages: %1"), self.dates.pages),
face = self.small_font_face,
padding = Size.padding.small,
}
table.insert(book_meta_info_group,
CenterContainer:new{
dimen = Geom:new{ w = width, h = text_pages:getSize().h },
text_pages
}
)
-- relesse date
local text_release = TextWidget:new{
text = T(_("Release date: %1"), self.dates.release),
face = self.small_font_face,
padding = Size.padding.small,
}
table.insert(book_meta_info_group,
CenterContainer:new{
dimen = Geom:new{ w = width, h = text_release:getSize().h },
text_release
}
)
local book_info_group = HorizontalGroup:new{
align = "top",
HorizontalSpan:new{ width = split_span_width }
}
-- thumbnail
local body = https.request(self.dates.image)
local bb_image
if body then bb_image = RenderImage:renderImageData(body, #body, false, img_width, img_height) end
if bb_image then
table.insert(book_info_group, ImageWidget:new{
image = bb_image,
})
else
table.insert(book_info_group, ImageWidget:new{
file = "plugins/goodreads.koplugin/goodreadsnophoto.png",
width = img_width,
height = img_height,
})
end
local book_info_group_span = HorizontalGroup:new{
align = "top",
HorizontalSpan:new{ width = split_span_width / 2 }
}
table.insert(book_info_group, book_info_group_span)
table.insert(book_info_group, CenterContainer:new{
dimen = Geom:new{ w = width , h = height },
book_meta_info_group,
})
return CenterContainer:new{
dimen = Geom:new{ w = self.screen_width, h = math.floor(self.screen_height * 0.35) },
book_info_group,
}
end
function GoodreadsBook:bookReview()
local css = [[
@page {
margin: 0;
font-family: 'Noto Sans';
}
body {
margin: 0;
line-height: 1.3;
text-align: justify;
}
]]
local book_meta_info_group = VerticalGroup:new{
align = "center",
padding = 0,
bordersize = 0,
ScrollHtmlWidget:new{
html_body = self.dates.description,
css = css,
width = math.floor(self.screen_width * 0.9),
height = math.floor(self.screen_height * 0.48),
dialog = self,
}
}
return CenterContainer:new{
dimen = Geom:new{ w = self.screen_width, h = math.floor(self.screen_height * 0.5) },
book_meta_info_group,
}
end
function GoodreadsBook:onAnyKeyPressed()
return self:onClose()
end
function GoodreadsBook:onClose()
UIManager:close(self, "flashui")
return true
end
return GoodreadsBook

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

@ -1,240 +0,0 @@
local InputContainer = require("ui/widget/container/inputcontainer")
local InputDialog = require("ui/widget/inputdialog")
local DoubleKeyValuePage = require("doublekeyvaluepage")
local MultiInputDialog = require("ui/widget/multiinputdialog")
local InfoMessage = require("ui/widget/infomessage")
local UIManager = require("ui/uimanager")
local Screen = require("device").screen
local _ = require("gettext")
local NetworkMgr = require("ui/network/manager")
local Goodreads = InputContainer:new {
name = "goodreads",
goodreads_key = "",
goodreads_secret = "",
}
function Goodreads:init()
local gr_sett = DoubleKeyValuePage:readGRSettings().data
if gr_sett.goodreads then
self.goodreads_key = gr_sett.goodreads.key
self.goodreads_secret = gr_sett.goodreads.secret
end
self.ui.menu:registerToMainMenu(self)
end
function Goodreads:addToMainMenu(menu_items)
menu_items.goodreads = {
text = _("Goodreads"),
sub_item_table = {
{
text = _("Settings"),
keep_menu_open = true,
callback = function() self:updateSettings() end,
},
{
text = _("Search all books"),
keep_menu_open = true,
callback = function(touchmenu_instance)
if self.goodreads_key ~= "" then
touchmenu_instance:closeMenu()
self:search("all")
else
UIManager:show(InfoMessage:new{
text = _("Please set up your Goodreads key in the settings dialog"),
})
end
end,
},
{
text = _("Search for book by title"),
keep_menu_open = true,
callback = function(touchmenu_instance)
if self.goodreads_key ~= "" then
touchmenu_instance:closeMenu()
self:search("title")
else
UIManager:show(InfoMessage:new{
text = _("Please set up your Goodreads key in the settings dialog"),
})
end
end,
},
{
text = _("Search for book by author"),
keep_menu_open = true,
callback = function(touchmenu_instance)
if self.goodreads_key ~= "" then
touchmenu_instance:closeMenu()
self:search("author")
else
UIManager:show(InfoMessage:new{
text = _("Please set up your Goodreads key in the settings dialog"),
})
end
end,
},
},
}
end
function Goodreads:updateSettings()
local hint_top
local text_top
local hint_bottom
local text_bottom
local text_info = _([[
How to generate a key and a secret key:
1. Go to https://www.goodreads.com/user/sign_up and create an account
2. Create a key and secret key on https://www.goodreads.com/api/keys
3. Enter your generated key and your secret key in the settings dialog (Login to Goodreads window)
]])
if self.goodreads_key == "" then
hint_top = _("Goodreads key left empty")
text_top = ""
else
hint_top = ""
text_top = self.goodreads_key
end
if self.goodreads_secret == "" then
hint_bottom = _("Goodreads secret left empty (optional)")
text_bottom = ""
else
hint_bottom = ""
text_bottom = self.goodreads_key
end
self.settings_dialog = MultiInputDialog:new {
title = _("Login to Goodreads"),
fields = {
{
text = text_top,
input_type = "string",
hint = hint_top ,
},
{
text = text_bottom,
input_type = "string",
hint = hint_bottom,
},
},
buttons = {
{
{
text = _("Cancel"),
callback = function()
self.settings_dialog:onClose()
UIManager:close(self.settings_dialog)
end
},
{
text = _("Info"),
callback = function()
UIManager:show(InfoMessage:new{text = text_info })
end
},
{
text = _("Apply"),
callback = function()
self:saveSettings(MultiInputDialog:getFields())
self.settings_dialog:onClose()
UIManager:close(self.settings_dialog)
end
},
},
},
width = math.floor(Screen:getWidth() * 0.95),
height = math.floor(Screen:getHeight() * 0.2),
input_type = "text",
}
UIManager:show(self.settings_dialog)
self.settings_dialog:onShowKeyboard()
end
function Goodreads:saveSettings(fields)
if fields then
self.goodreads_key = fields[1]
self.goodreads_secret = fields[2]
end
local settings = {
key = self.goodreads_key,
secret = self.goodreads_secret,
}
DoubleKeyValuePage:saveGRSettings(settings)
end
-- search_type = all - search all
-- search_type = author - serch book by author
-- search_type = title - search book by title
function Goodreads:search(search_type)
if NetworkMgr:willRerunWhenOnline(function() self:search(search_type) end) then
return
end
local title_header
local hint
local search_input
local text_input
local info
local result
if search_type == "all" then
title_header = _("Search all books in Goodreads")
hint = _("Title, author or ISBN")
elseif search_type == "author" then
title_header = _("Search for book by author in Goodreads")
hint = _("Author")
elseif search_type == "title" then
title_header = _("Search for book by title in Goodreads")
hint = _("Title")
end
search_input = InputDialog:new{
title = title_header,
input = "",
input_hint = hint,
input_type = "string",
buttons = {
{
{
text = _("Cancel"),
callback = function()
UIManager:close(search_input)
end,
},
{
text = _("Find"),
is_enter_default = true,
callback = function()
text_input = search_input:getInputText()
if text_input ~= nil and text_input ~= "" then
info = InfoMessage:new{text = _("Please wait…")}
UIManager:close(search_input)
UIManager:show(info)
UIManager:forceRePaint()
result = DoubleKeyValuePage:new{
title = _("Select book"),
text_input = text_input,
search_type = search_type,
}
if #result.kv_pairs > 0 then
UIManager:show(result)
end
UIManager:close(info)
else
UIManager:show(InfoMessage:new{
text =_("Please enter text"),
})
end
end,
},
}
},
}
UIManager:show(search_input)
search_input:onShowKeyboard()
end
return Goodreads
Loading…
Cancel
Save