local yesno = require('Module:Yesno')
local checkType = require('libraryUtil').checkType
-- Trim function
function trim(s)
return (s:gsub("^%s*(.-)%s*$", "%1"))
end
--local patterns = {
-- "中国唱片/CCD-0001~1000",
-- "相信音乐/BD0001~BD0999",
-- "上华国际/WCD 20000~30000",
-- "Della/TCD-12304~TCD-99999"
--}
function extractCode(str)
-- Pattern to match uppercase letters followed by a dash or space and numbers
local pattern = "/([A-Z]+)[%- ]%d"
-- Find and capture the code
local code = string.match(str, pattern) or ''
return code
end
function zeroPad(number, format)
-- Determine the number of zeros in the format
local numZeros = #format
-- Format the number as a zero-padded string
local paddedString = string.format("%0" .. numZeros .. "d", number)
return paddedString
end
-- Test the function
--print(zeroPad(1, "0000")) -- Output: 0001
--print(zeroPad(37, "0000")) -- Output: 0037
--print(zeroPad(123, "0000")) -- Output: 0123
--print(zeroPad(12345, "0000"))-- Output: 12345 (if the number exceeds the format, it will not be truncated)
--------------------------------------------------------------------------------
-- Catalog class
--------------------------------------------------------------------------------
local Catalog = {}
Catalog.__index = Catalog
Catalog.fields = {
code = true, -- catalog number prefix
number = true,
t = true, -- album title
a = true, -- artist
f = true, -- format: CD, Tape, LP etc.
id = true, -- isrc etc.
extra = true,
n = true, -- longnote
}
Catalog.cellMethods = {
number = 'makeNumberCell',
t = 'makeTitleCell',
a = 'makeArtistCell',
id = 'makeIdCell',
f = 'makeFormatCell',
extra = 'makeExtraCell',
n = 'makeLongNoteCell',
}
function Catalog.new(data, code, numform)
local self = setmetatable({}, Catalog)
for field in pairs(Catalog.fields) do
self[field] = data[field]
end
self.number = assert(tonumber(self.number))
self.code = code
self.numform = numform or '0'
return self
end
function Catalog:getFormatCredit()
return self.f
end
function Catalog:getIdCredit()
return self.id
end
function Catalog:getExtraField()
return self.extra
end
function Catalog:getLongNoteField()
return self.n
end
-- Note: called with single dot syntax
function Catalog.makeSimpleCell(wikitext)
wikitext = wikitext or ' '
return '| style="text-align:center" | ' .. wikitext .. '\n'
end
function Catalog:makeNumberCell()
local ret = ''
local form = self.numform or '0'
ret = self.code .. zeroPad(self.number, form)
return Catalog.makeSimpleCell(ret)
end
function Catalog:makeTitleCell()
self.t = self.t or ' '
local title = '| style="padding-left:10px;" | ' .. self.t .. '\n'
return title
end
function Catalog:makeArtistCell()
local ret = ''
if self.a then
ret = '[[' .. self.a .. ']]'
end
return Catalog.makeSimpleCell(ret)
end
function Catalog:makeIdCell()
return Catalog.makeSimpleCell(self.id)
end
function Catalog:makeFormatCell()
return Catalog.makeSimpleCell(self.f)
end
function Catalog:makeExtraCell()
return Catalog.makeSimpleCell(self.extra)
end
function Catalog:makeLongNoteCell()
self.n = self.n or ' '
local longnoteCell = '| style="padding-left:10px;vertical-align:center" | '
if (string.match(self.n, '%*') ) then
else
self.n = trim(self.n)
end
longnoteCell = longnoteCell .. self.n
return trim(longnoteCell)
end
function Catalog:exportRow(options)
options = options or {}
local columns = options.columns or {}
local row = '\n|-'
options.color = options.color or 'var(--theme-page-background-color)'
row = row .. ' style="background-color:' .. options.color ..';"\n'
for i, column in ipairs(columns) do
local method = Catalog.cellMethods[column]
if method then
--row = row .. method
row = row .. tostring(self[method](self)) --row:node(self[method](self))
else
row = row .. 'invalidxxxxx'
end
end
return row
end
function Catalog.setRow(data)
local self = setmetatable({}, Catalog)
for field in pairs(Catalog.fields) do
self[field] = data[field]
end
--self.number = assert(tonumber(self.number))
-- Songtitle
local pname = tostring(mw.title.getCurrentTitle())
if (string.match(pname, '%(')) then
local pattern = "^(.-)%s*%b()"
self.s = string.match(pname, pattern)
else
self.s = pname
end
self.a = self.a or 'Various'
-- Find columns to output
local columns = {'number', 'y', 'v', 'a', 't', 'n'}
local vrow = ''
vrow = self:exportRow({
columns = columns
})
return vrow
end
--------------------------------------------------------------------------------
-- CatalogListing class
--------------------------------------------------------------------------------
local CatalogListing = {}
CatalogListing.__index = CatalogListing
CatalogListing.fields = {
code = true,
dash = true,
format = true,
collapsed = true,
headline = true,
font_size = true,
extra_column = true,
num_width = true,
title_width = true,
artist_width = true,
id_width = true,
id_header = true,
format_width = true,
extra_width = true,
longnote_width = true,
category = true,
}
function CatalogListing.new(data)
local self = setmetatable({}, CatalogListing)
-- Add properties
for field in pairs(CatalogListing.fields) do
self[field] = data[field]
end
-- Evaluate boolean properties
self.collapsed = yesno(self.collapsed, false)
self.showCategories = yesno(self.category) ~= false
--self.category = nil
-- Catalog Code
self.format = self.format or '0' -- e.g. 0000, default = 0
self.dash = self.dash or ''
local pname = tostring(mw.title.getCurrentTitle())
if (self.code) then
self.code = self.code .. self.dash
elseif (string.match(pname, '%/')) then
self.code = extractCode(pname) or ''
self.code = self.code .. self.dash
else
self.code = ''
end
-- Make Catalog objects
self.catalogs = {}
for i, catalogData in ipairs(data.catalogs or {}) do
table.insert(self.catalogs, Catalog.new(catalogData, self.code, self.format))
end
-- Find which of the optional columns we have.
-- We could just check every column for every track object, but that would
-- be no fun^H^H^H^H^H^H inefficient, so we use four different strategies
-- to try and check only as many columns and track objects as necessary.
do
local optionalColumns = {}
local columnMethods = {
f = 'getFormatCredit',
id = 'getIdCredit',
--writer = 'getWriterCredit',
--arranger = 'getArrangerCredit',
--producer = 'getProducerCredit',
--ep = 'getEpCredit',
extra = 'getExtraField',
n = 'getLongNoteField',
--length = 'getLengthField',
}
for i, trackObj in ipairs(self.catalogs) do
for column, method in pairs(columnMethods) do
if trackObj[method](trackObj) then
optionalColumns[column] = true
columnMethods[column] = nil
end
end
if not next(columnMethods) then
break
end
end
self.optionalColumns = optionalColumns
end
return self
end
function CatalogListing:__tostring()
-- Find columns to output
local columns = {'number', 't', 'a'}
if self.optionalColumns.f then
columns[#columns + 1] = 'f' -- format
end
if self.optionalColumns.id then
columns[#columns + 1] = 'id' -- id isrc/isbn etc.
end
if self.optionalColumns.extra then
columns[#columns + 1] = 'extra'
end
if self.optionalColumns.n then
columns[#columns + 1] = 'n' -- longnote
end
self.num_width = self.num_width or '100'
self.artist_width = self.artist_width or '80'
self.title_width = self.title_width or '100'
self.id_width = self.id_width or '300'
self.longnote_width = self.longnote_width or '300'
self.format_width = self.format_width or '50'
self.extra_width = self.extra_width or '100'
-- Find intros
--local vheader = '厂牌目录名称'
self.id_header = self.id_header or 'ISRC/ISBN/EAN/UPC'
-- Root of the output
local root = '{|' -- ''
root = root .. 'class="wikitable" style="font-size:9pt"\n'
if (self.headline) then
root = root .. '|+ '.. self.headline .. '\n'
--vheader = '对应厂牌目录'
end
root = root .. '|-\n'
root = root .. '! scope="col" width="' .. self.num_width .. '" | 唱片编号 ' -- num
root = root .. '!!scope="col" width="' .. self.title_width .. '" | 专辑名称 ' -- t
root = root .. '!!scope="col" width="' .. self.artist_width .. '" | 主艺人 ' -- a
--if(self.format) then end
if self.optionalColumns['f'] then
root = root .. '!!scope="col" width="' .. self.format_width .. '" | 介质格式 ' -- f
end
if self.optionalColumns['id'] then
root = root .. '!!scope="col" width="' .. self.id_width .. '" | ' .. self.id_header -- id ISRC/ISBN etc.
end
if self.optionalColumns['extra'] then
root = root .. '!!scope="col" width="' .. self.extra_width .. '" | ' .. self.extra_column -- extra
end
if self.optionalColumns['n'] then
root = root .. '!!scope="col" width="' .. self.longnote_width .. '" | 备注 ' -- n
end
root = root .. '\n'
-- catalogs
local vrow = ''
for i, Catalog in ipairs(self.catalogs) do
vrow = Catalog:exportRow({
columns = columns,
color = i % 2 == 0 and 'var(--theme-page-background-color--secondary)' or 'var(--theme-page-background-color)'
})
root = root .. vrow
end
-- Warnings and Cataloging categories
--root:wikitext(self:renderWarnings())
--root:wikitext(self:renderCatalogingCategories())
root = root .. '\n|}'
if (self.showCategories) then
local code = self.code or '0'
root = root .. '[[Category:厂牌目录|' .. code .. ']]'
end
return root
end
function CatalogListing.setHeader(data)
local self = setmetatable({}, CatalogListing)
-- Add properties
for field in pairs(CatalogListing.fields) do
self[field] = data[field]
end
-- Evaluate boolean properties
self.collapsed = yesno(self.collapsed, false)
self.showCategories = yesno(self.category) ~= false
self.category = nil
-- CatalogNumPrefix
local pref = tostring(mw.title.getCurrentTitle())
if (self.song) then
elseif (string.match(pname, '%(')) then
local pattern = "^(.-)%s*%b()"
self.song = string.match(pname, pattern)
else
self.song = pname
end
self.verid_width = self.verid_width or '100'
self.longnote_width = self.longnote_width or '300'
self.title_width = self.title_width or '500'
self.artist_width = self.artist_width or '80'
-- Find intros
local vheader = '厂牌目录名称'
-- Root of the output
local header = '{|' -- ''
header = header .. 'class="wikitable" style="font-size:9pt"\n'
if (self.remastered) then
header = header .. '|+ Remastered Catalog\n'
vheader = '对应厂牌目录'
end
header = header .. '|-\n'
header = header .. '! 序号 !! scope="col" width="100" | 年份 !! ' -- n y
header = header .. 'scope="col" width="' .. self.verid_width .. '" | ' .. vheader .. ' !! ' -- v
header = header .. 'scope="col" width="' .. self.artist_width .. '" | 演唱者 !! ' -- a
header = header .. 'scope="col" width="' .. self.title_width .. '" | 收录专辑 !! ' -- t
header = header .. 'scope="col" width="' .. self.longnote_width .. '" | 备注 \n' -- n
return header
end
--------------------------------------------------------------------------------
-- Exports for Template Main Table
--------------------------------------------------------------------------------
local p = {};
function p._main(args)
-- Process numerical args so that we can iterate through them.
local data, catalogs = {}, {}
for k, v in pairs(args) do
if type(k) == 'string' then
local prefix, num = k:match('^(%D.-)(%d+)$')
if prefix and Catalog.fields[prefix] and (num == '0' or num:sub(1, 1) ~= '0') then
-- Allow numbers like 0, 1, 2 ..., but not 00, 01, 02...,
-- 000, 001, 002... etc.
num = tonumber(num)
catalogs[num] = catalogs[num] or {}
catalogs[num][prefix] = v
else
data[k] = v
end
end
end
data.catalogs = (function (t)
-- Compress sparse array
local ret = {}
for num, catalogData in pairs(t) do
catalogData.number = num
table.insert(ret, catalogData)
end
table.sort(ret, function (t1, t2)
return t1.number < t2.number
end)
return ret
end)(catalogs)
return tostring(CatalogListing.new(data))
end
function p.main(frame)
local args = require('Module:Arguments').getArgs(frame, {
wrappers = 'Template:厂牌目录'
})
return p._main(args)
end
--------------------------------------------------------------------------------
-- Exports for Template /Header
--------------------------------------------------------------------------------
function p._header(args)
-- Process numerical args so that we can iterate through them.
local data = {}
for k, v in pairs(args) do
if type(k) == 'string' then
data[k] = v
end
end
return tostring(CatalogListing.setHeader(data))
end
function p.header(frame)
local args = require('Module:Arguments').getArgs(frame, {
wrappers = 'Template:厂牌目录/Header'
})
return p._header(args)
end
--------------------------------------------------------------------------------
-- Exports for Template /data
--------------------------------------------------------------------------------
function p.vdata(frame)
local data = {}
data['number'] = trim(frame.args[1]) -- 序号
data['y'] = trim(frame.args[2]) -- 年份
data['v'] = trim(frame.args[3]) -- 厂牌目录名称
data['a'] = trim(frame.args[4]) -- 演唱者
data['t'] = frame.args[5] -- 收录专辑
data['n'] = frame.args[6] -- 备注
--local args = require('Module:Arguments').getArgs(frame, {
-- wrappers = 'Template:厂牌目录/Data'
--})
return trim(tostring(Catalog.setRow(data)))
end
return p