Module:RandomArticle

local p = {}

--================================= Custom Info Table ================================= --===== Use this to replace the automated info with custom image, description, etc ==== --Syntax: ["PAGENAME"] = {name = "Custom Name", image = "Custom Image", description = [=[Custom Description]=] --if you don't want to change one or more fields, leave them blank. --for the sake of maintenance, please add entries in alphabetical order custom_info = { --[""] = {name = "", image = "", description = [=[]=]}, }

--========================== Module functions ========================== function firstToLower(str) return (str:gsub("^%u", string.lower)) end

function ParseImage(content) local image = nil --searching for images using different patterns until one of them (or none) finds an image --note: [gjpsw][einpv][befg][gp]? is intended to capture the extensions jpg, png, jpeg, webp, gif and svg --this can also capture any combination of those letters, due to lua not having optional capturing groups --pattern 1 --searching for image in the infobox field "image" in the format local imgpattern = 'image%s*=%s*%[%[File:(.-%.[gjpsw][einpv][befg][gp]?)' image = string.match(content, imgpattern) --pattern 2 --searching for image in the infobox field "image" in the format image.ext if(image == nil) then imgpattern = 'image%s*=%s*(.-%.[gjpsw][einpv][befg][gp]?)' image = string.match(content, imgpattern) end --pattern 3 --searching for image anywhere else in the format [[File:image.ext	if(image == nil) then		imgpattern = '%[%[File:(.-%.[gjpsw][einpv][befg][gp]?)'		image = string.match(content, imgpattern)	end	--pattern 4	--searching for image inside a gallery in the format image.ext	if(image == nil) then		imgpattern = , )	--removes the heading of the "Concept" section to include its content in the description, if available	description = description:gsub('==+%s*Concept%s*==+', )	--removes everything below (and including) the first section marker	description = description:gsub('==+.*==+.*', )	--replaces multiple linebreaks with a single one	description = description:gsub('\n\n+', '\n')	--removes any template in the text	description = description:gsub(, )	--removes empty parenthesis	description = description:gsub('%(%)', '')	--limiting maximum length of description	if(string.len(description) > 290) then		--cropping at 290 characters		description = description:sub(1,290)		--removing last word (possibly cropped) and replacing with "..."		description = description:gsub('%s%S*$', '...')	end	return description end

function ParsePage(frame, article_type, pagename) local name = nil local image = nil local description = nil local content = mw.title.new(pagename):getContent --checking if page is a redirect local redirect_pattern = '#REDIRECT%s*%[%[(.*)%]%]' local redirect_link = pagename while(redirect_link ~= null) do       --navigating through redirects until a page with no redirect is found redirect_link = string.match(content, redirect_pattern) if(redirect_link ~= null) then --if a redirect is found, pagename is replaced by the target of the redirect pagename = redirect_link content = mw.title.new(pagename):getContent end end --if page doesn't exist or is empty, get another page if(content == nil) then return p.GetArticle(frame) end

--using custom info if available, otherwise get data from page if(custom_info[pagename] == nil or custom_info[pagename]['name'] == '') then --determining article name --checking if name was changed using the magicword DISPLAYTITLE local displaytitle_pattern = "%{%{DISPLAYTITLE:(.-)%}%}" name = string.match(content, displaytitle_pattern) --getting name from PAGENAME if(name == nil) then --stripping text between parenthesis from PAGENAME name = pagename:gsub('%s%(.-%)', '') --checking if name was used with first letter in lowercase local lowercase_name_pattern = "'''%s*" .. firstToLower(EscapeStringSymbols(name)) .. "%s*'''.*" lowercase_name_match = string.match(content, lowercase_name_pattern) if(lowercase_name_match ~= nil) then name = firstToLower(name) end end else name = custom_info[pagename]['name'] end if(custom_info[pagename] == nil or custom_info[pagename]['image'] == '') then image = ParseImage(content) else image = custom_info[pagename]['image'] end if(custom_info[pagename] == nil or custom_info[pagename]['description'] == '') then description = ParseDescription(content, name) else description = custom_info[pagename]['description'] end return BuildOutput(frame, "Featured " .. article_type, pagename, name, image, description) end

function BuildOutput(frame, title, link, name, image, description) local IMG_SIZE = '250px' local PRIMARY_COLOR = '#ffb2e8' local IMG_BACKGROUND_COLOR = '#3c3c3c' --Using Template:Infocard to display data on desktop only local desktop_output = frame:expandTemplate{ title = 'Infocard', args = {title = title, name = name, link = link, description = description, file = image, imgsize = IMG_SIZE, primarycolor = PRIMARY_COLOR, imgbackgroundcolor = IMG_BACKGROUND_COLOR} }	--Using Template:Infocard/mobile to display data on mobile only local mobile_output = frame:expandTemplate{ title = 'Infocard/mobile', args = {title = title, name = name, link = link, description = description, file = image, imgsize = IMG_SIZE, primarycolor = PRIMARY_COLOR, imgbackgroundcolor = IMG_BACKGROUND_COLOR} }	return ' ' .. desktop_output .. ' ' .. mobile_output .. ' ' end

function p.GetArticle(frame) local article_type = frame.args[1] if(article_type == 'Group' or article_type == 'Soloist' or article_type == 'Test') then --loading pagenames into tables local data = {} if(article_type == 'Test') then data = {"Pages to test goes here"} else data = require('Module:RandomArticle/' .. article_type .. 's') end

if(#data > 0) then --getting random index and accessing data table at that index math.randomseed(os.time) local pagename = data[math.random(#data)] data = nil return ParsePage(frame, article_type, pagename) else return "RandomArticle:GetArticle: " .. article_type .. ": PAGENAME list not found or empty." end else return "RandomArticle:GetArticle: Invalid Type. Supported: Group, Soloist, Test." end end return p