Documentation for this module may be created at Module:Main page feed/doc

-- Recent events and deaths for the Vector main page.
-- Reads "YYYY in India" (Events and Deaths). No JavaScript.
--
-- {{#invoke:Main page feed|events|5}}
-- {{#invoke:Main page feed|deaths|5}}

local p = {}

local months = {
	'January', 'February', 'March', 'April', 'May', 'June',
	'July', 'August', 'September', 'October', 'November', 'December'
}

local monthIndex = {}
for i, name in ipairs(months) do
	monthIndex[name:lower()] = i
end

local function istNow()
	-- Server clock is UTC. India is UTC+5:30.
	return os.date('!*t', os.time() + 19800)
end

local function pageContent(year)
	local title = mw.title.new(tostring(year) .. ' in India')
	if not title or not title.exists then
		return ''
	end
	return title:getContent() or ''
end

local function chapter(text, name)
	local _, finish = text:find('==%s*' .. name .. '%s*==')
	if not finish then
		return ''
	end
	local rest = text:sub(finish + 1)
	local nextHeading = rest:find('\n==[^=]')
	if nextHeading then
		rest = rest:sub(1, nextHeading - 1)
	end
	return rest
end

local function clean(text)
	text = text:gsub('<ref[^>]-/>', '')
	text = text:gsub('<ref.->.-</ref>', '')
	text = text:gsub('{{[^{}]-}}', '')
	text = text:gsub('%s+', ' ')
	text = text:gsub('^%s+', ''):gsub('%s+$', '')
	text = text:gsub('[%.%s]+$', '')
	return text
end

local function parseDated(section, year)
	local items = {}
	local currentDay, currentMonth
	for line in (section .. '\n'):gmatch('(.-)\n') do
		local day, monthName, rest = line:match('^%*+%s*(%d%d?)%s+(%a+)%s*[–—%-]%s*(.*)$')
		if day and monthIndex[monthName:lower()] then
			currentDay = tonumber(day)
			currentMonth = monthIndex[monthName:lower()]
			rest = clean(rest or '')
			if rest ~= '' then
				table.insert(items, {
					day = currentDay,
					month = currentMonth,
					year = year,
					text = rest
				})
			end
		elseif currentDay and line:match('^%*+%s*%S') then
			local text = clean(line:gsub('^%*+%s*', ''))
			if text ~= '' then
				table.insert(items, {
					day = currentDay,
					month = currentMonth,
					year = year,
					text = text
				})
			end
		end
	end
	return items
end

local function stamp(item)
	return item.year * 10000 + item.month * 100 + item.day
end

local function collect(kind, limit)
	local now = istNow()
	local today = now.year * 10000 + now.month * 100 + now.day
	local year = now.year
	local text = pageContent(year)
	local items = parseDated(chapter(text, kind), year)

	local function keep(list)
		local out = {}
		for _, item in ipairs(list) do
			if stamp(item) <= today then
				table.insert(out, item)
			end
		end
		return out
	end

	items = keep(items)
	if #items < limit then
		local prevMonth = now.month - 1
		local prevYear = year
		local prevText = text
		if prevMonth < 1 then
			prevMonth = 12
			prevYear = year - 1
			prevText = pageContent(prevYear)
		end
		local older = parseDated(chapter(prevText, kind), prevYear)
		for _, item in ipairs(keep(older)) do
			if item.month == prevMonth then
				table.insert(items, item)
			end
		end
	end

	table.sort(items, function(a, b)
		return stamp(a) > stamp(b)
	end)

	local out = {}
	for i = 1, math.min(limit, #items) do
		out[i] = items[i]
	end
	return out, year
end

local function render(items, empty)
	if #items == 0 then
		return empty
	end
	local lines = {}
	for _, item in ipairs(items) do
		table.insert(lines, string.format(
			'* \'\'\'%d %s\'\'\' – %s',
			item.day,
			months[item.month],
			item.text
		))
	end
	return table.concat(lines, '\n')
end

function p.events(frame)
	local limit = tonumber(frame.args[1]) or 5
	local items = collect('Events', limit)
	return render(items, '* No recent events listed.')
end

function p.deaths(frame)
	local limit = tonumber(frame.args[1]) or 5
	local items = collect('Deaths', limit)
	return render(items, '* No recent deaths listed.')
end

return p