# Module:Spoken Wikipedia

local getArgs = require('Module:Arguments').getArgs  
local yesno = require('Module:Yesno')  
local Date = require('Module:Date')._Date  
local lang = mw.language.new('en')  
local cfg = mw.loadData('Module:Spoken Wikipedia/configuration')  

p = {}  

local function wikiError(message)  
local ret = mw.html.create('div')  
:addClass(cfg.i18n.class.err)  
:wikitext(message)  
:done  
return tostring(ret)  
end  

local function category(c, nocat)  
if nocat then  
return ''  
else  
return c  
end  
end  

local function formatPageText(page)  
if page then  
return '<span>' .. page .. '</span>'  
end  
if mw.title.getCurrentTitle.namespace == 0 then  
return cfg.i18n.this_article  
else  
return cfg.i18n.this_page  
end  
end  

local function formatFileLength(filenames)  
local length = 0  
for _, filename in ipairs(filenames) do  
local fileTitle = mw.title.new(filename, 'Media')  
if fileTitle and fileTitle.file and fileTitle.file.exists then  
length = length + fileTitle.file.length  
end  
end  

-- Add 30 to offset the rounding down  
local intervals = lang:getDurationIntervals(length + 30, { 'hours', 'minutes' })  
local ret = string.format(  
'<span>%s</span> %s',  
intervals.minutes or 0,  
intervals.minutes == 1 and cfg.i18n.minute or cfg.i18n.minutes  
if intervals.hours then  
ret = string.format(  
'<span>%s</span> %s and %s',  
intervals.hours,  
intervals.hours == 1 and cfg.i18n.hour or cfg.i18n.hours,  
ret  
end  
return '<span>' .. ret .. '</span>'  
end  

local function formatHeader(filenames, page)  
local listento = mw.html.create('span')  
:addClass(cfg.i18n.class.listento)  
:wikitext(string.format(  
cfg.i18n.listento,  
formatPageText(page)  
))  
:done  

local file_length  
if #filenames > 1 then  
file_length = string.format(  
cfg.i18n.n_files_length,  
tostring(#filenames),  
formatFileLength(filenames)  
else  
file_length = string.format(  
cfg.i18n.one_file_length,  
formatFileLength(filenames)  
end  
return mw.html.create('div')  
:addClass(cfg.i18n.class.header)  
:node(listento)  
:wikitext(file_length)  
:done  
end  

local function formatIcon  
return mw.html.create('div')  
:addClass(cfg.i18n.class.icon)  
:wikitext(cfg.i18n.icon)  
:done  
end  

local function formatFiles(filenames, nocat)  
if #filenames == 0 then  
return wikiError(cfg.i18n.err.no_filename) ..  
category(cfg.i18n.cat.no_filename, nocat)  
end  

-- TODO: the else branch really wants to be a mw.html <ol> object rather than wikitext  
-- version of the same, so that we can style the numbers nicer  
local files = {}  
if #filenames == 1 then  
table.insert(files, string.format(cfg.i18n.one_file, filenames[1]))  
else  
for i, filename in ipairs(filenames) do  
table.insert(files, string.format(cfg.i18n.n_files, filename, i))  
end  
end  

return mw.html.create('div')  
:addClass(cfg.i18n.class.files)  
:wikitext(table.concat(files))  
:done  
:newline  
end  

local function formatDateText(, dateArg, nocat)  
local d = dateArg and Date(dateArg) or nil  
return d and :expandTemplate{  
title = 'Start date', args = {  
d.year,  
d.month,  
d.day,  
df='y'  
}  
} or (wikiError(cfg.i18n.err.no_date) .. category(cfg.i18n.cat.no_date, nocat))  
end  

local function formatDisclaimer(, filenames, page, dateArg, nocat)  
local thisFileText = ''  
local disclaimer  
if #filenames == 1 then  
thisFileText = filenames[1]  
disclaimer = cfg.i18n.one_file_disclaimer  
else  
disclaimer = cfg.i18n.n_files_disclaimer  
end  
return mw.html.create('div')  
:addClass(cfg.i18n.class.disclaimer)  
:wikitext(string.format(  
disclaimer,  
thisFileText,  
formatPageText(page),  
formatDateText(, dateArg, nocat)  
))  
:done  
end  

local function formatFooter  
return mw.html.create('div')  
:addClass(cfg.i18n.class.footer)  
:wikitext(cfg.i18n.footer)  
:done  
end  

local function formatTopicon(, filenames)  
local wikilink  
if #filenames > 0 then  
wikilink = 'File:' .. filenames[1]  
else  
wikilink = cfg.i18n.topicon_multiwikilink  
end  
return :expandTemplate{  
title = "Top icon",  
args = {  
imagename = 'Sound-icon.svg',  
wikilink = wikilink,  
text = 'Listen to this article',  
id = 'spoken-icon'  
}  
}  
end  

local function extractFilenames(args)  
local filenames = {}  
for key, rawValue in ipairs(args) do  
local value = mw.text.trim(rawValue)  
if type(key) == "number" and value ~= '' then  
table.insert(filenames, value)  
end  
end  
return filenames  
end  

local function sidebox(nodes)  
root = mw.html.create('div')  
:addClass(cfg.i18n.class.box)  
for _, node in ipairs(nodes) do  
root:node(node)  
end  
return root  
end  

function main  
local args = getArgs  

-- Mandatory parameters  
local filenames = extractFilenames(args)  
local dateArg = args['date']  
-- Optional parameters  
local page = args['page']  
local nocat = yesno(args['nocat'], false) or false  

local root = sidebox({  
formatHeader(filenames, page),  
formatFiles(filenames, nocat),  
formatIcon,  
formatDisclaimer(, filenames, page, dateArg, nocat),  
formatFooter  
})  

if mw.title.getCurrentTitle.namespace == 0 then  
root:wikitext(formatTopicon(, filenames))  
root:wikitext(category(cfg.i18n.cat.articles, nocat))  
end  

return :extensionTag{  
name = 'templatestyles', args = { src = cfg.templatestyles }  
} .. tostring(root)  
end  

p.main = main  

return p