<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://www.cultopedia.org/index.php?action=history&amp;feed=atom&amp;title=Module%3ASpoken_Wikipedia</id>
	<title>Module:Spoken Wikipedia - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://www.cultopedia.org/index.php?action=history&amp;feed=atom&amp;title=Module%3ASpoken_Wikipedia"/>
	<link rel="alternate" type="text/html" href="https://www.cultopedia.org/index.php?title=Module:Spoken_Wikipedia&amp;action=history"/>
	<updated>2026-04-06T01:34:31Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.44.5</generator>
	<entry>
		<id>https://www.cultopedia.org/index.php?title=Module:Spoken_Wikipedia&amp;diff=1970&amp;oldid=prev</id>
		<title>imported&gt;Anomie: File:Sound-icon.svg is LGPL, which requires the link to the file description page for attribution and notice of license. See MOS:PDI for more info. Switch to File:Gnome-mime-sound-openclipart.svg which is public domain.</title>
		<link rel="alternate" type="text/html" href="https://www.cultopedia.org/index.php?title=Module:Spoken_Wikipedia&amp;diff=1970&amp;oldid=prev"/>
		<updated>2025-10-18T00:13:29Z</updated>

		<summary type="html">&lt;p&gt;&lt;a href=&quot;/index.php/File:Sound-icon.svg&quot; title=&quot;File:Sound-icon.svg&quot;&gt;File:Sound-icon.svg&lt;/a&gt; is LGPL, which requires the link to the file description page for attribution and notice of license. See &lt;a href=&quot;https://en.wikipedia.org/wiki/MOS%3APDI&quot; class=&quot;extiw cultopedia-missing-wikipedia&quot; title=&quot;MOS:PDI on Wikipedia&quot; rel=&quot;nofollow&quot;&gt;MOS:PDI&lt;/a&gt; for more info. Switch to &lt;a href=&quot;/index.php/File:Gnome-mime-sound-openclipart.svg&quot; title=&quot;File:Gnome-mime-sound-openclipart.svg&quot;&gt;File:Gnome-mime-sound-openclipart.svg&lt;/a&gt; which is public domain.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local getArgs = require(&amp;#039;Module:Arguments&amp;#039;).getArgs&lt;br /&gt;
local yesno = require(&amp;#039;Module:Yesno&amp;#039;)&lt;br /&gt;
local Date = require(&amp;#039;Module:Date&amp;#039;)._Date&lt;br /&gt;
local lang = mw.language.new(&amp;#039;en&amp;#039;)&lt;br /&gt;
local cfg = mw.loadData(&amp;#039;Module:Spoken Wikipedia/configuration&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
p = {}&lt;br /&gt;
&lt;br /&gt;
local function wikiError(message)&lt;br /&gt;
	local ret = mw.html.create(&amp;#039;div&amp;#039;)&lt;br /&gt;
		:addClass(cfg.i18n.class.err)&lt;br /&gt;
		:wikitext(message)&lt;br /&gt;
		:done()&lt;br /&gt;
	return tostring(ret)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function category(c, nocat)&lt;br /&gt;
	if nocat then&lt;br /&gt;
		return &amp;#039;&amp;#039;&lt;br /&gt;
	else&lt;br /&gt;
		return c&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatPageText(page)&lt;br /&gt;
	if page then&lt;br /&gt;
		return &amp;#039;&amp;lt;span class=&amp;quot;fn&amp;quot;&amp;gt;[[&amp;#039; .. page .. &amp;#039;]]&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	if mw.title.getCurrentTitle().namespace == 0 then&lt;br /&gt;
		return cfg.i18n.this_article&lt;br /&gt;
	else&lt;br /&gt;
		return cfg.i18n.this_page&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatFileLength(filenames)&lt;br /&gt;
	local length = 0&lt;br /&gt;
	for _, filename in ipairs(filenames) do&lt;br /&gt;
		local fileTitle = mw.title.new(filename, &amp;#039;Media&amp;#039;)&lt;br /&gt;
		if fileTitle and fileTitle.file and fileTitle.file.exists then&lt;br /&gt;
			length = length + fileTitle.file.length&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Add 30 to offset the rounding down&lt;br /&gt;
	local intervals = lang:getDurationIntervals(length + 30, { &amp;#039;hours&amp;#039;, &amp;#039;minutes&amp;#039; })&lt;br /&gt;
	local ret = string.format(&lt;br /&gt;
		&amp;#039;&amp;lt;span class=&amp;quot;min&amp;quot;&amp;gt;%s&amp;lt;/span&amp;gt; %s&amp;#039;,&lt;br /&gt;
		intervals.minutes or 0,&lt;br /&gt;
		intervals.minutes == 1 and cfg.i18n.minute or cfg.i18n.minutes&lt;br /&gt;
	)&lt;br /&gt;
	if intervals.hours then&lt;br /&gt;
		ret = string.format(&lt;br /&gt;
			&amp;#039;&amp;lt;span class=&amp;quot;h&amp;quot;&amp;gt;%s&amp;lt;/span&amp;gt; %s and %s&amp;#039;,&lt;br /&gt;
			intervals.hours,&lt;br /&gt;
			intervals.hours == 1 and cfg.i18n.hour or cfg.i18n.hours,&lt;br /&gt;
			ret&lt;br /&gt;
		)&lt;br /&gt;
	end&lt;br /&gt;
	return &amp;#039;&amp;lt;span class=&amp;quot;duration&amp;quot;&amp;gt;&amp;#039; .. ret .. &amp;#039;&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatHeader(filenames, page)&lt;br /&gt;
	local listento = mw.html.create(&amp;#039;span&amp;#039;)&lt;br /&gt;
		:addClass(cfg.i18n.class.listento)&lt;br /&gt;
		:wikitext(string.format(&lt;br /&gt;
			cfg.i18n.listento,&lt;br /&gt;
			formatPageText(page)&lt;br /&gt;
		))&lt;br /&gt;
		:done()&lt;br /&gt;
	&lt;br /&gt;
	local file_length&lt;br /&gt;
	if #filenames &amp;gt; 1 then&lt;br /&gt;
		file_length = string.format(&lt;br /&gt;
			cfg.i18n.n_files_length,&lt;br /&gt;
			tostring(#filenames),&lt;br /&gt;
			formatFileLength(filenames)&lt;br /&gt;
		)&lt;br /&gt;
	else&lt;br /&gt;
		file_length = string.format(&lt;br /&gt;
			cfg.i18n.one_file_length,&lt;br /&gt;
			formatFileLength(filenames)&lt;br /&gt;
		)&lt;br /&gt;
	end&lt;br /&gt;
	return mw.html.create(&amp;#039;div&amp;#039;)&lt;br /&gt;
		:addClass(cfg.i18n.class.header)&lt;br /&gt;
		:node(listento)&lt;br /&gt;
		:wikitext(file_length)&lt;br /&gt;
		:done()&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatIcon()&lt;br /&gt;
	return mw.html.create(&amp;#039;div&amp;#039;)&lt;br /&gt;
		:addClass(cfg.i18n.class.icon)&lt;br /&gt;
		:wikitext(cfg.i18n.icon)&lt;br /&gt;
		:done()&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatFiles(filenames, nocat)&lt;br /&gt;
	if #filenames == 0 then&lt;br /&gt;
		return wikiError(cfg.i18n.err.no_filename) ..&lt;br /&gt;
			category(cfg.i18n.cat.no_filename, nocat)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- TODO: the else branch really wants to be a mw.html &amp;lt;ol&amp;gt; object rather than wikitext&lt;br /&gt;
	-- version of the same, so that we can style the numbers nicer&lt;br /&gt;
	local files = {}&lt;br /&gt;
	if #filenames == 1 then&lt;br /&gt;
		table.insert(files, string.format(cfg.i18n.one_file, filenames[1]))&lt;br /&gt;
	else&lt;br /&gt;
		for i, filename in ipairs(filenames) do&lt;br /&gt;
			table.insert(files, string.format(cfg.i18n.n_files, filename, i))&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return mw.html.create(&amp;#039;div&amp;#039;)&lt;br /&gt;
		:addClass(cfg.i18n.class.files)&lt;br /&gt;
		:wikitext(table.concat(files))&lt;br /&gt;
		:done()&lt;br /&gt;
		:newline()&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatDateText(frame, dateArg, nocat)&lt;br /&gt;
	local d = dateArg and Date(dateArg) or nil&lt;br /&gt;
	return d and frame:expandTemplate{&lt;br /&gt;
		title = &amp;#039;Start date&amp;#039;, args = {&lt;br /&gt;
			d.year,&lt;br /&gt;
			d.month,&lt;br /&gt;
			d.day,&lt;br /&gt;
			df=&amp;#039;y&amp;#039;&lt;br /&gt;
		}&lt;br /&gt;
	} or (wikiError(cfg.i18n.err.no_date) .. category(cfg.i18n.cat.no_date, nocat))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatDisclaimer(frame, filenames, page, dateArg, nocat)&lt;br /&gt;
	local thisFileText = &amp;#039;&amp;#039;&lt;br /&gt;
	local disclaimer&lt;br /&gt;
	if #filenames == 1 then&lt;br /&gt;
		thisFileText = filenames[1]&lt;br /&gt;
		disclaimer = cfg.i18n.one_file_disclaimer&lt;br /&gt;
	else&lt;br /&gt;
		disclaimer = cfg.i18n.n_files_disclaimer&lt;br /&gt;
	end&lt;br /&gt;
	return mw.html.create(&amp;#039;div&amp;#039;)&lt;br /&gt;
		:addClass(cfg.i18n.class.disclaimer)&lt;br /&gt;
		:wikitext(string.format(&lt;br /&gt;
			disclaimer,&lt;br /&gt;
			thisFileText,&lt;br /&gt;
			formatPageText(page),&lt;br /&gt;
			formatDateText(frame, dateArg, nocat)&lt;br /&gt;
		))&lt;br /&gt;
		:done()&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatFooter()&lt;br /&gt;
	return mw.html.create(&amp;#039;div&amp;#039;)&lt;br /&gt;
		:addClass(cfg.i18n.class.footer)&lt;br /&gt;
		:wikitext(cfg.i18n.footer)&lt;br /&gt;
		:done()&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function formatTopicon(frame, filenames)&lt;br /&gt;
	local wikilink&lt;br /&gt;
	if #filenames &amp;gt; 0 then&lt;br /&gt;
		wikilink = &amp;#039;File:&amp;#039; .. filenames[1]&lt;br /&gt;
	else&lt;br /&gt;
		wikilink = cfg.i18n.topicon_multiwikilink&lt;br /&gt;
	end&lt;br /&gt;
	return frame:expandTemplate{&lt;br /&gt;
		title = &amp;quot;Top icon&amp;quot;,&lt;br /&gt;
		args = {&lt;br /&gt;
			imagename = &amp;#039;Gnome-mime-sound-openclipart.svg&amp;#039;,&lt;br /&gt;
			wikilink = wikilink,&lt;br /&gt;
			text = &amp;#039;Listen to this article&amp;#039;,&lt;br /&gt;
			id = &amp;#039;spoken-icon&amp;#039;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function extractFilenames(args)&lt;br /&gt;
	local filenames = {}&lt;br /&gt;
	for key, rawValue in ipairs(args) do&lt;br /&gt;
		local value = mw.text.trim(rawValue)&lt;br /&gt;
		if type(key) == &amp;quot;number&amp;quot; and value ~= &amp;#039;&amp;#039; then&lt;br /&gt;
			table.insert(filenames, value)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return filenames&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function sidebox(nodes)&lt;br /&gt;
	root = mw.html.create(&amp;#039;div&amp;#039;)&lt;br /&gt;
		:addClass(cfg.i18n.class.box)&lt;br /&gt;
	for _, node in ipairs(nodes) do&lt;br /&gt;
		root:node(node)&lt;br /&gt;
	end&lt;br /&gt;
	return root&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function main(frame)&lt;br /&gt;
	local args = getArgs(frame)&lt;br /&gt;
&lt;br /&gt;
	-- Mandatory parameters&lt;br /&gt;
	local filenames = extractFilenames(args)&lt;br /&gt;
	local dateArg = args[&amp;#039;date&amp;#039;]&lt;br /&gt;
	-- Optional parameters&lt;br /&gt;
	local page = args[&amp;#039;page&amp;#039;]&lt;br /&gt;
	local nocat = yesno(args[&amp;#039;nocat&amp;#039;], false) or false&lt;br /&gt;
&lt;br /&gt;
	local root = sidebox({&lt;br /&gt;
		formatHeader(filenames, page),&lt;br /&gt;
		formatFiles(filenames, nocat),&lt;br /&gt;
		formatIcon(),&lt;br /&gt;
		formatDisclaimer(frame, filenames, page, dateArg, nocat),&lt;br /&gt;
		formatFooter()&lt;br /&gt;
	})&lt;br /&gt;
&lt;br /&gt;
	if mw.title.getCurrentTitle().namespace == 0 then&lt;br /&gt;
		root:wikitext(formatTopicon(frame, filenames))&lt;br /&gt;
		root:wikitext(category(cfg.i18n.cat.articles, nocat))&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return frame:extensionTag{&lt;br /&gt;
		name = &amp;#039;templatestyles&amp;#039;, args = { src = cfg.templatestyles }&lt;br /&gt;
	} .. tostring(root)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
p.main = main&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>imported&gt;Anomie</name></author>
	</entry>
</feed>