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 PopulateBand DataInsert("-Shintenchi Kaibyaku Shudan- zigzag","","","",[=[]=]) DataInsert("04 Limited Sazabys","","","",[=[]=]) DataInsert("Accént","","",[=[]=]) DataInsert("ALI","","",[=[]=]) DataInsert("Alice Nine","","",[=[]=]) DataInsert("Amiliyah","","",[=[]=]) DataInsert("ANARCHY STONE","","",[=[]=]) DataInsert("BABYMETAL","","",[=[]=]) DataInsert("BAND-MAID","","",[=[]=]) DataInsert("BAND-MAIKO","","",[=[]=]) DataInsert("BRATS","","",[=[]=]) DataInsert("BRIDEAR","","",[=[]=]) DataInsert("CIDER GIRL","","",[=[]=]) DataInsert("CLASSMATE⊿CINDERELLA","","","",[=[]=]) DataInsert("Dorodoro","","",[=[]=]) DataInsert("Dragon Guardian","","",[=[]=]) DataInsert("ELLEGARDEN","","",[=[]=]) DataInsert("FATE GEAR","","",[=[]=]) DataInsert("Fear, and Loathing in Las Vegas","","",[=[]=]) DataInsert("Fuyu no Doubutsuen","","",[=[]=]) DataInsert("Galneryus","","",[=[]=]) DataInsert("Gordon","","",[=[]=]) DataInsert("HANABIE.","","",[=[]=]) DataInsert("hitorie","","",[=[]=]) DataInsert("Imperial Circus Dead Decadence","","",[=[]=]) DataInsert("Japanese Folk Metal","","",[=[]=]) DataInsert("Jupiter","","",[=[]=]) DataInsert("Kidorikko","","",[=[]=]) DataInsert("King Gnu","","",[=[]=]) DataInsert("Knuckle Chiwawa","","",[=[]=]) DataInsert("Linked Horizon","","",[=[]=]) DataInsert("LOVEBITES","","",[=[]=]) DataInsert("MAN WITH A MISSION","","",[=[]=]) DataInsert("Mary's Blood","","",[=[]=]) DataInsert("MAXIMUM THE HORMONE","","",[=[]=]) DataInsert("Mrs. GREEN APPLE","","",[=[]=]) DataInsert("MUTANT MONSTER","","",[=[]=]) DataInsert("NEMOPHILA","","",[=[]=]) DataInsert("Official HIGE DANdism","","",[=[]=]) DataInsert("Otoboke Beaver","","",[=[]=]) DataInsert("Roselia","","",[=[]=]) DataInsert("Ryokuoushoku Shakai","","",[=[]=]) DataInsert("SCANDAL","","",[=[]=]) DataInsert("SEKAI NO OWARI","","",[=[]=]) DataInsert("SPYAIR","","",[=[]=]) DataInsert("Shinsei Kamattechan","","",[=[]=]) DataInsert("SHOW-YA","","",[=[]=]) DataInsert("SiM","","",[=[]=]) DataInsert("spira・spica","","",[=[]=]) DataInsert("Survive Said The Prophet","","",[=[]=]) DataInsert("the GazettE","","",[=[]=]) DataInsert("the peggies","","",[=[]=]) DataInsert("TRiDENT","","",[=[]=]) DataInsert("Unlucky Morpheus","","",[=[]=]) DataInsert("Wagakki Band","","",[=[]=]) DataInsert("Who-ya Extended","","",[=[]=]) DataInsert("X JAPAN","","",[=[]=]) DataInsert("YOASOBI","","",[=[]=]) DataInsert("Yorushika","","",[=[]=]) DataInsert("Yousei Teikoku","","",[=[]=]) DataInsert("Ziyoou-Vachi","","",[=[]=]) end

function PopulateSoloist DataInsert("2&","","",[=[]=]) DataInsert("Ado","","",[=[]=]) DataInsert("Akase Akari","","",[=[]=]) DataInsert("Akiyama Kiro","","",[=[]=]) DataInsert("Aoi Eir","","",[=[]=]) DataInsert("DAOKO","","",[=[]=]) DataInsert("GARUDA","","",[=[]=]) DataInsert("Haru Nemuri","","",[=[]=]) DataInsert("Higuchi Ai","","",[=[]=]) DataInsert("Horiuchi Marina","","",[=[]=]) DataInsert("Hoshino Gen","","",[=[]=]) DataInsert("Ito Mio","","",[=[]=]) DataInsert("Iwai Yukiko","","",[=[]=]) DataInsert("Juuyondaime Toire no Hanako-san","","",[=[]=]) DataInsert("Kanou Emiri","","",[=[]=]) DataInsert("Kosaka Riyu","","",[=[]=]) DataInsert("KOTO","","",[=[]=]) DataInsert("KOTOKO","","",[=[]=]) DataInsert("LiSA","","",[=[]=]) DataInsert("marble≠marble","","",[=[Tnaka is a solo idol that performs in the techno project marble≠marble.]=]) DataInsert("N Feni","","",[=[]=]) DataInsert("Nono Aimi","","",[=[]=]) DataInsert("Okinawa Electric Girl Saya","","",[=[]=]) DataInsert("Oomori Seiko","","",[=[]=]) DataInsert("Rie a.k.a. Suzaku","","",[=[]=]) DataInsert("Sakurai Yune","","",[=[]=]) DataInsert("Sawano Hiroyuki","","",[=[]=]) DataInsert("Shiina Hikari","","",[=[]=]) DataInsert("Tatsumi Rika (1965)","Tatsumi Rika","",[=[]=]) DataInsert("Tsukimori Kaede","","",[=[]=]) DataInsert("Vaundy","","",[=[]=]) DataInsert("Vickeblanka","","",[=[]=]) DataInsert("Yajima Mai","","",[=[]=]) DataInsert("yama","","",[=[]=]) DataInsert("Yamazaki Mayumi","","",[=[]=]) DataInsert("Yonezu Kenshi","","",[=[]=]) DataInsert("YUC'e","","",[=[]=]) DataInsert("Yunomi","","",[=[]=]) DataInsert("Yuuri (Singer-songwriter)","Yuuri","",[=[]=]) DataInsert("ZAQ","","",[=[]=]) end

function PopulateGroup DataInsert("2i2","","",[=[]=]) DataInsert("340.29m/s","","",[=[]=]) DataInsert("&Ch!ll","","",[=[]=]) DataInsert(".BPM","","",[=[]=]) DataInsert("@onefive","","",[=[]=]) DataInsert("26-Ji no Masquerade","","",[=[]=]) DataInsert("340.29m/s","","",[=[]=]) DataInsert("8bitBRAIN","","",[=[]=]) DataInsert("A.B.C-Z","","",[=[]=]) DataInsert("Aiiro Asterism","","",[=[]=]) DataInsert("Alice Juban","","",[=[]=]) DataInsert("alliance","","",[=[]=]) DataInsert("Amaterasu","","",[=[]=]) DataInsert("Angel Sisters","","",[=[]=]) DataInsert("Angel♡Heart","","",[=[]=]) DataInsert("Anthurium","","",[=[]=]) DataInsert("Aqua Note","","",[=[]=]) DataInsert("Armor Girls","","",[=[]=]) DataInsert("Atarashii Gakkou no Leaders","","",[=[]=]) DataInsert("BABYBEARD","","",[=[]=]) DataInsert("BeForU","","",[=[]=]) DataInsert("Bellring Shoujo Heart","","",[=[]=]) DataInsert("BLUEGOATS","","",[=[]=]) DataInsert("Boku wa Mada Shinanai","","",[=[]=]) DataInsert("BROKEN BY THE SCREAM","","",[=[]=]) DataInsert("chelmico","","",[=[]=]) DataInsert("Chouonpa","","",[=[]=]) DataInsert("chuLa","","",[=[]=]) DataInsert("Ciào Smiles","","",[=[]=]) DataInsert("Cinder-ella","","",[=[]=]) DataInsert("COLORLESS","","",[=[]=]) DataInsert("CROSSNOESIS","","",[=[]=]) DataInsert("CY8ER","","",[=[]=]) DataInsert("Dempagumi.inc","","",[=[]=]) DataInsert("DEARDEVIL","","",[=[]=]) DataInsert("DESURABBITS","","",[=[]=]) DataInsert("DokidokiDreamCampus+","","",[=[]=]) DataInsert("DoublePeace","","",[=[]=]) DataInsert("EASTER GIRLS","","",[=[]=]) DataInsert("FiDZ","","",[=[]=]) DataInsert("Gekizyou Refrain","","",[=[]=]) DataInsert("HAMIDASYSTEM","","",[=[]=]) DataInsert("Hamu!STAR","","",[=[]=]) DataInsert("HARP STAR","","",[=[]=]) DataInsert("HEROINES","","",[=[]=]) DataInsert("Hey! Say! JUMP","","",[=[]=]) DataInsert("Higeki no Heroine Syndrome","","",[=[]=]) DataInsert("Hikicomoteikoku","","",[=[]=]) DataInsert("Ichizen!","","",[=[]=]) DataInsert("iLiFE!","","",[=[]=]) DataInsert("INUWASI","","",[=[]=]) DataInsert("Item wa Teru Teru Nomi 3","","",[=[]=]) DataInsert("JAM Project","","",[=[]=]) DataInsert("Jyujyu","","",[=[]=]) DataInsert("Kamen Joshi","","",[=[]=]) DataInsert("Kamikaze Sensation","","",[=[]=]) DataInsert("KAQRIYOTERROR","","",[=[]=]) DataInsert("KATA☆CHU","","",[=[]=]) DataInsert("KAT-TUN","","",[=[]=]) DataInsert("Konyanko","","",[=[]=]) DataInsert("LADYBABY","","",[=[]=]) DataInsert("Last Idol","","",[=[]=]) DataInsert("Lil na Valley","","",[=[]=]) DataInsert("link laze","","",[=[]=]) DataInsert("Little Glee Monster","","",[=[]=]) DataInsert("L★ROCK BAB","","",[=[]=]) DataInsert("L・I・E・P","","",[=[]=]) DataInsert("M!LK","","",[=[]=]) DataInsert("MAD JAMIE","","",[=[]=]) DataInsert("MAG!C☆PRINCE","","",[=[]=]) DataInsert("MANACLE","","",[=[]=]) DataInsert("Marble Angel","","",[=[]=]) DataInsert("MELON BATAKE A GO GO","","",[=[]=]) DataInsert("MERUCHU","","",[=[]=]) DataInsert("MIGMA SHELTER","","",[=[]=]) DataInsert("Minna no Kodomo-chan","","",[=[]=]) DataInsert("miscast","","",[=[]=]) DataInsert("misola de edison","","",[=[]=]) DataInsert("Monoclone","","",[=[]=]) DataInsert("NECRONOMIDOL","","",[=[]=]) DataInsert("NEO JAPONISM","","",[=[]=]) DataInsert("NiceToMeetYou","","",[=[]=]) DataInsert("NILKLY","","",[=[]=]) DataInsert("OHMIKAMI","","",[=[]=]) DataInsert("One Chance Yeah Hoi!","","",[=[]=]) DataInsert("OnePixcel","","",[=[]=]) DataInsert("Onyanko Club","","",[=[]=]) DataInsert("Paradox Risk","","",[=[]=]) DataInsert("PassCode","","",[=[]=]) DataInsert("PATI PATI CANDY...☆","","",[=[]=]) DataInsert("PIGGS","","",[=[]=]) DataInsert("PiXMiX","","",[=[]=]) DataInsert("PLANCK STARS","","",[=[]=]) DataInsert("Policy Nante Gongo Doudan!","","",[=[]=]) DataInsert("Ponkotsu Konpo","","",[=[]=]) DataInsert("POPPING EMO","","",[=[]=]) DataInsert("Pu Lathessa","","",[=[]=]) DataInsert("QueeenMarionette","","",[=[]=]) DataInsert("RABBIT HUTCH","","",[=[]=]) DataInsert("reaction","","",[=[]=]) DataInsert("RILISREVERSE","","",[=[]=]) DataInsert("Runup!!","","",[=[]=]) DataInsert("Sakura Gakuin","","",[=[]=]) DataInsert("Satanic Punish","","",[=[]=]) DataInsert("Seifuku Koujo Iinkai","","",[=[]=]) DataInsert("Seireki13ya","","",[=[]=]) DataInsert("Sexy Zone","","",[=[]=]) DataInsert("Shinshi Todoroku, Gekijou no Gotoku.","","",[=[]=]) DataInsert("Smewthie","","",[=[]=]) DataInsert("SPACE PIRATES class ZERO","","",[=[]=]) DataInsert("SPARK SPEAKER","","",[=[]=]) DataInsert("STARMARIE","","",[=[]=]) DataInsert("Steam Girls","","",[=[]=]) DataInsert("Suneeds","","",[=[]=]) DataInsert("TENRIN","","",[=[]=]) DataInsert("TOKYO GIRLS' STYLE","","",[=[]=]) DataInsert("Tokyo Psychopath","","",[=[]=]) DataInsert("Twinkle","","",[=[]=]) DataInsert("ULTRA BUZZ","","",[=[]=]) DataInsert("Underbeasty","","",[=[]=]) DataInsert("WAGAMAMARAKIA","","",[=[]=]) DataInsert("Wa-Suta","","",[=[]=]) DataInsert("WONDER SNAKE","","",[=[]=]) DataInsert("X21","","",[=[]=]) DataInsert("XTEEN","","",[=[]=]) DataInsert("Yandoll","","",[=[]=]) DataInsert("YORUWA KOREKARA","","",[=[]=]) DataInsert("YURiMental","","",[=[]=]) DataInsert("Yurutto Kakumeidan","","",[=[]=]) DataInsert("Zenbu Kimi no Sei da.","","",[=[]=]) DataInsert("Zsasz","","",[=[]=]) DataInsert("ZOC","","",[=[]=]) DataInsert("ZOMBIE POWDER","","",[=[]=]) end

function PopulateArtist PopulateBand 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 = '#e15467' imgbackgroundcolor = '#3c3c3c' 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} }	--Using Template:Infocard/mobile to display collected data on mobile --emphasizing title on mobile 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} }	return ' ' .. desktop_output .. ' ' .. mobile_output .. ' ' end

function p.GetBand(frame) --loading predefined data into tables PopulateBand if(n_items > 0) then return ParsePage(frame, "Featured Band") end 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.GetArtist(frame) --loading predefined data into tables PopulateArtist if(n_items > 0) then return ParsePage(frame, "Featured Artist") end end return p