Module:曲目列表
此模块的文档可以在Module:曲目列表/doc创建
local p = {}
-- 数据页: 存 JSON 原文 (json 内容模型)
local DATA_TITLE = '模板:曲目列表.json'
local function esc(s)
-- 防御 wikitext 特殊字符 (当前数据无, 以防未来出现)
return (s:gsub('|', '|'))
end
-- 链接目标: # 是 MediaWiki 的锚点分隔符, 标题里一律换成全角 #
-- 优先用「链接名」字段; 没有就回退到曲名并自动替换 (双保险)
-- 注意: 光用 <nowiki>#</nowiki> 之类的转义救不了 —— # 在标题解析阶段就被切走了
local function pageName(song, suffix)
local n = song['链接名'] or song['曲名']
if suffix then
n = n .. '(' .. suffix .. ')'
end
return (n:gsub('#', '#'))
end
local function norm(s)
-- 曲绘文件名规范: 空格 -> 下划线
return (s:gsub(' ', '_'))
end
local function langWrap(song)
local lang = song['lang']
if lang == 'ja' then
return '{{lang|ja|' .. esc(song['曲名']) .. '}}'
elseif lang == 'zh-Hant' then
return '{{lang|zh-Hant|' .. esc(song['曲名']) .. '}}'
end
return esc(song['曲名'])
end
local DIFF_CLASS = { CASUAL = 'cas', TOUGH = 'tou', INSANE = 'ins', PRO = 'pro' }
local function diffsCell(diffs)
if #diffs == 1 and diffs[1] == '?' then
return '? ? ?'
end
local out = {}
for _, d in ipairs(diffs) do
table.insert(out, '{{难度|' .. d .. '}}')
end
return table.concat(out, '<br>')
end
local function songRow(song, suffix)
local art = song['曲绘'] or ''
if suffix then
art = art:gsub('(' .. suffix .. ')$', '') .. '_' .. suffix
end
local link = esc(song['曲名']) .. (suffix and ('(' .. suffix .. ')') or '')
local artist = esc(song['曲师'] or '')
return '|-\n| [[File:曲绘-' .. norm(art) .. '.png|96px|link=曲目:' .. link
.. ']] || [[' .. '曲目:' .. link .. '|' .. langWrap(song) .. ']] || '
.. artist .. ' || style="text-align:center" | ' .. diffsCell(song['难度'])
end
local function tableOpen()
return '{| class="wikitable sortable" style="width:100%"\n! 曲绘 !! 曲名 !! 曲师 !! style="text-align:center" | 难度'
end
local function loadData()
local t = mw.title.new(DATA_TITLE)
if not t or not t.exists then
return nil, '数据页不存在: [[' .. DATA_TITLE .. ']]'
end
local ok, data = pcall(mw.text.jsonDecode, t:getContent())
if not ok or type(data) ~= 'table' then
return nil, '数据页 JSON 解析失败: [[' .. DATA_TITLE .. ']]'
end
return data
end
function p.render(frame)
local demomode = frame and frame.args['demo']
local data, err = loadData()
if not data then
return '<span class="error">' .. tostring(err) .. '</span>'
end
local out = { tableOpen() }
for _, song in ipairs(data.songs) do
table.insert(out, songRow(song))
end
table.insert(out, '|}')
table.insert(out, '\n== 石墩子模式 ==')
table.insert(out, '愚人节限定的特殊谱面,正常游玩时不会出现。石墩子模式中,会将游戏角色强行锁定为石墩子:\n')
table.insert(out, tableOpen())
for _, song in ipairs(data.special) do
table.insert(out, songRow(song, '石墩子模式'))
end
table.insert(out, '|}')
if not demomode then
table.insert(out, '\n[[Category:曲目]]')
end
-- Scribunto 返回文本中的 {{模板}} 不会被自动展开, 必须显式 preprocess
return frame:preprocess(table.concat(out, '\n'))
end
return p