唱片资料 维基

See Also


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