Dictionary and wikipedia enhancements (#2393)

Stardict:
- remove duplicate results
- better cleaning of selection
- append results from a 2nd query of a 2nd set of dictionaries
  in data/dict_ext/

Wikipedia:
- use the search API for better results
- allow viewing the full page content of a result in a bigger window
- allow queries for multiple languages
- available languages can be set in settings.reader.lua :
    ["wikipedia_languages"] = {"en", "fr", "it"}
- "Wikipedia lookup" added to Tools menu

For both:
- allow selection of multiple words for a new lookup (so one can
  actually browse wikipedia)
- allow continuous reading with Tap
- display "current result / total number of results"

Details in #2393
pull/2419/head
poire-z 8 years ago committed by Qingping Hou
parent 5040bfe4c5
commit 1708fd5e1c

@ -7,12 +7,14 @@ local Screen = require("device").screen
local Device = require("device")
local JSON = require("json")
local DEBUG = require("dbg")
local util = require("util")
local _ = require("gettext")
local T = require("ffi/util").template
local ReaderDictionary = InputContainer:new{
data_dir = nil,
dict_window_list = {},
lookup_msg = _("Searching dictionary for:\n%1")
}
function ReaderDictionary:init()
@ -40,7 +42,7 @@ function ReaderDictionary:onLookupWord(word, box, highlight)
return true
end
local function tidy_markup(results)
local function tidyMarkup(results)
local cdata_tag = "<!%[CDATA%[(.-)%]%]>"
local format_escape = "&[29Ib%+]{(.-)}"
for _, result in ipairs(results) do
@ -64,20 +66,97 @@ local function tidy_markup(results)
return results
end
function ReaderDictionary:cleanSelection(text)
-- Will be used by ReaderWikipedia too
if not text then
return ""
end
-- We do multiple times the same replacements, which is most of the time overkill,
-- but sometimes provices better cleaning
-- Some extremes cases to explain the multiples gsub :
--
-- Sample epub html: mais, qu« absolument, on ne peut décidément pas » revenir en arrière
-- Holding on "qu" or "absolument" will make crengine returns: qu« absolument,
-- We want to only get: absolument
--
-- Sample epub html: car « létat, actuel, de notre connaissance » sy oppose
-- Holding on "état" will make crengine returns: « létat,
-- We want to get: état
--
-- Some of these gsub could be removed when crengine does a better job
-- at finding word boundaries
--
-- Strip some quotations marks
text = string.gsub(text, "\xC2\xAB", '') -- U+00AB << (left double angle quotation mark)
text = string.gsub(text, "\xC2\xBB", '') -- U+00BB >> (right double angle quotation mark)
text = string.gsub(text, "\xE2\x80\x9D", '') -- U+201D '' (right double quotation mark)
text = string.gsub(text, "\xE2\x80\x9C", '') -- U+201C `` (left double quotation mark)
text = string.gsub(text, "\xE2\x80\x94", '') -- U+2014 - (em dash)
text = string.gsub(text, "\xE2\x80\x95", '') -- U+2015 - (horizontal bar)
text = string.gsub(text, "\xC2\xA0", '') -- U+00A0 no-break space
-- Replace some meaningful quotes with ascii quote
text = string.gsub(text, "\xE2\x80\x99", "'") -- U+2019 (right single quotation mark)
-- Strip punctuation characters around selection
-- (this had to be done after the utf8 gsubs above, or it would strip part of these utf8 chars)
text = util.stripePunctuations(text)
-- Strip leading and trailing spaces
text = string.gsub(text, "^%s+", '')
text = string.gsub(text, "%s+$", '')
-- Strip some french grammatical constructs
text = string.gsub(text, "^[LSDMNTlsdmnt]'", '') -- french l' s' t'
text = string.gsub(text, "^[Qq][Uu]'", '') -- french qu'
-- Strip again leading and trailing spaces
text = string.gsub(text, "^%s+", '')
text = string.gsub(text, "%s+$", '')
return text
end
function ReaderDictionary:onLookupStarted(word)
local text = T(self.lookup_msg, word)
self.lookup_progress_msg = InfoMessage:new{text=text}
UIManager:show(self.lookup_progress_msg)
UIManager:forceRePaint()
end
function ReaderDictionary:onLookupDone()
if self.lookup_progress_msg then
UIManager:close(self.lookup_progress_msg)
UIManager:forceRePaint()
end
self.lookup_progress_msg = nil
end
function ReaderDictionary:stardictLookup(word, box)
DEBUG("lookup word:", word, box)
if word then
word = require("util").stripePunctuations(word)
DEBUG("stripped word:", word)
-- escape quotes and other funny characters in word
-- escape quotes and other funny characters in word
word = self:cleanSelection(word)
DEBUG("stripped word:", word)
if word == "" then
return
end
self:onLookupStarted(word)
local final_results = {}
local seen_results = {}
-- Allow for two sdcv calls : one in the classic data/dict, and
-- another one in data/dict_ext if it exists
-- We could put in data/dict_ext dictionaries with a great number of words
-- but poor definitions as a fall back. If these were in data/dict,
-- they would prevent fuzzy searches in other dictories with better
-- definitions, and masks such results. This way, we can get both.
local dict_dirs = {self.data_dir}
local dict_ext = self.data_dir.."_ext"
if lfs.attributes(dict_ext, "mode") == "directory" then
table.insert(dict_dirs, dict_ext)
end
for _, dict_dir in ipairs(dict_dirs) do
local results_str = nil
if Device:isAndroid() then
local A = require("android")
results_str = A.stdout("./sdcv", "--utf8-input", "--utf8-output",
"-nj", word, "--data-dir", self.data_dir)
"-nj", word, "--data-dir", dict_dir)
else
local std_out = io.popen("./sdcv --utf8-input --utf8-output -nj "
.. ("%q"):format(word) .. " --data-dir " .. self.data_dir, "r")
.. ("%q"):format(word) .. " --data-dir " .. dict_dir, "r")
if std_out then
results_str = std_out:read("*all")
std_out:close()
@ -86,21 +165,33 @@ function ReaderDictionary:stardictLookup(word, box)
--DEBUG("result str:", word, results_str)
local ok, results = pcall(JSON.decode, results_str)
if ok and results then
--DEBUG("lookup result table:", word, results)
self:showDict(word, tidy_markup(results), box)
-- we may get duplicates (sdcv may do multiple queries,
-- in fixed mode then in fuzzy mode), we have to remove them
local h
for _,r in ipairs(results) do
h = r.dict .. r.word .. r.definition
if seen_results[h] == nil then
table.insert(final_results, r)
seen_results[h] = true
end
end
else
DEBUG("JSON data cannot be decoded", results)
-- dummy results
results = {
{
dict = "",
word = word,
definition = _("No definition found."),
}
}
self:showDict(word, results, box)
end
end
if #final_results == 0 then
-- dummy results
final_results = {
{
dict = "",
word = word,
definition = _("No definition found."),
}
}
end
self:onLookupDone()
--DEBUG("lookup result table:", word, final_results)
self:showDict(word, tidyMarkup(final_results), box)
end
function ReaderDictionary:showDict(word, results, box)
@ -118,7 +209,8 @@ function ReaderDictionary:showDict(word, results, box)
width = Screen:getWidth() - Screen:scaleBySize(80),
word_box = box,
-- differentiate between dict and wiki
wiki = self.wiki,
is_wiki = self.is_wiki,
wiki_languages = self.wiki_languages,
}
table.insert(self.dict_window_list, self.dict_window)
UIManager:show(self.dict_window)

@ -494,8 +494,7 @@ function ReaderHighlight:onHighlightDictLookup()
DEBUG("dictionary lookup highlight")
self:highlightFromHoldPos()
if self.selected_text then
local text = require("util").stripePunctuations(self.selected_text.text)
self.ui:handleEvent(Event:new("LookupWord", text))
self.ui:handleEvent(Event:new("LookupWord", self.selected_text.text))
end
end

@ -3,65 +3,147 @@ local Translator = require("ui/translator")
local Wikipedia = require("ui/wikipedia")
local DEBUG = require("dbg")
local _ = require("gettext")
local T = require("ffi/util").template
-- Wikipedia as a special dictionary
local ReaderWikipedia = ReaderDictionary:extend{
-- identify itself
wiki = true,
is_wiki = true,
wiki_languages = {},
no_page = _("No wiki page found."),
lookup_msg = _("Searching Wikipedia for:\n%1")
}
-- the super "class" ReaderDictionary has already registers a menu entry
-- we should override the init function in ReaderWikipedia
function ReaderWikipedia:init()
self.ui.menu:registerToMainMenu(self)
end
function ReaderWikipedia:onLookupWikipedia(word, box)
-- set language from book properties
local lang = self.view.document:getProps().language
if lang == nil then
-- or set laguage from KOReader settings
lang = G_reader_settings:readSetting("language")
if lang == nil then
-- or detect language
local ok_translator
function ReaderWikipedia:addToMainMenu(tab_item_table)
table.insert(tab_item_table.plugins, {
text = _("Wikipedia lookup"),
tap_input = {
title = _("Enter words to look up on Wikipedia"),
type = "text",
callback = function(input)
self:onLookupWikipedia(input)
end,
},
})
end
function ReaderWikipedia:initLanguages(word)
if #self.wiki_languages > 0 then -- already done
return
end
-- Fill self.wiki_languages with languages to propose
local wikipedia_languages = G_reader_settings:readSetting("wikipedia_languages")
if type(wikipedia_languages) == "table" and #wikipedia_languages > 0 then
-- use this setting, no need to guess
self.wiki_languages = wikipedia_languages
else
-- guess some languages
self.seen_lang = {}
local addLanguage = function(lang)
if lang and lang ~= "" then
-- convert "zh-CN" and "zh-TW" to "zh"
lang = lang:match("(.*)-") or lang
if lang == "C" then lang="en" end
lang = lang:lower()
if not self.seen_lang[lang] then
table.insert(self.wiki_languages, lang)
self.seen_lang[lang] = true
end
end
end
-- use book and UI languages
addLanguage(self.view.document:getProps().language)
addLanguage(G_reader_settings:readSetting("language"))
if #self.wiki_languages == 0 and word then
-- if no language at all, do a translation of selected word
local ok_translator, lang
ok_translator, lang = pcall(Translator.detect, Translator, word)
if not ok_translator then return end
if ok_translator then
addLanguage(lang)
end
end
-- add english anyway, so we have at least one language
addLanguage("en")
end
end
function ReaderWikipedia:onLookupWikipedia(word, box, get_fullpage)
-- word is the text to query. If get_fullpage is true, it is the
-- exact wikipedia page title we want the full page of.
self:initLanguages(word)
-- use first lang from self.wiki_languages, which may have been rotated by DictQuickLookup
local lang = self.wiki_languages[1]
DEBUG("lookup word:", word, box, get_fullpage)
-- no need to clean word if get_fullpage, as it is the exact wikipetia page title
if word and not get_fullpage then
-- escape quotes and other funny characters in word
word = self:cleanSelection(word)
-- no need to lower() word with wikipedia search
end
DEBUG("stripped word:", word)
if word == "" then
return
end
-- convert "zh-CN" and "zh-TW" to "zh"
lang = lang:match("(.*)-") or lang
-- strip punctuation characters around selected word
word = string.gsub(word, "^%p+", '')
word = string.gsub(word, "%p+$", '')
-- seems lower case phrase has higher hit rate
word = string.lower(word)
self:onLookupStarted(word)
local results = {}
local ok, pages = pcall(Wikipedia.wikintro, Wikipedia, word, lang)
local ok, pages
if get_fullpage then
ok, pages = pcall(Wikipedia.wikifull, Wikipedia, word, lang)
else
ok, pages = pcall(Wikipedia.wikintro, Wikipedia, word, lang)
end
if ok and pages then
-- sort pages according to 'index' attribute if present (not present
-- in fullpage results)
local sorted_pages = {}
local has_indexes = false
for pageid, page in pairs(pages) do
if page.index ~= nil then
sorted_pages[page.index+1] = page
has_indexes = true
end
end
if has_indexes then
pages = sorted_pages
end
for pageid, page in pairs(pages) do
local definition = page.extract or self.no_page
if page.length then
-- we get 'length' only for intro results
-- let's append it to definition so we know
-- how big/valuable the full page is
local fullkb = math.ceil(page.length/1024)
local more_factor = math.ceil( page.length / (1+definition:len()) ) -- +1 just in case len()=0
definition = definition .. "\n" .. T(_("(full page : %1 kB, = %2 x this intro length)"), fullkb, more_factor)
end
local result = {
dict = _("Wikipedia"),
dict = T(_("Wikipedia %1"), lang:upper()),
word = page.title,
definition = page.extract or self.no_page,
definition = definition,
is_fullpage = get_fullpage,
}
table.insert(results, result)
end
DEBUG("lookup result:", word, results)
self:showDict(word, results, box)
else
DEBUG("error:", pages)
-- dummy results
results = {
{
dict = _("Wikipedia"),
dict = T(_("Wikipedia %1"), lang:upper()),
word = word,
definition = self.no_page,
is_fullpage = get_fullpage,
}
}
DEBUG("dummy result table:", word, results)
self:showDict(word, results, box)
end
self:onLookupDone()
self:showDict(word, results, box)
end
-- override onSaveSettings in ReaderDictionary

@ -21,6 +21,7 @@ local Event = require("ui/event")
local Font = require("ui/font")
local DEBUG = require("dbg")
local _ = require("gettext")
local T = require("ffi/util").template
local Blitbuffer = require("ffi/blitbuffer")
--[[
@ -31,9 +32,11 @@ local DictQuickLookup = InputContainer:new{
lookupword = nil,
dictionary = nil,
definition = nil,
displayword = nil,
is_wiki = false,
is_fullpage = false,
dict_index = 1,
title_face = Font:getFace("tfont", 22),
word_face = Font:getFace("tfont", 22),
content_face = Font:getFace("cfont", DDICT_FONT_SIZE),
width = nil,
height = nil,
@ -44,6 +47,9 @@ local DictQuickLookup = InputContainer:new{
title_margin = Screen:scaleBySize(2),
word_padding = Screen:scaleBySize(5),
word_margin = Screen:scaleBySize(2),
-- alt padding/margin for wiki to compensate for reduced font size
wiki_word_padding = Screen:scaleBySize(7),
wiki_word_margin = Screen:scaleBySize(3),
definition_padding = Screen:scaleBySize(2),
definition_margin = Screen:scaleBySize(2),
button_padding = Screen:scaleBySize(14),
@ -78,67 +84,134 @@ function DictQuickLookup:init()
}
},
},
HoldWord = {
-- This was for selection of a single word with simple hold
-- HoldWord = {
-- GestureRange:new{
-- ges = "hold",
-- range = function()
-- return self.region
-- end,
-- },
-- -- callback function when HoldWord is handled as args
-- args = function(word)
-- self.ui:handleEvent(
-- -- don't pass self.highlight to subsequent lookup, we want
-- -- the first to be the only one to unhighlight selection
-- -- when closed
-- Event:new("LookupWord", word, self.word_box))
-- end
-- },
-- Allow selection of one or more words (see textboxwidget.lua) :
HoldStartText = {
GestureRange:new{
ges = "hold",
range = function()
return self.region
end,
},
-- callback function when HoldWord is handled as args
args = function(word)
},
HoldReleaseText = {
GestureRange:new{
ges = "hold_release",
range = function()
return self.region
end,
},
-- callback function when HoldReleaseText is handled as args
args = function(text, hold_duration)
local lookup_target
if hold_duration < 2.0 then
-- do this lookup in the same domain (dict/wikipedia)
lookup_target = self.is_wiki and "LookupWikipedia" or "LookupWord"
else
-- but allow switching domain with a long hold
lookup_target = self.is_wiki and "LookupWord" or "LookupWikipedia"
end
self.ui:handleEvent(
Event:new("LookupWord", word, self.word_box, self.highlight))
-- don't pass self.highlight to subsequent lookup, we want
-- the first to be the only one to unhighlight selection
-- when closed
Event:new(lookup_target, text)
)
end
},
}
table.insert(self.dict_bar,
CloseButton:new{ window = self, })
end
end
function DictQuickLookup:update()
local orig_dimen = self.dict_frame and self.dict_frame.dimen or Geom:new{}
-- calculate window dimension and try to not hide highlighted word
-- calculate window dimension
self.align = "center"
self.region = Geom:new{
x = 0, y = 0,
w = Screen:getWidth(),
h = Screen:getHeight(),
}
if self.word_box then
local box = self.word_box
if box.y + box.h/2 < Screen:getHeight()*0.3 then
self.region.y = box.y + box.h
self.region.h = Screen:getHeight() - box.y - box.h
self.align = "top"
elseif box.y + box.h/2 > Screen:getHeight()*0.7 then
self.region.y = 0
self.region.h = box.y
self.align = "bottom"
if self.is_fullpage then
-- bigger window if fullpage being shown - this will let
-- some room anyway for footer display (time, battery...)
self.height = Screen:getHeight()
self.width = Screen:getWidth() - Screen:scaleBySize(40)
else
-- smaller window otherwise
-- try to not hide highlighted word
if self.word_box then
local box = self.word_box
if box.y + box.h/2 < Screen:getHeight()*0.3 then
self.region.y = box.y + box.h
self.region.h = Screen:getHeight() - box.y - box.h
self.align = "top"
elseif box.y + box.h/2 > Screen:getHeight()*0.7 then
self.region.y = 0
self.region.h = box.y
self.align = "bottom"
end
end
self.height = math.min(self.region.h*0.7, Screen:getHeight()*0.5)
end
self.height = math.min(self.region.h*0.7, Screen:getHeight()*0.5)
-- dictionary title
local dict_title_text = TextWidget:new{
text = self.dictionary,
face = self.title_face,
bold = true,
width = self.width,
}
-- Some different UI tweaks for dict or wiki
local lookup_word_font_size, lookup_word_padding, lookup_word_margin
if self.is_wiki then
-- visual hint : dictionary title left adjusted, Wikipedia title centered
dict_title_text = CenterContainer:new{
dimen = Geom:new{
w = self.width,
h = dict_title_text:getSize().h,
},
dict_title_text
}
-- Wikipedia has longer titles, so use a smaller font
lookup_word_font_size = 18
lookup_word_padding = self.wiki_word_padding
lookup_word_margin = self.wiki_word_margin
else
-- Usual font size for dictionary
lookup_word_font_size = 22
lookup_word_padding = self.word_padding
lookup_word_margin = self.word_margin
end
self.dict_title = FrameContainer:new{
padding = self.title_padding,
margin = self.title_margin,
bordersize = 0,
TextWidget:new{
text = self.dictionary,
face = self.title_face,
bold = true,
width = self.width,
}
dict_title_text
}
-- lookup word
local lookup_word = Button:new{
padding = self.word_padding,
margin = self.word_margin,
padding = lookup_word_padding,
margin = lookup_word_margin,
bordersize = 0,
text = self.lookupword,
text = self.displayword,
text_font_face = "tfont",
text_font_size = 22,
text_font_size = lookup_word_font_size,
hold_callback = function() self:lookupInputWord(self.lookupword) end,
}
-- word definition
@ -150,14 +223,27 @@ function DictQuickLookup:update()
text = self.definition,
face = self.content_face,
width = self.width,
height = self.height*0.7,
-- get a bit more height for definition as wiki has one less button raw
height = self.is_fullpage and self.height*0.75 or self.height*0.7,
dialog = self,
},
}
local button_table = ButtonTable:new{
width = math.max(self.width, definition:getSize().w),
button_font_face = "cfont",
button_font_size = 20,
-- Different sets of buttons if fullpage or not
local buttons
if self.is_fullpage then
-- Only a single wide close button, get a little more room for
-- closing by taping at bottom (on footer or on this button)
buttons = {
{
{
text = "Close",
callback = function()
UIManager:close(self)
end,
},
},
}
else
buttons = {
{
{
@ -185,30 +271,48 @@ function DictQuickLookup:update()
},
{
{
text = _("Wikipedia"),
enabled = not self.wiki,
-- if dictionary result, do the same search on wikipedia
-- if already wiki, get the full page for the current result
text = self.is_wiki and _("Wikipedia full") or _("Wikipedia"),
callback = function()
UIManager:scheduleIn(0.1, function()
self:lookupWikipedia()
self:lookupWikipedia(self.is_wiki) -- will get_fullpage if is_wiki
end)
end,
},
-- Rotate thru available wikipedia languages (disabled if dictionary window)
-- (replace previous unimplemented "Add Note")
{
text = _("Add Note"),
enabled = false,
-- if more than one language, enable it and display "current lang > next lang"
-- otherwise, just display current lang
text = self.is_wiki and ( #self.wiki_languages > 1 and self.wiki_languages[1].." > "..self.wiki_languages[2] or self.wiki_languages[1] ) or "-",
enabled = self.is_wiki and #self.wiki_languages > 1,
callback = function()
self.ui:handleEvent(Event:new("HighlightAddNote"))
-- rotate wiki_languages
local current_lang = table.remove(self.wiki_languages, 1)
table.insert(self.wiki_languages, current_lang)
UIManager:close(self)
self:lookupWikipedia()
end,
},
{
text = _("Search"),
text = self.is_wiki and _("Close") or _("Search"),
callback = function()
self.ui:handleEvent(Event:new("HighlightSearch"))
if not self.is_wiki then
self.ui:handleEvent(Event:new("HighlightSearch"))
end
UIManager:close(self)
end,
},
},
},
}
end
local button_table = ButtonTable:new{
width = math.max(self.width, definition:getSize().w),
button_font_face = "cfont",
button_font_size = 20,
buttons = buttons,
zero_sep = true,
show_parent = self,
}
@ -225,6 +329,7 @@ function DictQuickLookup:update()
h = self.dict_title:getSize().h
},
self.dict_title,
CloseButton:new{ window = self, },
}
self.dict_frame = FrameContainer:new{
@ -318,11 +423,19 @@ function DictQuickLookup:isNextDictAvaiable()
end
function DictQuickLookup:changeToPrevDict()
self:changeDictionary(self.dict_index - 1)
if self:isPrevDictAvaiable() then
self:changeDictionary(self.dict_index - 1)
elseif #self.results > 1 then -- restart at end if first reached
self:changeDictionary(#self.results)
end
end
function DictQuickLookup:changeToNextDict()
self:changeDictionary(self.dict_index + 1)
if self:isNextDictAvaiable() then
self:changeDictionary(self.dict_index + 1)
elseif #self.results > 1 then -- restart at first if end reached
self:changeDictionary(1)
end
end
function DictQuickLookup:changeDictionary(index)
@ -331,6 +444,19 @@ function DictQuickLookup:changeDictionary(index)
self.dictionary = self.results[index].dict
self.lookupword = self.results[index].word
self.definition = self.results[index].definition
self.is_fullpage = self.results[index].is_fullpage
if self.is_fullpage then
self.displayword = self.lookupword
else
-- add "dict_index / nbresults" to displayword, so we know where
-- we're at and what's yet to see
self.displayword = self.lookupword.." "..index.." / "..#self.results
-- add queried word to 1st result's definition, so we can see
-- what was the selected text and if we selected wrong
if index == 1 then
self.definition = self.definition.."\n_______\n"..T(_("(query : %1)"), self.word)
end
end
self:update()
end
@ -374,10 +500,19 @@ function DictQuickLookup:onTapCloseDict(arg, ges_ev)
if ges_ev.pos:notIntersectWith(self.dict_frame.dimen) then
self:onClose()
return true
elseif not ges_ev.pos:notIntersectWith(self.dict_title.dimen) then
elseif not ges_ev.pos:notIntersectWith(self.dict_title.dimen) and not self.is_wiki then
self.ui:handleEvent(Event:new("UpdateDefaultDict", self.dictionary))
return true
end
-- Allow for changing dict with tap (tap event will be first
-- processed for scrolling definition by ScrollTextWidget, which
-- will pop it up for us here when it can't scroll anymore).
-- This allow for continuous reading of results' definitions with tap.
if ges_ev.pos.x < Screen:getWidth()/2 then
self:changeToPrevDict()
else
self:changeToNextDict()
end
return true
end
@ -390,7 +525,11 @@ function DictQuickLookup:onClose()
end
end
if self.highlight then
self.highlight:clear()
-- delay unhighlight of selection, so we can see where we stopped when
-- back from our journey into dictionary or wikipedia
UIManager:scheduleIn(1, function()
self.highlight:clear()
end)
end
return true
end
@ -399,6 +538,12 @@ function DictQuickLookup:onHoldClose()
self:onClose()
for i = #self.window_list, 1, -1 do
local window = self.window_list[i]
-- if one holds a highlight, let's clear it like in onClose()
if window.highlight then
UIManager:scheduleIn(1, function()
window.highlight:clear()
end)
end
UIManager:close(window)
table.remove(self.window_list, i)
end
@ -447,7 +592,7 @@ end
function DictQuickLookup:inputLookup()
local word = self.input_dialog:getInputText()
if word and word ~= "" then
local event = self.wiki and "LookupWikipedia" or "LookupWord"
local event = self.is_wiki and "LookupWikipedia" or "LookupWord"
self.ui:handleEvent(Event:new(event, word))
end
end
@ -456,8 +601,19 @@ function DictQuickLookup:closeInputDialog()
UIManager:close(self.input_dialog)
end
function DictQuickLookup:lookupWikipedia()
self.ui:handleEvent(Event:new("LookupWikipedia", self.word, self.word_box))
function DictQuickLookup:lookupWikipedia(get_fullpage)
local word
if get_fullpage then
-- we use the word of the displayed result's definition, which
-- is the exact title of the full wikipedia page
word = self.lookupword
else
-- we use the original word that was querried
word = self.word
end
-- strange : we need to pass false instead of nil if word_box is nil,
-- otherwise get_fullpage is not passed
self.ui:handleEvent(Event:new("LookupWikipedia", word, self.word_box and self.word_box or false, get_fullpage))
end
return DictQuickLookup

@ -3,7 +3,8 @@ local DEBUG = require("dbg")
--[[
-- Query wikipedia using Wikimedia Web API.
-- http://en.wikipedia.org/w/api.php?action=query&prop=extracts&format=json&exintro=&explaintext=&redirects=&titles=hello
-- https://en.wikipedia.org/w/api.php?format=jsonfm&action=query&generator=search&gsrnamespace=0&gsrsearch=ereader&gsrlimit=10&prop=extracts&exintro&explaintext&exlimit=max
-- https://en.wikipedia.org/w/api.php?action=query&prop=extracts&format=jsonfm&explaintext=&redirects=&titles=E-reader
--]]
local Wikipedia = {
@ -13,11 +14,29 @@ local Wikipedia = {
action = "query",
prop = "extracts",
format = "json",
exintro = "",
-- exintro = nil, -- get more than only the intro
explaintext = "",
redirects = "",
-- title = nil, -- text to lookup, will be added below
},
default_lang = "en",
-- Search query for better results
-- see https://www.mediawiki.org/wiki/API:Main_page
wiki_search_params = {
action = "query",
generator = "search",
gsrnamespace = "0",
-- gsrsearch = nil, -- text to lookup, will be added below
gsrlimit = 20, -- max nb of results to get
exlimit = "max",
prop = "extracts|info", -- 'extracts' to get text, 'info' to get full page length
format = "json",
explaintext = "",
exintro = "",
-- We have to use 'exintro=' to get extracts for ALL results
-- (otherwise, we get the full text for only the first result, and
-- no text at all for the others
},
}
function Wikipedia:getWikiServer(lang)
@ -36,14 +55,22 @@ function Wikipedia:loadPage(text, lang, intro, plain)
local request, sink = {}, {}
local query = ""
self.wiki_params.exintro = intro and "" or nil
self.wiki_params.explaintext = plain and "" or nil
for k,v in pairs(self.wiki_params) do
query = query .. k .. '=' .. v .. '&'
end
local parsed = url.parse(self:getWikiServer(lang))
parsed.path = self.wiki_path
parsed.query = query .. "titles=" .. url.escape(text)
if intro == true then -- search query
self.wiki_search_params.explaintext = plain and "" or nil
for k,v in pairs(self.wiki_search_params) do
query = query .. k .. '=' .. v .. '&'
end
parsed.query = query .. "gsrsearch=" .. url.escape(text)
else -- full page content
self.wiki_params.explaintext = plain and "" or nil
for k,v in pairs(self.wiki_params) do
query = query .. k .. '=' .. v .. '&'
end
parsed.query = query .. "titles=" .. url.escape(text)
end
-- HTTP request
request['url'] = url.build(parsed)
@ -79,7 +106,7 @@ function Wikipedia:loadPage(text, lang, intro, plain)
end
end
-- extract intro passage in wiki page
-- search wikipedia and get intros for results
function Wikipedia:wikintro(text, lang)
local result = self:loadPage(text, lang, true, true)
if result then
@ -90,4 +117,16 @@ function Wikipedia:wikintro(text, lang)
end
end
-- get full content of a wiki page
function Wikipedia:wikifull(text, lang)
local result = self:loadPage(text, lang, false, true)
if result then
local query = result.query
if query then
return query.pages
end
end
end
return Wikipedia

Loading…
Cancel
Save