Module:VOCALOID Songbox
来自Vocawiki
更多操作
此模块的文档可以在Module:VOCALOID Songbox/doc创建
local strings = require('Module:Strings')
local get = require('Module:Get')
local acandy = require('Module:ACandy')
local a, Fragment, Raw = acandy.a, acandy.Fragment, acandy.Raw
local div, span = a.div, a.span
local trim = mw.text.trim
---@alias Image {
--- file: string,
--- caption: string?,
--- size: string?,
---}
---@alias Platform { id: string }
---@alias Platforms {
--- nico: Platform?,
--- bili: Platform?,
--- acfun: Platform?,
--- ncm: Platform?,
--- ytb: Platform?,
--- other_info: string?,
---}
---@alias Style {
--- general: string?,
--- [1]: string?,
--- [2]: string?,
--- [3]: string?,
---}
---@param str string | nil
---@return string | nil
local function clean(str)
if not str then return nil end
str = trim(str)
return str ~= '' and str or nil
end
---@param s1 string | nil
---@param s2 string | nil
---@return string | nil
local function merge(s1, s2)
local merged = trim((s1 or '')..(s2 or ''))
return merged ~= '' and merged or nil
end
local function raw_or_empty(v)
return v ~= nil and Raw(v) or ''
end
local c = {} -- components
---@param props {
--- image: Image?,
--- tabs: string?,
--- title: string?,
--- uploader: string?,
--- producer: string?,
--- uploaded_at: string?,
--- views: string?,
--- note: string?,
--- singer: string?,
--- platforms: Platforms,
--- colors: Style,
--- text_styles: Style,
---}
function c.SongBox(props)
local colors = props.colors
local text_styles = props.text_styles
local function THeader(nth, content)
local th_style = colors[nth] or colors.general
if th_style then
th_style = 'background:'..th_style
else
th_style = 'background: #66CDAA; color: #FFF;'
end
return div['songbox_th'] {
style = th_style,
span {
style = 'display: inline-block;'..(text_styles[nth] or text_styles.general or ''),
content,
},
}
end
return div['songbox'] {
props.image and c.Image(props.image) or '',
raw_or_empty(props.tabs),
c.Title(props.title),
c.Note(props),
THeader(1, '演唱'),
div['songbox_td'] / raw_or_empty(props.singer),
THeader(2, props.uploader and 'UP主' or 'P主'),
div['songbox_td'] / raw_or_empty(props.uploader or props.producer),
THeader(3, '链接'),
div['songbox_td'] / c.Links(props.platforms),
}
end
---@param props Image
function c.Image(props)
local frame = mw.getCurrentFrame()
return Raw(frame:expandTemplate { title = '氛围图片', args = props })
end
---@param title string?
function c.Title(title)
if not title then
return div['songbox_titles unknown']
end
local titles = strings.split(title, '%s*<br%s*/?>%s*')
local main_title = table.remove(titles, 1)
return div['songbox_titles'] {
div['songbox_main-title'] / Raw(main_title),
Raw(table.concat(titles, '<br>')),
}
end
---@param props {uploaded_at: string?, views: string?, note: string?}
function c.Note(props)
local content = ''
if props.uploaded_at then
content = '于'..props.uploaded_at..'投稿'
end
if props.views then
if #content > 0 then
content = content..',再生数为'..props.views
else
content = '再生数为'..props.views
end
end
if props.note then
if #content > 0 then
content = content..' '..props.note
else
content = props.note
end
end
return content ~= '' and div['songbox_note'] {
raw_or_empty(content),
} or ''
end
---@param props Platforms
function c.Links(props)
local links = Fragment()
for platform in get(
{ key = 'nico', url = 'https://www.nicovideo.jp/watch/%s', name = 'Nicovideo' },
{ key = 'bili', url = 'https://www.bilibili.com/video/%s', name = 'bilibili' },
{ key = 'acfun', url = 'http://www.acfun.cn/v/%s', name = 'AcFun' },
{ key = 'ncm', url = 'https://music.163.com/#/song?id=%s', name = '网易云' },
{ key = 'ytb', url = 'https://www.youtube.com/watch?v=%s', name = 'YouTube' }
):filter(function (x) return props[x.key] end) do
local data = props[platform.key] ---@cast data Platform
links:insert(
Raw(('[%s %s] '):format(platform.url:format(data.id), platform.name))
)
end
if props.other_info then
links:insert(Raw(props.other_info))
end
return links
end
local p = {
components = c,
}
local function get_by_aliases(t, ...)
local n = select('#', ...)
for i = 1, n do
local key = select(i, ...)
local item = t[key]
if item ~= nil then
return item
end
end
return nil
end
--[[
image
圖片信息 + 图片信息
圖片大小 > 图片大小
tabs
歌曲名称
再生 + 投稿时间 + 其他资料
演唱
UP主 > P主
nnd_id + bb_id + ac_id + wyy_id + yt_id + 链接
颜色
颜色1
颜色2
颜色3
文字样式
文字样式1
文字样式2
文字样式3
]]
function p.from_args(uncleaned_args)
local args = {} ---@type table<string, string | nil>
for k, v in pairs(uncleaned_args) do
args[k] = clean(v)
end
local props = {
image = args.image and {
file = args.image,
caption = merge(args['圖片信息'], args['图片信息']),
size = get_by_aliases(args, '圖片大小', '图片大小'),
},
tabs = args.tabs,
title = args['歌曲名称'],
uploader = args['UP主'],
producer = args['P主'],
uploaded_at = args['投稿时间'],
views = args['再生'],
note = args['其他资料'],
singer = args['演唱'],
platforms = {
nico = args.nnd_id and { id = args.nnd_id },
bili = args.bb_id and { id = args.bb_id },
acfun = args.ac_id and { id = args.ac_id },
ncm = args.wyy_id and { id = args.wyy_id },
ytb = args.yt_id and { id = args.yt_id },
other_info = args['链接'],
},
colors = {
general = args['颜色'],
args['颜色1'],
args['颜色2'],
args['颜色3'],
},
text_styles = {
general = args['文字样式'],
args['文字样式1'],
args['文字样式2'],
args['文字样式3'],
},
}
return c.SongBox(props)
end
function p.from_frame(frame)
return p.from_args(frame.args)
end
function p.from_parent(frame)
local parent = frame:getParent()
return p.from_frame(parent)
end
return p