Module:Firehose links

From PickiPedia: A knowledge base of bluegrass, old time psychedelic jams, and other public domain music
Jump to navigationJump to search

Documentation for this module may be created at Module:Firehose links/doc

-- Helpers for Template:Firehose.
--
-- The firehose runs its #ask with link=none, because Semantic MediaWiki
-- otherwise hands the template a pre-rendered link for every value, which
-- defeats both #titleparts and any attempt to relabel the episode link.
--
-- The cost of link=none is that topic names arrive as plain text, comma-joined
-- when an episode has more than one. Linking that string whole would produce a
-- single broken redlink -- one link containing "Sam Bush, Jerry Douglas" -- so
-- split it and link each name on its own.
--
-- Note for future editors: do not wrap this header in a --[==[ ]==] block
-- comment containing wiki link syntax. Lua reads the inner brackets as nested
-- long brackets and refuses to load the module.

local p = {}

-- Values the title parser sometimes yields that are not entities, and so
-- should be shown but never linked.
local NOT_AN_ENTITY = {
	["and more"] = true,
	["more"] = true,
	["etc"] = true,
	["etc."] = true,
}

local function split( raw )
	local out = {}
	for name in ( ( raw or "" ) .. "," ):gmatch( "%s*(.-)%s*," ) do
		if name ~= "" then
			table.insert( out, name )
		end
	end
	return out
end

local function link( name )
	if NOT_AN_ENTITY[ name:lower() ] then
		return name
	end
	return "[[" .. name .. "]]"
end

-- Which of these names are pages in Category:People.
--
-- One query for the whole row rather than one per name, since a tribute
-- episode can name nine people and a firehose shows twenty-five rows.
local function peopleAmong( frame, names )
	local candidates = {}
	for _, name in ipairs( names ) do
		if not NOT_AN_ENTITY[ name:lower() ] then
			table.insert( candidates, name )
		end
	end
	if #candidates == 0 then
		return {}
	end

	local found = frame:callParserFunction( "#ask", {
		"[[Category:People]][[" .. table.concat( candidates, "||" ) .. "]]",
		"format=list",
		"link=none",
		"sep=;",
		"searchlabel=",
		"limit=50",
	} )

	-- SMW wraps each value in span markup, even with link=none, and may hand
	-- the result back as a strip marker. Reduce it to the bare names first, or
	-- "<span class=smw-value>Billy Strings</span>" never equals Billy Strings
	-- and every person gets filed as a topic.
	found = mw.text.unstrip( found ):gsub( "<[^>]+>", "" )

	local set = {}
	for name in ( found .. ";" ):gmatch( "%s*(.-)%s*;" ) do
		if name ~= "" then
			set[ name ] = true
		end
	end
	return set
end

-- Every subject of an episode, linked, and filed as people or topics.
--
-- A page in Category:People is a person. A page that exists and is not in it —
-- a band, a festival, a tune — is a topic. A name with no page yet is filed
-- with the people, because nothing yet says otherwise and nearly everything
-- the title parser extracts is a personal name. That default corrects itself:
-- the moment somebody writes East Nash Grass up as a band, it moves across.
function p.subjects( frame )
	local names = split( frame.args[1] )
	if #names == 0 then
		return ""
	end

	local people = peopleAmong( frame, names )
	local persons, topics = {}, {}

	for _, name in ipairs( names ) do
		local title = mw.title.new( name )
		if people[ name ] then
			table.insert( persons, link( name ) )
		elseif title and title.exists then
			table.insert( topics, link( name ) )
		else
			table.insert( persons, link( name ) )
		end
	end

	local parts = {}
	if #persons > 0 then
		table.insert( parts, "people " .. table.concat( persons, ", " ) )
	end
	if #topics > 0 then
		table.insert( parts, "topics " .. table.concat( topics, ", " ) )
	end
	return table.concat( parts, " &middot; " )
end

-- Every subject linked, unlabelled. Kept for callers that want a plain list.
function p.topiclinks( frame )
	local out = {}
	for _, name in ipairs( split( frame.args[1] ) ) do
		table.insert( out, link( name ) )
	end
	return table.concat( out, ", " )
end

-- Former name, kept so an older revision of a calling template does not break.
p.guestlinks = p.topiclinks

return p