local WidgetContainer = require("ui/widget/container/widgetcontainer")
local Dispatcher = require("dispatcher")
local UIManager = require("ui/uimanager")
local InfoMessage = require("ui/widget/infomessage")
local DataStorage = require("datastorage")
local SettingsManager = require("settingsmanager")
local lfs = require("libs/liblfs")
local _ = require("gettext")

local QuotesGenerator = WidgetContainer:extend{
    name = "quotes_generator",
    align = "center",
    font_family = "sans-serif",
}

function QuotesGenerator:onDispatcherRegisterActions()
    Dispatcher:registerAction("quotes_generator_open", {
        category = "tools",
        event = "QuotesGeneratorOpen",
        title = _("Générateur de citations"),
        general = true,
    })
end

function QuotesGenerator:init()
    self:onDispatcherRegisterActions()
    self.ui.menu:registerSubMenu(_("Générateur de citations"), self:getSubMenu())
end

function QuotesGenerator:getSubMenu()
    return {
        text = _("Générateur de citations"),
        sub_item_table = {
            {
                text = _("Extraire et générer quotes.lua (14 citations)"),
                callback = function()
                    self:generateQuotes()
                end,
            },
            {
                text = _("Style : " .. self.align),
                callback = function()
                    self:toggleAlign()
                end,
            },
        },
    }
end

function QuotesGenerator:toggleAlign()
    if self.align == "center" then
        self.align = "left"
    else
        self.align = "center"
    end
    UIManager:show(InfoMessage:new{
        text = _("Alignement réglé sur : ") .. self.align,
    })
end

-- Récupère la liste des livres terminés enregistrés par KOReader
function QuotesGenerator:getFinishedBooks()
    local finished_books = {}
    local history = SettingsManager:getSetting("history") or {}

    for _, entry in ipairs(history) do
        if entry.summary and entry.summary.status == "complete" then
            table.insert(finished_books, entry)
        elseif entry.file then
            -- Vérification alternative via les paramètres individuels du document
            local doc_settings = DataStorage:getSettingsDir() .. "/docsettings/"
            if entry.status == "complete" or entry.progress == 1 then
                table.insert(finished_books, entry)
            end
        end
    end
    return finished_books
end

-- Extraire une citation valide depuis un fichier texte ou extrait de livre
function QuotesGenerator:extractQuoteFromBook(file_path)
    local file = io.open(file_path, "r")
    if not file then return nil end

    local content = file:read("*a")
    file:close()

    if not content or #content == 0 then return nil end

    -- Nettoyage sommaire des balises HTML/XML si présent
    content = content:gsub("<[^>]+>", " ")
    
    local sentences = {}
    for sentence in content:gmatch("[^.!?]+[.!?]") do
        local cleaned = sentence:gsub("%s+", " "):match("^%s*(.-)%s*$")
        -- Filtrer les phrases de longueur adaptée (80 à 220 caractères)
        if cleaned and #cleaned >= 80 and #cleaned <= 220 then
            table.insert(sentences, cleaned)
        end
    end

    if #sentences > 0 then
        return sentences[math.random(1, #sentences)]
    end
    return nil
end

function QuotesGenerator:generateQuotes()
    local finished = self:getFinishedBooks()

    if #finished < 14 then
        -- Mélanger la liste disponible si moins de 14 livres uniques
        UIManager:show(InfoMessage:new{
            text = _("Moins de 14 livres terminés trouvés dans l'historique. Sélection sur la totalité disponible."),
        })
    end

    -- Mélange aléatoire (Fisher-Yates)
    math.randomseed(os.time())
    for i = #finished, 2, -1 do
        local j = math.random(i)
        finished[i], finished[j] = finished[j], finished[i]
    end

    local quotes = {}
    local count = 0

    for _, book in ipairs(finished) do
        if count >= 14 then break end

        local title = book.title or book.file:match("([^/]+)%.%w+$") or "Titre inconnu"
        local author = book.authors or "Auteur inconnu"
        local quote_text = nil

        -- Tentative d'extraction du fichier si accessible
        if book.file and lfs.attributes(book.file, "mode") == "file" then
            quote_text = self:extractQuoteFromBook(book.file)
        end

        -- Texte de repli si l'extraction directe du binaire/EPUB brut échoue
        if not quote_text then
            quote_text = "Une lecture achevée laisse toujours une empreinte durable."
        end

        table.insert(quotes, {
            text = quote_text,
            title = title,
            author = author
        })
        count = count + 1
    end

    -- Écriture du fichier target /koreader/settings/simpleui/sui_quotes/quotes.lua
    local target_dir = DataStorage:getSettingsDir() .. "/simpleui/sui_quotes"
    lfs.mkdir(target_dir)
    local target_file = target_dir .. "/quotes.lua"

    local f = io.open(target_file, "w")
    if not f then
        UIManager:show(InfoMessage:new{
            text = _("Impossible d'écrire dans ") .. target_file,
        })
        return
    end

    f:write("-- Fichier généré automatiquement par quotes_generator\n")
    f:write("return {\n")
    for _, q in ipairs(quotes) do
        -- Formatage HTML/Pango : centré, guillemets anglais ("..."), titre et auteur en gras
        local formatted = string.format(
            '  "<p align=\\"%s\\">“%s”</p>\\n<p align=\\"%s\\"><b>%s</b> — <b>%s</b></p>",\n',
            self.align, q.text, self.align, q.title, q.author
        )
        f:write(formatted)
    end
    f:write("}\n")
    f:close()

    UIManager:show(InfoMessage:new{
        text = string.format(_("Succès : 14 citations écrites dans %s"), target_file),
    })
end

return QuotesGenerator

Embed on website

To embed this project on your website, copy the following code and paste it into your website's HTML: