| 此模块使用Lua语言: |
这个模板仿照YouTube和Bilibili超级留言/醒目留言的样式,可以生成一个类似的框。
{{SC|b|money=100|currency=USD|message=自定义信息|username=Leranjun|rank=总督|is-user=true|image=https://pic.downk.cc/item/5eb666ddc2a9a83be5ba165a.jpg|external=true|width=80%|image-up=0px|image-right=0px}}
参数说明:
仅BSC:
| 等级 | 参数 |
|---|---|
| 舰长 | 舰长、Captain或c |
| 提督 | 提督、Admiral或a |
| 总督 | 总督、Viceroy或v |
其他可调参数不建议使用。详情请查看模板源代码。
{{SC}}
| 代码 | 效果 |
|---|---|
{{SC|yt}}
|
FINAL
US$ 30
请输入发送内容!
|
{{SC|yt|money=300|message=这是一串超长的内容,我不知道它会不会出框。诶?不会吗?那它支持换行吗?<br />哦,支持换行。真好。}}
|
FINAL
US$ 300
这是一串超长的内容,我不知道它会不会出框。诶?不会吗?那它支持换行吗?
哦,支持换行。真好。 |
{{SC|yt|money=300|currency=CNY}}
|
FINAL
¥ 300
请输入发送内容!
|
{{SC|yt|username=Leranjun|is-user=true}}
|
Leranjun
US$ 30
请输入发送内容!
|
{{SC|yt|username=萌百娘}}
|
萌百娘
US$ 30
请输入发送内容!
|
{{SC|yt|image=大萌字.svg}}
|
FINAL
US$ 30
请输入发送内容!
|
{{SC|yt|image=https://pic.downk.cc/item/5eb666ddc2a9a83be5ba165a.jpg|external=true}}
|
请输入发送内容!
|
{{SC|yt|width=80%}}
|
FINAL
US$ 30
请输入发送内容!
|
| 代码 | 效果 |
|---|---|
{{SC|b}}
|
阿卡林
300电池
输入留言内容传递自己的心意吧!
メッセージを入力して、心を届けよう! |
{{SC|b|money=10|message=穷人没有权利出来说话。——鲁迅}}
|
阿卡林
100电池
穷人没有权利出来说话。——鲁迅
|
{{SC|b|money=300|message=注意啦!<br />右下角的边框会随金额变化哦~}}
|
阿卡林
3000电池
注意啦!
右下角的边框会随金额变化哦~ |
{{SC|b|money=3000000|message=其实,我在这里写什么都没用}}
|
阿卡林
30000000电池
其实,我在这里写什么都没用
|
{{SC|b|message=你好!|message-ja=こんにちは!}}
|
阿卡林
300电池
你好!
こんにちは! |
{{SC|b|money=300|currency=USD}}
|
阿卡林
21620电池
输入留言内容传递自己的心意吧!
メッセージを入力して、心を届けよう! |
{{SC|b|username=Leranjun|is-user=true}}
|
Leranjun
300电池
输入留言内容传递自己的心意吧!
メッセージを入力して、心を届けよう! |
{{SC|b|username=萌百娘}}
|
萌百娘
300电池
输入留言内容传递自己的心意吧!
メッセージを入力して、心を届けよう! |
{{SC|b|image=大萌字.svg}}
|
阿卡林
300电池
输入留言内容传递自己的心意吧!
メッセージを入力して、心を届けよう! |
{{SC|b|image=https://i.loli.net/2020/06/09/BiPVsW7fpTzCAe1.jpg|external=true}}
|
阿卡林
300电池
输入留言内容传递自己的心意吧!
メッセージを入力して、心を届けよう! |
{{SC|b|width=80%}}
|
阿卡林
300电池
输入留言内容传递自己的心意吧!
メッセージを入力して、心を届けよう! |
{{SC|b|money=500|rank=舰长|message=我是舰长}}
|
阿卡林
5000电池
我是舰长
|
{{SC|b|money=1000|rank=提督|message=我是提督}}
|
阿卡林
10000电池
我是提督
|
{{SC|b|money=3000|rank=总督|message=我是总督}}
|
阿卡林
30000电池
我是总督
|
由于部分用户错误地使用了这个模板,现在已经加上了更严格的判断。乐然提醒您:请务必不要这样滥用模板。滥用模板的后果自负。
| 代码 | 效果 | 注释 |
|---|---|---|
{{SC|xyz}}
|
错误:无法识别的平台参数。 | 错误使用平台参数。 |
{{SC|yt|money=3.1415926}}
|
错误:无法识别的money参数。 | money参数为小数。 |
{{SC|b|money=3.1415926}}
|
错误:无法识别的money参数。 | |
{{SC|yt|money=1+2}}
|
FINAL
US$ 30
请输入发送内容!
|
money参数中含有特殊字符。 |
{{SC|b|money=3*10}}
|
阿卡林
300电池
输入留言内容传递自己的心意吧!
メッセージを入力して、心を届けよう! | |
{{SC|yt|money=2020/10/30}}
|
FINAL
US$ 30
请输入发送内容!
|
| 等级 | 上半背景色 | 下半背景色 | 用户名文字 | 留言金额文字 | 留言内容文字 |
|---|---|---|---|---|---|
| 一(深蓝) | rgb(21,101,192)
|
等级一不可输入留言 | rgba(255,255,255,0.7)
|
rgb(255,255,255)
|
等级一不可输入留言 |
| 二(青) | rgb(0,184,212)
|
rgb(0,229,255)
|
rgba(0,0,0,0.7)
|
rgb(0,0,0)
|
rgb(0,0,0)
|
| 三(绿) | rgb(0,191,165)
|
rgb(29,233,182)
|
rgba(0,0,0,0.54)
|
rgb(0,0,0)
|
rgb(0,0,0)
|
| 四(黄) | rgb(255,179,0)
|
rgb(255,202,40)
|
rgba(0,0,0,0.54)
|
rgba(0,0,0,0.875)
|
rgba(0,0,0,0.875)
|
| 五(橙) | rgb(230,81,0)
|
rgb(245,124,0)
|
rgba(255,255,255,0.7)
|
rgba(255,255,255,0.875)
|
rgba(255,255,255,0.875)
|
| 六(品红) | rgb(194,24,91)
|
rgb(233,30,99)
|
rgba(255,255,255,0.7)
|
rgb(255,255,255)
|
rgb(255,255,255)
|
| 七(红) | rgb(208,0,0)
|
rgb(230,33,23)
|
rgba(255,255,255,0.7)
|
rgb(255,255,255)
|
rgb(255,255,255)
|
| 新会员 | rgb(15,157,88)
|
不可用 | rgb(255,255,255)
|
rgba(255,255,255,0.7)
|
不可用 |
| (新会员欢迎信息) | |||||
--[[
模块:SC
原作者:YouTube超级留言:User:FINAL;Bilibili醒目留言:User:RabBIThole
参数调整、模板整合:User:Leranjun
改造为Lua模块:User:没有羽翼的格雷塔
模板更新日期:2023-01-25
模块化:2025-12-30
汇率更新日期:见Template:SC/currency
]]
local p = {}
-- 辅助函数:获取参数,处理空值
local function getArg(args, argName, default)
local value = args[argName]
if value == nil or value == '' then
return default
end
return mw.text.trim(value)
end
-- 辅助函数:字符串转小写
local function lc(str)
return mw.ustring.lower(str or '')
end
-- 辅助函数:字符串转大写
local function uc(str)
return mw.ustring.upper(str or '')
end
-- 辅助函数:判断字符串是否为整数
local function isInteger(n)
return tonumber(n) and math.floor(tonumber(n)) == tonumber(n)
end
-- 辅助函数:获取图片路径
local function getImagePath(frame, args, username, isUser)
local image = getArg(args, 'image', nil)
local external = getArg(args, 'external', '')
if image then
if external ~= '' then
return image
else
return frame:callParserFunction('filepath',{'File:' .. image})
end
else
if isUser then
return 'https://commons.moegirl.org.cn/index.php?action=avatar&userName=' .. (username or '')
else
return frame:callParserFunction('filepath',{'File:铃音捏脸.png'})
end
end
end
-- 辅助函数:获取汇率
local function getExchangeRate(frame, fromCurrency, toCurrency)
if fromCurrency == toCurrency then
return 1
end
local rate = frame:expandTemplate{title = 'SC/currency', args = {fromCurrency, toCurrency}}
return tonumber(rate) or 1
end
-- 辅助函数:获取货币符号
local function getCurrencySymbol(currency)
local symbols = {
CNY = '¥',
USD = 'US$',
TWD = 'NT$',
AUD = 'A$',
JPY = 'JP¥',
HKD = 'HK$',
SGD = 'S$',
MOP = 'MOP$'
}
return symbols[uc(currency)] or 'US$'
end
-- 辅助函数:根据金额计算YouTube留言颜色
local function getYouTubeColors(conv)
if conv < 2 then
return {
top = 'rgb(21,101,192)',
bottom = 'rgb(25,121,230)',
username = 'rgba(255,255,255,0.7)',
money = 'rgb(255,255,255)',
message = 'rgb(255,255,255)'
}
elseif conv < 5 then
return {
top = 'rgb(0,184,212)',
bottom = 'rgb(0,229,255)',
username = 'rgba(0,0,0,0.7)',
money = 'rgb(0,0,0)',
message = 'rgb(0,0,0)'
}
elseif conv < 10 then
return {
top = 'rgb(85,188,166)',
bottom = 'rgb(109,230,184)',
username = 'rgba(0,0,0,0.54)',
money = 'rgba(0,0,0,0.875)',
message = 'rgba(0,0,0,0.875)'
}
elseif conv < 20 then
return {
top = 'rgb(255,179,0)',
bottom = 'rgb(255,202,40)',
username = 'rgba(0,0,0,0.54)',
money = 'rgba(0,0,0,0.875)',
message = 'rgba(0,0,0,0.875)'
}
elseif conv < 50 then
return {
top = 'rgb(230,81,0)',
bottom = 'rgb(245,124,0)',
username = 'rgba(255,255,255,0.7)',
money = 'rgba(255,255,255,0.875)',
message = 'rgba(255,255,255,0.875)'
}
elseif conv < 100 then
return {
top = 'rgb(194,24,91)',
bottom = 'rgb(233,30,99)',
username = 'rgba(255,255,255,0.7)',
money = 'rgb(255,255,255)',
message = 'rgb(255,255,255)'
}
else
return {
top = 'rgb(208,0,0)',
bottom = 'rgb(230,33,23)',
username = 'rgba(255,255,255,0.7)',
money = 'rgb(255,255,255)',
message = 'rgb(255,255,255)'
}
end
end
-- 辅助函数:根据金额计算Bilibili样式
local function getBilibiliStyles(conv)
local styles = {
top = '#EDF5FF',
bottom = '#2A60B2',
bottomRight = nil,
message = '输入留言内容传递自己的心意吧!'
}
if conv < 30 then
styles.message = '挂这个模板的用户是个穷光蛋,连30块都付不起。'
elseif conv >= 100 and conv < 500 then
styles.top = '#DBFFFD'
styles.bottom = '#427D9E'
elseif conv >= 500 and conv < 1000 then
styles.top = '#FFF1C5'
styles.bottom = '#E2B52B'
elseif conv >= 1000 and conv < 2000 then
styles.top = '#FFEAD2'
styles.bottom = '#E09443'
styles.bottomRight = 500
elseif conv >= 2000 and conv < 3000000 then
styles.top = '#FFE7E4'
styles.bottom = '#E54D4D'
styles.bottomRight = 1000
elseif conv >= 3000000 then
styles.top = '#FFD8D8'
styles.bottom = '#AB1A32'
styles.bottomRight = 2000
styles.message = '挂这个模板的用户因为太富,被怀疑是睿总在萌百开的账号。'
end
return styles
end
-- 辅助函数:格式化金瓜子
local function formatGoldenSeeds(goldenSeeds)
if goldenSeeds < 10000 then
return tostring(math.floor(goldenSeeds / 1000 * 10 + 0.5) / 10), '千'
elseif goldenSeeds < 100000000 then
return tostring(math.floor(goldenSeeds / 10000 * 10 + 0.5) / 10), '万'
else
return tostring(math.floor(goldenSeeds / 100000000 * 10 + 0.5) / 10), '亿'
end
end
-- 主函数
function p.main(frame)
local args = frame:getParent().args
-- 获取基本参数
local platform = lc(getArg(args, 1, 'youtube'))
local isUser = getArg(args, 'is-user', '') ~= ''
local money = tonumber(getArg(args, 'money', '30')) or 30
local negative = getArg(args, 'negative', '') ~= ''
-- 检查money参数是否有效
if not isInteger(money) then
return '<span class="error">错误:无法识别的money参数。</span>'
end
-- 确定正负号
local negativeSign = 1
if negative then
negativeSign = -1
elseif money <= 0 then
return '<span class="error">错误:无法识别的money参数。</span>'
end
if platform == 'youtube' or platform == 'yt' then
return p.renderYouTube(frame, args, money, negativeSign, isUser)
elseif platform == 'bilibili' or platform == 'bili' or platform == 'b' then
return p.renderBilibili(frame, args, money, negativeSign, isUser)
else
return '<span class="error">错误:无法识别的平台参数。</span>'
end
end
-- 渲染YouTube超级留言
function p.renderYouTube(frame, args, money, negativeSign, isUser)
local currency = uc(getArg(args, 'currency', 'USD'))
local username = getArg(args, 'username', 'FINAL')
local image = getImagePath(frame, args, username, isUser)
local width = getArg(args, 'width', '335px')
local message = getArg(args, 'message', '请输入发送内容!')
-- 获取汇率和符号
local er = getExchangeRate(frame, currency, 'USD')
local symbol = getCurrencySymbol(currency)
-- 计算转换后的金额
local conv = math.floor((money * negativeSign) * er + 0.5)
-- 获取颜色
local colors = getYouTubeColors(conv)
-- 允许自定义颜色覆盖
local colorTop = getArg(args, 'color-top', colors.top)
local colorBottom = getArg(args, 'color-bottom', colors.bottom)
local colorUsername = getArg(args, 'color-username', colors.username)
local colorMoney = getArg(args, 'color-money', colors.money)
local colorMessage = getArg(args, 'color-message', colors.message)
local imageUp = getArg(args, 'image-up', '0px')
local imageRight = getArg(args, 'image-right', '0px')
local float = getArg(args, 'float', 'none')
local css = getArg(args, 'css', '')
-- 生成HTML
local html = string.format([[
<div style="float:%s;font-size:12px;line-height:1.15;width:%s;min-width:227.5px;border-radius:4px;display:flex;flex-direction:column;box-shadow:0 2px 2px 0 rgba(0,0,0,0.14),0 1px 5px 0 rgba(0,0,0,0.12),0 3px 1px -2px rgba(0,0,0,0.2);%s">
<div style="position:relative;background-color:%s;color:rgb(0,0,0);font-weight:500;padding:8px 0px;min-height:20px;display:flex;flex-direction:row;align-items:center;border-top-left-radius:4px;border-top-right-radius:4px;">
<div style="display:block;padding-top: 3px;padding-left: 65px;position: relative;">
<div style="top: 0;left: 15px;width: 40px;height: 40px;display:block;position: absolute;">
<div style="width: 100%%;height: 100%%;margin-top: 0;margin-left: 0;border-radius: 50%%;background-size: cover;overflow:hidden;">%s</div>
</div>
<div style="color:%s;font-size:14px;font-weight:bold;width: 100px;white-space: nowrap;text-overflow: ellipsis;overflow: hidden;">%s</div>
<div style="font-size:14px;font-weight:bold;display:block;color:%s">%s %d</div>
</div>
</div>
<div style="width: 100%%;padding:8px 16px;box-sizing: border-box;font-size: 15px;overflow-y: hidden;position: relative;display: block;background-color: %s;border-bottom-left-radius:6px;border-bottom-right-radius:6px;">
<div style="overflow: hidden !important;overflow-anchor: none;touch-action: auto;position: relative;display: block;">
<div style="display: inline-block;vertical-align: middle;width: 99%%;">
<div style="padding-bottom: 5px;position: relative;display: block;">
<div style="top: 0;left: 0;height: 100%%;padding: 0;border: none;background: none;color: %s;resize: none;font-weight:500;">%s</div>
</div>
</div>
</div>
</div>
</div>]],
float, width, css,
colorTop,
frame:callParserFunction('#img',{image, style='bottom:'..imageUp..';left:'..imageRight..';', width='40px'}),
colorUsername, username,
colorMoney, symbol, math.abs(money),
colorBottom,
colorMessage, message
)
return html
end
-- 渲染Bilibili醒目留言
function p.renderBilibili(frame, args, money, negativeSign, isUser)
local currency = uc(getArg(args, 'currency', 'CNY'))
local rankInput = lc(getArg(args, 'rank', ''))
-- 转换舰长等级
local rank = nil
if rankInput == '舰长' or rankInput == 'captain' or rankInput == 'c' then
rank = '舰长'
elseif rankInput == '提督' or rankInput == 'admiral' or rankInput == 'a' then
rank = '新提督'
elseif rankInput == '总督' or rankInput == 'viceroy' or rankInput == 'v' then
rank = '总督'
end
local username = getArg(args, 'username', '阿卡林')
local image = getImagePath(frame, args, username, isUser)
local width = getArg(args, 'width', '269px')
local backgroundRight = getArg(args, 'background-right', '-38.016px')
local message = getArg(args, 'message', '输入留言内容传递自己的心意吧!')
local messageJa = getArg(args, 'message-ja', nil)
-- 获取汇率和符号
local er = getExchangeRate(frame, currency, 'CNY')
local symbol = getCurrencySymbol(currency)
-- 计算转换后的金额
local conv = math.floor((money * negativeSign) * er + 0.5)
-- 计算金瓜子
local goldenSeeds = conv * 1000
local batteries = conv * 10
-- 获取样式
local styles = getBilibiliStyles(conv)
-- 允许自定义颜色覆盖
local colorTop = getArg(args, 'color-top', styles.top)
local colorBottom = getArg(args, 'color-bottom', styles.bottom)
local colorMessage = getArg(args, 'color-message', nil)
-- 如果没有提供message,使用默认的message
if not args['message'] or args['message'] == '' then
-- 只有在既没有提供message也没有提供message-ja时,才设置默认的日文文本
if not args['message-ja'] or args['message-ja'] == '' then
message = styles.message
messageJa = 'メッセージを入力して、心を届けよう!'
end
end
-- 判断消息颜色
local messageSize = '12px'
if colorMessage == nil then
if message == '输入留言内容传递自己的心意吧!' then
colorMessage = 'rgba(255, 255, 255, 0.4)'
else
colorMessage = 'rgba(255, 255, 255, 1)'
end
end
-- 格式化金瓜子
local goldenSeedsFormatted, goldenSeedsUnit = formatGoldenSeeds(goldenSeeds)
local float = getArg(args, 'float', 'none')
local css = getArg(args, 'css', '')
-- 获取rank图标
local rankIcon = ''
if rank then
rankIcon = string.format('<div style="position:absolute;left: -2px;top:-2px;">%s</div>',
frame:callParserFunction('#img',{
frame:callParserFunction('filepath',{'File:BSC_' .. rank .. '.png'}),
width='34px', height='34px'
}))
end
-- 生成HTML
local html = string.format([[
<div style="position:relative;display:flex;float:%s;font-family: Arial,Microsoft YaHei,Microsoft Sans Serif,Microsoft SanSerf,\\5FAE\\8F6F\\96C5\\9ED1!important;font-size:12px;line-height:1.15;%s">
<div style="width:%s;min-width: 130px;border: 1px solid %s;border-radius:6px;display:flex;flex-direction:column;box-shadow:0 2px 2px 0 rgba(0,0,0,0.14),0 1px 5px 0 rgba(0,0,0,0.12),0 3px 1px -2px rgba(0,0,0,0.2);overflow:hidden;">
<div style="position:relative;background-color: %s;color:rgb(0,0,0);font-weight:500;min-height:48px;display:flex;flex-direction:row;">
<div style="display:flex;align-items:center;">
<div style="left: 8px;display:block;position: absolute;"><div style="position:relative;overflow:hidden;border-radius: 50%%;">%s</div>%s</div>
</div>
<div style="display:flex;align-items:center;">
<div style="display:block;margin-top: 2px;margin-left: 44px;color: #333;position: relative;">
<div style="color: #f9708e;font-size: 12px;opacity: .78;white-space: nowrap;width:100px;text-overflow: ellipsis;overflow: hidden;">%s</div>
<div style="font-size: 14px;display: block;line-height: 16px;margin-top: 2px;">%d电池</div>
</div>
<div style="right:%s;display:block;position: absolute;">
<div style="display:flex;position: relative;float:right;">%s</div>
</div>
</div>
</div>
<div style="width: 100%%;padding: 2px 9px;box-sizing: border-box;color: #fff;font-size: %s;overflow-y: hidden;position: relative;display: block;background-color: %s;">
<div style="padding-top:7px;overflow: hidden;position: relative;display: block;">
<div style="display: inline-block;vertical-align: middle;width: 99%%;">
<div style="padding-bottom: 5px;%sposition: relative;display: block;">
<div style="display:inline;top: 0;left: 0;height: 100%%;border: none;background: none;line-height: 20px;color: %s;resize: none;line-height: 20px;">%s</div>
</div>%s
</div>
</div>
%s
</div>
</div>
</div>]],
float, css,
width, colorBottom,
colorTop,
frame:callParserFunction('#img',{image, width='30px'}),
rankIcon,
username,
batteries,
backgroundRight,
frame:callParserFunction('#img',{
frame:callParserFunction('filepath',{'File:BSC_Background.png'}),
width='126.72px', height='48px'
}),
messageSize, colorBottom,
(messageJa and messageJa ~= '' and 'border-bottom: 1px solid hsla(0,0%%,96%%,.33);' or ''),
colorMessage, message,
(messageJa and messageJa ~= '' and string.format('<p><span style="display:inline;top: 0;left: 0;height: 100%%;border: none;background: none;line-height: 20px;color: %s;resize: none;line-height: 20px;">%s</span></p>', colorMessage, frame:expandTemplate{title = 'lj', args = {messageJa}}) or ''),
(styles.bottomRight and string.format('%s', frame:callParserFunction('#img',{
frame:callParserFunction('filepath',{'File:BSC ' .. styles.bottomRight .. ' Bottom-Right.png'}),
style='display:block;right:0px;bottom:0px;position:absolute;', width='15px', height='15px'
})) or '')
)
return html
end
return p