Module:RandomArticle

local p = {}

L = {} N = {} I = {} D = {} n_items = 0

function DataInsert(link, name, image, desc) table.insert(L, link) table.insert(N, name) table.insert(I, image) table.insert(D, desc) n_items = n_items + 1 end

--====================== DATA INSERT: Syntax: DataInsert("link","name", "image", [=[description]=]) ======================== --if name is the same as link, you can leave it blank --if image is blank, it will be picked automatically from the article --if description is blank, it will be picked automatically from the article --if name or link includes a double quote, it needs to be written as \" so the quote is not interpreted as the end of the name. --for the sake of maintenance, please add entries in alphabetical order function PopulateGroup	DataInsert("1、5M!LK","","",[=[]=])	DataInsert("4TE","","",[=[]=])	DataInsert("8YUME","","",[=[]=])	DataInsert("A-MUSE","","",[=[]=])	DataInsert("Amai Monogatari","","",[=[]=])	DataInsert("C.LiTZ","","",[=[]=])	DataInsert("C.yndrome","","",[=[]=])	DataInsert("CHEATCODE","","",[=[]=])	DataInsert("Ddi","","",[=[]=])	DataInsert("ERISU","","",[=[]=])	DataInsert("GENtellite","","",[=[]=])	DataInsert("HaRunoSpecula","","",[=[]=])	DataInsert("Heartless","","",[=[]=])	DataInsert("HIBANA","","",[=[]=])	DataInsert("HONEY HIME","","",[=[]=])	DataInsert("Kamisama","","",[=[]=])	DataInsert("KIRA! SUN","","",[=[]=])	DataInsert("Kizuna Simulation","","",[=[]=])	DataInsert("KKD","","",[=[]=]) DataInsert("Kohi Sekai","","",[=[]=]) DataInsert("Kurohika","","",[=[]=]) DataInsert("LIPIMOON","","",[=[]=]) DataInsert("Little Princess Project","","",[=[]=]) DataInsert("MERAMERAHEART","","",[=[]=]) DataInsert("Minerva Land","","",[=[]=]) DataInsert("NANOKA","","",[=[]=]) DataInsert("NEKIRU","","",[=[]=]) DataInsert("NEORiYON","","",[=[]=]) DataInsert("Perfume de Ange","","",[=[]=]) DataInsert("Proxima Club","","",[=[]=]) DataInsert("PhEri","","",[=[]=]) DataInsert("RARE STAGE","","",[=[]=]) DataInsert("RELIVE SEKAI","","",[=[]=]) DataInsert("Say! Won!","","",[=[]=]) DataInsert("Sky Rabbit","","",[=[]=]) DataInsert("SONOKI","","",[=[]=]) DataInsert("SONYOMETAL","","",[=[]=]) DataInsert("StryGo!","","",[=[]=]) DataInsert("X!DENT","","",[=[]=]) DataInsert("XcidenX","","",[=[]=]) DataInsert("YURASAI","","",[=[]=]) end

function PopulateSoloist DataInsert("Ban Seolhee","","",[=[]=]) DataInsert("Chaeli","","",[=[]=]) DataInsert("Heo LunaBella","","",[=[]=]) DataInsert("HIRO","","",[=[]=]) DataInsert("Lingling","","",[=[]=]) DataInsert("Mayumi","","",[=[]=]) DataInsert("Melancholiaah!","","",[=[]=]) DataInsert("MyoU","","",[=[]=]) DataInsert("Re:A","","",[=[]=]) DataInsert("Raku","","",[=[]=]) end

function PopulateAll PopulateGroup PopulateSoloist end

--================================================ Module functions ================================================

function ParseImage(content) 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 --search for image in the infobox field "image" as 	if(image == nil) then imgpattern = 'image%s*=%s*%[%[File:(.-%.[gjpsw][einpv][befg][gp]?)' image = string.match(content, imgpattern) end --pattern 2 --search for image in the infobox field "image" as image.ext if(image == nil) then imgpattern = 'image%s*=%s*(.-%.[gjpsw][einpv][befg][gp]?)' image = string.match(content, imgpattern) end --pattern 3 --search for image anywhere else as [[File:image.ext]] if(image == nil) then imgpattern = '%[%[File:(.-%.[gjpsw][einpv][befg][gp]?)' image = string.match(content, imgpattern) end --pattern 4 --search for image inside a gallery as 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 		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	end	return description end

function ParsePage(frame, title) --getting random index math.randomseed(os.time) index = math.random(n_items) --accessing data table with random index link = L[index] name = N[index] image = I[index] description = D[index] page = mw.title.new(link) content = page:getContent --checking if page is a redirect if(content ~= nil) then redirectpattern = '#REDIRECT%s*%[%[(.*)%]%]' redirectlink = link --navigating through redirects until a page with content is found or not found while (redirectlink ~= null) do           redirectlink = string.match(content, redirectpattern) if (redirectlink ~= null) then --if a redirect is found, link is replaced by the target of the redirect link = redirectlink page = mw.title.new(link) content = page:getContent end end end

--if no name is given, use link as the name if(name == '') then name = link end --if no image is given, try to get it from the article if(image == '') then if(content == nil) then image = nil else --if article exists, get it from the article content image = ParseImage(content) end end --if no description is given, try to get it from the article if(description == '') then if(content == nil) then description = nil else --if article exists, get it from the article content description = ParseDescription(content, name) end end return BuildOutput(frame, title, link, name, image, description) end

function BuildOutput(frame, title, link, name, image, description) imgsize = '250px' primarycolor = '#ffb2e8' imgbackgroundcolor = '#3c3c3c' titlecolor = '#000000' if(image == nil) then --if no image was found, return empty string. This will be treated in Template:Infocard image = '' end if(description == nil) then --if description is nil, page don't exist. Return error message. description = 'No article found with PAGENAME ' .. link .. '. If you see this message, please contact an admin so it can be fixed.' end --Using Template:Infocard to display collected data on desktop desktop_output = frame:expandTemplate{ title = 'Infocard', args = {title = title, name = name, link = link, description = description, file = image, imgsize = imgsize, primarycolor = primarycolor, imgbackgroundcolor = imgbackgroundcolor, titlecolor = titlecolor} }	--Using Template:Infocard/mobile to display collected data on mobile --bold title on mobile to emphasize it since there's no custom CSS title = "'''" .. title .. "'''"	mobile_output = frame:expandTemplate{ title = 'Infocard/mobile', args = {title = title, name = name, link = link, description = description, file = image, imgsize = imgsize, primarycolor = primarycolor, imgbackgroundcolor = imgbackgroundcolor, titlecolor = titlecolor} }	return ' ' .. desktop_output .. ' ' .. mobile_output .. ' ' end

function p.GetGroup(frame) --loading predefined data into tables PopulateGroup if(n_items > 0) then return ParsePage(frame, "Featured Group") end end

function p.GetSoloist(frame) --loading predefined data into tables PopulateSoloist if(n_items > 0) then return ParsePage(frame, "Featured Soloist") end end

function p.GetArticle(frame) --loading predefined data into tables PopulateAll if(n_items > 0) then return ParsePage(frame, "Featured Article") end end return p