首页
随机
登录
设置
关于Bleap Wiki
免责声明
Bleap Wiki
搜索
查看“︁Module:曲目页面”︁的源代码
←
Module:曲目页面
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
local p = {} -- 数据页: 曲目列表 (曲绘/曲师/曲包/定数 的单一来源) local DATA_TITLE = '模板:曲目列表.json' local validator = require('模块:数据页校验') local parse = require('模块:署名解析') local ARTIST_MAP = '模板:曲师映射.json' local CHARTER_MAP = '模板:谱师映射.json' local function esc(s) return (s:gsub('|', '|')) end local function norm(s) return (s:gsub(' ', '_')) end -- Lua 中空字符串为真值, 必须显式判空 local function arg(frame, k, default) local v = frame.args[k] if v == nil or v == '' then return default end return v end local function fmt(v) if type(v) == 'number' then return string.format('%.1f', v) end return v or '' end local function loadJson(title) local t = mw.title.new(title) if not t or not t.exists then return nil end local ok, data = pcall(mw.text.jsonDecode, t:getContent()) if not ok then return nil end return data end -- 列表页里实际有小节的署名集合 local function knownCredits(data, lk, field, includeSpecial) local known = {} local function eat(list) for _, s in ipairs(list or {}) do local raw = s[field] if type(raw) == 'table' then for _, v in pairs(raw) do for _, pt in ipairs(parse.attribute(lk, v) or parse.parts(v)) do known[pt.base] = true end end else for _, pt in ipairs(parse.attribute(lk, raw) or parse.parts(raw)) do known[pt.base] = true end end end end eat(data.songs) if includeSpecial then eat(data.special) end return known end -- 署名 → 链到 [[<列表页>#主名义]](马甲/合作名义自动归并;无小节则纯文本) local function linkedCredits(raw, lk, page, known) if not raw or raw == '' then return '' end local parts = parse.attribute(lk, raw) or parse.parts(raw) local out = {} for _, pt in ipairs(parts) do local text = pt.rawPart or pt.base if known and not known[pt.base] then out[#out + 1] = esc(text) else out[#out + 1] = '[[' .. page .. '#' .. esc(pt.base) .. '|' .. esc(text) .. ']]' end end -- 本曲实际使用的名义(真·马甲/组合标签/带注释 才提示) local note = '' if parse.creditNote(raw, lk) and parse.norm(raw) ~= parse.norm(table.concat((function() local t = {} for _, pt in ipairs(parts) do t[#t + 1] = (pt.rawPart or pt.base) end return t end)(), ' / ')) then note = ' <span style="font-size:85%;color:#666">(名义:' .. esc(raw) .. ')</span>' end return table.concat(out, ' / ') .. note end local function loadData() return validator.load(DATA_TITLE) end local function findSong(data, name, specialOnly) if not specialOnly then for _, s in ipairs(data.songs or {}) do if s['曲名'] == name then return s, false end end end for _, s in ipairs(data.special or {}) do if s['曲名'] == name then return s, true end end return nil, false end local function langWrapName(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 function songArt(song, isSpecial) local art = song['曲绘'] or song['曲名'] or '' if isSpecial then art = art:gsub('(石墩子模式)$', '') .. '_石墩子模式' end return norm(art) end -- 自动生成解锁方式: 按曲包类型 local function autoUnlock(pack) if pack == '' or pack == nil then return '(待补充)' end if pack == '教程' then return '游戏内教学关卡,无需解锁' elseif pack == '剧情模式' then return '剧情模式内出现' elseif pack == '免费单曲' then return '无需解锁' elseif pack == '免费单曲(商店)' then return '前往[[商店#单曲|商店]]使用[[货币#瓶盖|瓶盖]]购买单曲' elseif pack == 'CORE基础卡' then return '前往[[商店#闪音卡|商店]]购买基础卡解锁' else return '前往[[商店#曲包|商店]]购买[[曲包列表#' .. esc(pack) .. '|' .. esc(pack) .. ']]解锁' end end function p.render(frame) local name = arg(frame, '曲名', '') if name == '' then return '<span class="error">未指定 |曲名= 参数</span>' end local data, err = loadData() if not data then return '<span class="error">' .. tostring(err) .. '</span>' end local specialOnly = arg(frame, '特殊', '') == '石墩子' local song, isSpecial = findSong(data, name, specialOnly) if not song then return '<span class="error">数据页中找不到曲目: ' .. esc(name) .. '(请检查 [[模板:曲目列表.json]])</span>' end local defaultTitle = isSpecial and (langWrapName(song) .. '(石墩子模式)') or song['曲名'] local title = arg(frame, '标题', defaultTitle) -- 标题先单独展开 ({{lang}} 嵌套在信息框参数内不会被最终 preprocess 二次展开) title = frame:preprocess(title) local art = songArt(song, isSpecial) local consts = song['定数'] or {} local out = {} local tagline = arg(frame, '标语', '') if tagline ~= '' then table.insert(out, '<div class="song-tagline">' .. tagline .. '</div>') end local artistLk = parse.buildLookup(loadJson(ARTIST_MAP)) local charterLk = parse.buildLookup(loadJson(CHARTER_MAP)) local knownArtists = knownCredits(data, artistLk, '曲师', true) local knownCharters = knownCredits(data, charterLk, '谱师', false) -- 信息框: 自动填 标题/图片/曲师/曲包/定数/谱师/时长/BPM, 手工传参可覆盖 table.insert(out, '{{曲目信息框') table.insert(out, '|标题= ' .. esc(title)) local imgOverride = arg(frame, '图片', '') if imgOverride ~= '' then table.insert(out, '|图片= ' .. imgOverride) else table.insert(out, '|图片= [[文件:曲绘-' .. esc(art) .. '.png|256px]]') end table.insert(out, '|曲师= ' .. arg(frame, '曲师', linkedCredits(song['曲师'], artistLk, '曲师列表', knownArtists))) -- 曲包: 手工传参优先; 否则自动生成指向 曲包列表#<曲包名> 的链接 local packArg = frame.args['曲包'] local packText = song['曲包'] or '' if packArg ~= nil and packArg ~= '' then packText = packArg elseif packText ~= '' then packText = '[[' .. '曲包列表#' .. esc(packText) .. '|' .. esc(packText) .. ']]' end table.insert(out, '|曲包= ' .. packText) table.insert(out, '|时长= ' .. esc(arg(frame, '时长', song['时长'] or ''))) table.insert(out, '|BPM= ' .. esc(arg(frame, 'BPM', song['BPM'] or ''))) local charters = song['谱师'] or {} for _, d in ipairs({ 'CASUAL', 'TOUGH', 'INSANE', 'PRO' }) do table.insert(out, '|' .. d .. '定数= ' .. fmt(consts[d])) table.insert(out, '|' .. d .. '谱师= ' .. arg(frame, d .. '谱师', linkedCredits(charters[d], charterLk, '谱师列表', knownCharters))) table.insert(out, '|' .. d .. '连击= ' .. esc(arg(frame, d .. '连击', ''))) end table.insert(out, '}}') -- 标准段落 -- 解锁方式: 手工传参优先, 否则按曲包自动生成 local unlock = arg(frame, '解锁方式', '') if unlock == '' then unlock = autoUnlock(song['曲包'] or '') end table.insert(out, '\n== 解锁方式 ==\n' .. unlock) table.insert(out, '\n== 游戏相关 ==\n=== 定数调整历史 ===\n' .. arg(frame, '定数调整历史', '(待补充)')) -- 其他相关子章节: 新参数优先, 兼容旧参数 |游戏相关= local otherRelated = arg(frame, '其他相关', '') local legacy = arg(frame, '游戏相关', '') if otherRelated == '' then otherRelated = legacy end if otherRelated == '' then otherRelated = '(待补充)' end table.insert(out, '\n=== 其他相关 ===\n' .. otherRelated) table.insert(out, '\n== 歌词 ==\n' .. arg(frame, '歌词', '纯音乐,请欣赏')) local other = arg(frame, '其他', '') if other ~= '' then table.insert(out, '\n== 其他 ==\n' .. other) end table.insert(out, '\n[[Category:曲目]]') -- 展开 {{曲目信息框}} 等模板 return frame:preprocess(table.concat(out, '\n')) end return p
此页面嵌入的页面:
Module:曲目页面/doc
(
查看源代码
)
返回
Module:曲目页面
。