Module:SongColor
Appearance
Documentation for this module may be created at Module:SongColor/doc
-- Module:SongColor (fixed)
-- Uses named |type= when provided; otherwise infers type from |peak=.
-- The FIRST unnamed argument is treated as the default color (e.g., "#E6E8FA").
local p = {}
local map = {
["no.1 hit song"] = "khaki",
["major hit song"] = "#ffce1b",
["top 5 hit song"] = "#ffd27f",
["top 10 hit song"] = "#E6E8FA",
["top 20 hit song"] = "#dfefff",
["charted song"] = "#f0f0f0",
}
local super_to_norm = {
["⁰"]="0", ["¹"]="1", ["²"]="2", ["³"]="3", ["⁴"]="4",
["⁵"]="5", ["⁶"]="6", ["⁷"]="7", ["⁸"]="8", ["⁹"]="9"
}
local function trim_collapse_lower(s)
s = tostring(s or "")
s = mw.ustring.gsub(s, "^%s+", "")
s = mw.ustring.gsub(s, "%s+$", "")
s = mw.ustring.gsub(s, "%s+", " ")
s = mw.ustring.lower(s)
return s
end
local function unlink(text)
text = tostring(text or "")
text = mw.ustring.gsub(text, "^%s*%[%[", "")
text = mw.ustring.gsub(text, "%]%]%s*$", "")
local pipe = mw.ustring.find(text, "|", 1, true)
if pipe then text = mw.ustring.sub(text, 1, pipe - 1) end
return text
end
local function superscripts_to_number(sup)
local norm = {}
for uchar in mw.ustring.gmatch(sup or "", ".") do
local d = super_to_norm[uchar]
if not d then return nil end
table.insert(norm, d)
end
return tonumber(table.concat(norm))
end
local function type_from_peak(peak_raw)
local peak = tostring(peak_raw or "")
peak = mw.ustring.gsub(peak, "^%s+", "")
peak = mw.ustring.gsub(peak, "%s+$", "")
if peak == "" then return nil end
-- Extract leading numeric part
local position_str, rest = peak:match("^(%d+)(.*)$")
if not position_str then return nil end
local position = tonumber(position_str)
if position == 1 then
if rest == "" then
return "no.1 hit song"
end
-- superscripts?
local super_only = true
for uchar in mw.ustring.gmatch(rest, ".") do
if not super_to_norm[uchar] then
super_only = false; break
end
end
if super_only then
local expn = superscripts_to_number(rest)
if expn then
if expn >= 5 then return "major hit song" else return "no.1 hit song" end
end
end
-- caret form 1^N
local caret_num = peak:match("^1%^%s*(%d+)$")
if caret_num then
local expn = tonumber(caret_num)
if expn then
return (expn >= 5) and "major hit song" or "no.1 hit song"
end
end
elseif position >= 2 and position <= 60 then
-- For non-1, ignore rest (superscripts), use position
if position <= 5 then
return "top 5 hit song"
elseif position <= 10 then
return "top 10 hit song"
elseif position <= 20 then
return "top 20 hit song"
else
return "charted song"
end
end
return nil
end
local function color_for_type(raw_type, default_color)
if not raw_type or raw_type == "" then return default_color end
local key = trim_collapse_lower(unlink(raw_type))
return map[key] or default_color
end
function p.color(frame)
-- IMPORTANT: prefer module-call args first, then fall back to parent
local margs = frame.args or {}
local pargs = (frame:getParent() and frame:getParent().args) or {}
-- FIRST unnamed arg is the default color; or use |default=
local default_color = margs[1] or pargs[1] or margs.default or pargs.default or "#E6E8FA"
-- Only accept named |type= (avoid collision with default color)
local typ = margs.type or pargs.type or ""
local peak = margs.peak or pargs.peak
if typ ~= "" then
return color_for_type(typ, default_color)
end
local inferred = type_from_peak(peak)
if inferred then
return color_for_type(inferred, default_color)
end
return default_color
end
return p