Module:ProjectCounts: Difference between revisions
Created page with "-- Counts data rows in the wikitable(s) inside one named section of a page. -- Usage: {{#invoke:ProjectCounts|count|Active BOINC Projects|page=BOINC projects}} local p = {} local function esc(s) return (s:gsub('(%W)', '%%%1')) end function p.count(frame) local section = mw.text.trim(frame.args[1] or '') local title = mw.title.new(frame.args.page or 'BOINC projects') if not title then return 0 end local content = title:getContent() if not content the..." |
No edit summary |
||
| (One intermediate revision by the same user not shown) | |||
| Line 1: | Line 1: | ||
-- Counts | -- Module:ProjectCounts | ||
-- | -- Counts BOINC project table rows and related figures for the wiki. | ||
-- | |||
-- {{#invoke:ProjectCounts|count|Section name|page=Page title}} | |||
-- Data rows in the wikitable(s) of one section. | |||
-- {{#invoke:ProjectCounts|total|Section A|Section B|...|page=Page title}} | |||
-- Sum of data rows across several sections of one page. | |||
-- {{#invoke:ProjectCounts|documented|Local BOINC project wiki pages|page=Main Page}} | |||
-- Distinct existing mainspace articles linked in a section. | |||
-- {{#invoke:ProjectCounts|recordings|Screensaver Gallery|page=BOINC project screensavers}} | |||
-- Unique YouTube recordings linked in a section. | |||
local p = {} | local p = {} | ||
local function esc(s) return (s:gsub('(%W)', '%%%1')) end | local function esc(s) return (s:gsub('(%W)', '%%%1')) end | ||
local function getContent(page) | |||
local t = mw.title.new(page) | |||
if not t then return nil end | |||
return t:getContent() | |||
end | |||
-- Extract the wikitext of one section: from its heading (any level) | |||
-- to the next heading of the same or higher level. | |||
local function getSection(content, section) | |||
local hStart, hEnd, marks = content:find('\n(=+)%s*' .. esc(section) .. '%s*=*') | |||
if not hStart then return nil end | |||
local depth = #marks | |||
local secEnd = #content + 1 | |||
local pos = hEnd | |||
while true do | |||
local nStart, nEnd, nMarks = content:find('\n(=+)', pos) | |||
if not nStart then break end | |||
if #nMarks <= depth then secEnd = nStart break end | |||
pos = nEnd | |||
end | |||
return '\n' .. content:sub(hEnd + 1, secEnd - 1) | |||
end | |||
-- Data rows = row separators minus one header separator per table. | |||
local function countRows(body) | |||
local _, tables = body:gsub('\n{|', '') | |||
local _, seps = body:gsub('\n|%-', '') | |||
return math.max(seps - tables, 0) | |||
end | |||
local function countSection(page, section) | |||
local content = getContent(page) | |||
if not content then return 0 end | |||
local body = getSection(content, mw.text.trim(section)) | |||
if not body then return 0 end | |||
return countRows(body) | |||
end | |||
function p.count(frame) | function p.count(frame) | ||
return countSection(frame.args.page or 'BOINC projects', frame.args[1] or '') | |||
end | |||
function p.total(frame) | |||
local page = frame.args.page or 'BOINC projects' | |||
local content = getContent(page) | |||
if not content then return 0 end | |||
local sum = 0 | |||
for _, s in ipairs(frame.args) do | |||
local body = getSection(content, mw.text.trim(s)) | |||
if body then sum = sum + countRows(body) end | |||
end | |||
return sum | |||
end | |||
function p.documented(frame) | |||
local page = frame.args.page or 'Main Page' | |||
local section = mw.text.trim(frame.args[1] or 'Local BOINC project wiki pages') | |||
local content = getContent(page) | |||
if not content then return 0 end | |||
local body = getSection(content, section) | |||
if not body then return 0 end | |||
local seen, n = {}, 0 | |||
for link in body:gmatch('%[%[([^|%]%[#:]+)') do | |||
link = mw.text.trim(link) | |||
if link ~= '' and not seen[link] then | |||
seen[link] = true | |||
local t = mw.title.new(link) | |||
if t and t.namespace == 0 and t.exists then | |||
n = n + 1 | |||
end | |||
end | |||
end | |||
return n | |||
end | |||
function p.recordings(frame) | |||
local content = getContent(frame.args.page or 'BOINC project screensavers') | |||
if not content then return 0 end | |||
local body = getSection(content, mw.text.trim(frame.args[1] or 'Screensaver Gallery')) | |||
if not body then return 0 end | |||
local seen, n = {}, 0 | |||
local function mark(id) | |||
if id and id ~= '' and not seen[id] then | |||
seen[id] = true | |||
n = n + 1 | |||
end | |||
end | |||
for id in body:gmatch('youtube%.com/watch%?v=([%w_-]+)') do mark(id) end | |||
for id in body:gmatch('youtu%.be/([%w_-]+)') do mark(id) end | |||
for id in body:gmatch('img%.youtube%.com/vi/([%w_-]+)') do mark(id) end | |||
return n | |||
end | end | ||
return p | return p | ||