メニューを切り替える
個人設定を切り替える
ログインしていません
編集を行うと、IPアドレスが公開されます。
2024年1月26日 (金) 18:16時点における今川 凌 (MONACA) (トーク | 投稿記録)による版

このモジュールについての説明文ページを モジュール:Tracklist/doc に作成できます

local p = {}

--共通変数
local track = {}	--トラックテーブル格納用テーブル
local all = {}	--全○○格納用テーブル
local desc = {nil, nil}	--コメント格納用テーブル
local credits = {}	--クレジット表示可否格納用テーブル
local args = {}	--その他引数格納用テーブル
local col = 0	--列数
local width = {}	--列幅格納用テーブル
local collapsed = false	--折りたたみ可否
local writer, lyrics, music, arranger, extra1, extra2, extra3, extra4, length = function() return '' end, function() return '' end, function() return '' end,function() return '' end, function() return '' end, function() return '' end, function() return '' end, function() return '' end, function() return '' end	--基本セル関数
local md = true	--microdata on/off


--[[
引数取得
]]
local function getArgs(frame)
	local t_info, t_num = '', 0
	local func_credits = function(v)
		if v == 'yes' then return true end
		local alias = {'+arrangements', '+a', '+編曲', '・編曲'}
		for _k, _v in ipairs(alias) do
			if v == _v then return _v end
		end
		return false
	end
	
	for k, v in pairs(require('Module:Arguments').getArgs(frame, {parentOnly = true})) do
		if string.match(k, '^%D+%d+$') then
			--各トラック格納
			t_info, t_num = string.match(k, '(%D+)(%d+)')
			if not track[t_num] then track[t_num] = {} end
			track[t_num][1] = tonumber(t_num)		-- トラック番号はkey=1で記録
			track[t_num][t_info] = v	-- トラック情報はkey=引数で記録
		elseif string.match(k, 'all_') then
			--全○○格納
			local pattern = string.gsub(k, 'all_', '')
			if not all[pattern] then all[pattern] = {nil, v} end
		elseif string.match(k, '^%d$') then
			--コメント格納
			desc[k] = string.gsub(v, '^([*#;:])', '\n%1')
		elseif string.match(k, '_credits') then
			--クレジット表示可否格納
			credits[string.gsub(k, '_credits', '')] = func_credits(v)
		else
			-- その他格納
			args[k] = v
		end
	end
	
	--allの整理
	if all then
		local function isSame(a, b)	--リンクを考慮して文字列を比較する
			if a and b then
				return (string.match(a[2], '%[%[.-%|(.-)]]') or string.match(a[2], '%[%[(.-)]]') or a[2]) == (string.match(b[2], '%[%[.-%|(.-)]]') or string.match(b[2], '%[%[(.-)]]') or b[2])
			else
				return false
			end
		end
		
		if not all.writing and isSame(all.lyrics, all.music) then
			all.writing = {nil, all.lyrics[2]}
		end
		if all.writing then
			all.lyrics, all.music = nil, nil
			all.writing[1] = '全作詞・作曲: '
		else
			if all.lyrics then all.lyrics[1] = '全作詞: ' end
			if all.music then all.music[1] = '全作曲: ' end
		end
		if isSame(all.writing, all.arrangements) then
			all.all = {'全作詞・作曲・編曲: ', all.writing[2]}
			all.writing, all.arrangements = nil, nil
		else
			if all.arrangements then all.arrangements[1] = '全編曲: ' end
		end
		if isSame(all.music, all.arrangements) then
			all.producing = {'全作曲・編曲: ', all.music[2]}
			all.music, all.arrangements = nil, nil
		end
	end
	
	credits.extra1 = args.extra1_column
	if credits.writing then
		credits.lyrics, credits.music = false, false
		if credits.writing ~= true then credits.arrangements = false end
	end
	if credits.music and credits.music ~= true then credits.arrangements = false end
	collapsed = (args.collapsed == 'yes')
	md = (args.microdata == 'no') and false or args.id
end

	credits.extra2 = args.extra2_column
	if credits.writing then
		credits.lyrics, credits.music = false, false
		if credits.writing ~= true then credits.arrangements = false end
	end
	if credits.music and credits.music ~= true then credits.arrangements = false end
	collapsed = (args.collapsed == 'yes')
	md = (args.microdata == 'no') and false or args.id

	credits.extra3 = args.extra3_column
	if credits.writing then
		credits.lyrics, credits.music = false, false
		if credits.writing ~= true then credits.arrangements = false end
	end
	if credits.music and credits.music ~= true then credits.arrangements = false end
	collapsed = (args.collapsed == 'yes')
	md = (args.microdata == 'no') and false or args.id

	credits.extra4 = args.extra4_column
	if credits.writing then
		credits.lyrics, credits.music = false, false
		if credits.writing ~= true then credits.arrangements = false end
	end
	if credits.music and credits.music ~= true then credits.arrangements = false end
	collapsed = (args.collapsed == 'yes')
	md = (args.microdata == 'no') and false or args.id

--[[
列数計算
]]
local function calc_columns()
	local col = 2	--#,タイトル
	for k, v in pairs(track) do
		if not v.length then
			credits.length = false
		else
			credits.length = true
			break
		end
	end
	for k, v in pairs(credits) do
		if v then col = col + 1 end
	end
	return col
end


--[[
幅計算
]]
local function calc_width()
	local width = {}
	if not credits.length then col = col + 1 end
	if col < 4 then
		width.title, width.credits = '100%', 'auto'
	elseif col < 5 then
		width.title, width.credits = '60%', '40%'
	elseif col < 6 then
		width.title, width.credits = '40%', '30%'
	elseif col < 7 then
		width.title, width.credits = '40%', '20%'
	else
		width.title, width.credits = '40%', '15%'
	end
	return width
end


--[[
ヘッダ部
]]
local function header()
	--キャプション定義
	local result = (args.headline or collapsed) and '<caption style="text-align:left; padding:0.25em 0.9em; font-weight:bold; line-height:1.4em; white-space:nowrap;">' .. (args.headline or 'トラックリスト') .. '</caption>' or ''
	
	if collapsed then
		--折りたたみ表示において[表示]ボタン行追加
		result = result .. '<tr style="position:absolute; top:0.25em; right:0.9em; speak:none;"><th colspan="' .. col .. '"></th></tr>'
	end
	
	local newall = {}	--全○○表示用テーブル
	if all then	--全○○/コメント表示のとき
		if all.lyrics and not credits.lyrics then newall[1] = all.lyrics[1] .. all.lyrics[2] end
		if all.music and not credits.music then newall[#newall + 1] = all.music[1] .. all.music[2] end
		if all.all and not credits.writing and not credits.lyrics and not credits.music and not credits.arrangements then
			newall[1] = all.all[1] .. all.all[2]
		elseif all.writing and not credits.writing and not credits.lyrics and not credits.music then
			newall[1] = all.writing[1] .. all.writing[2]
		elseif all.producing and not credits.music and not credits.arrangements then
			newall[#newall + 1] = all.producing[1] .. all.producing[2]
		end
		if all.arrangements and not credits.arrangements then newall[#newall + 1] = all.arrangements[1] .. all.arrangements[2] end
	end
	
	if newall[1] or #desc > 0 then
		--全○○/コメント行追加
		result = result .. '<tr><td colspan="' .. col .. '" style="padding-left:0.5em;"><small style="font-size:100%;">' .. (desc[1] or '') .. (newall[1] and (table.concat(newall, '、') .. '。') or '') .. (desc[2] or '') .. '</small></td></tr>'
	end
	
	--見出し行追加(#列・タイトル列追加)
	result = result .. '<tr style="text-align:left; font-size:111%;"><th scope="col" style="width:2em; padding-right:0.3em; text-align:right; white-space:nowrap;">#</th><th scope="col" style="width:' .. width.title .. '; padding-left:0.9em; white-space:nowrap;">タイトル</th>'
	
	if credits.writing then
		--作詞・作曲列追加
		result = result .. '<th scope="col" style="width:' .. (args.writing_width or (credits.extra and '30%' or '40%')) .. ';">作詞・作曲' .. (credits.writing == true and '' or '・編曲') .. '</th>'
		--作詞・作曲セル関数再定義
		if md then
			writer = function(x) return '<td itemprop="recordingOf" itemscope itemtype="http://schema.org/MusicComposition"><span itemprop="lyricist composer" itemscope itemtype="http://schema.org/Person"><span itemprop="name">' .. (x.writer or all.writer and all.writer[2] or all.all and all.all[2] or '&nbsp;') .. '</span></span></td>' end
		else
			writer = function(x) return '<td>' .. (x.writer or all.writer and all.writer[2] or all.all and all.all[2] or '&nbsp;') .. '</td>' end
		end
	else
		local disp = function(y) if y then return '' else return 'display:none;' end end
		--作詞列追加
		result = result .. '<th scope="col" style="width:' .. (args.lyrics_width or width.credits) .. ';' .. disp(credits.lyrics) .. '">作詞</th>'
		--作詞セル関数再定義
		if md then
			lyrics = function(x) return '<td itemprop="recordingOf" itemscope itemtype="http://schema.org/MusicComposition" style="' .. disp(credits.lyrics) .. '"><span itemprop="lyricist" itemscope itemtype="http://schema.org/Person"><span itemprop="name">' .. (x.lyrics or all.lyrics and all.lyrics[2] or x.writer or all.writing and all.writing[2] or all.all and all.all[2] or '&nbsp;') .. '</span></span></td>' end
		else
			lyrics = function(x) return '<td style="' .. disp(credits.lyrics) .. '">' .. (x.lyrics or all.lyrics and all.lyrics[2] or x.writer or all.writing and all.writing[2] or all.all and all.all[2]  or '&nbsp;') .. '</td>' end
		end
		--作曲列追加
		result = result .. '<th scope="col" style="width:' .. (args.music_width or width.credits) .. ';' .. disp(credits.music) .. '">作曲' .. (credits.music == true and '' or '・編曲') .. '</th>'
		--作曲セル関数再定義
		if md then
			music = function(x) return '<td itemprop="recordingOf" itemscope itemtype="http://schema.org/MusicComposition" style="' .. disp(credits.music) .. '"><span itemprop="composer" itemscope itemtype="http://schema.org/Person"><span itemprop="name">' .. (x.music or all.music and all.music[2] or x.writer or all.writing and all.writing[2] or all.producing and all.producing[2]  or all.all and all.all[2] or '&nbsp;') .. '</span></span></td>' end
		else
			music = function(x) return '<td style="' .. disp(credits.music) .. '">' .. (x.music or all.music and all.music[2] or x.writer or all.writing and all.writing[2] or all.producing and all.producing[2]  or all.all and all.all[2] or '&nbsp;') .. '</td>' end
		end
	end
	if credits.arrangements then
		--編曲列追加
		result = result .. '<th scope="col" style="width:' .. (args.arrangements_width or width.credits) .. ';">編曲</th>'
		--編曲セル関数再定義
		arranger = function(x) return '<td>' .. (x.arranger or all.arrangements and all.arrangements[2] or all.producing and all.producing[2]  or all.all and all.all[2] or '&nbsp;') .. '</td>' end
	end
	if credits.extra1 then
		--extra1列追加
		result = result .. '<th scope="col" style="width:' .. (args.extra1_width or width.credits) .. ';">' .. credits.extra1 .. '</th>'
		--extra1セル関数再定義
		extra1 = function(x) return '<td>' .. (x.extra1 or '&nbsp;') .. '</td>' end
	end
	if credits.extra2 then
		--extra2列追加
		result = result .. '<th scope="col" style="width:' .. (args.extra2_width or width.credits) .. ';">' .. credits.extra2 .. '</th>'
		--extra2セル関数再定義
		extra2 = function(x) return '<td>' .. (x.extra2 or '&nbsp;') .. '</td>' end
	end
	if credits.extra3 then
		--extra3列追加
		result = result .. '<th scope="col" style="width:' .. (args.extra3_width or width.credits) .. ';">' .. credits.extra3 .. '</th>'
		--extra3セル関数再定義
		extra3 = function(x) return '<td>' .. (x.extra3 or '&nbsp;') .. '</td>' end
	end
	if credits.extra4 then
		--extra4列追加
		result = result .. '<th scope="col" style="width:' .. (args.extra4_width or width.credits) .. ';">' .. credits.extra4 .. '</th>'
		--extra4セル関数再定義
		extra4 = function(x) return '<td>' .. (x.extra4 or '&nbsp;') .. '</td>' end
	end
end
	if credits.length then
		--時間列追加
		result = result .. '<th scope="col" style="width:4em; padding-right:0.5em; text-align:right; white-space:nowrap;">時間</th>'
		--時間セル再定義
		if md then
			length = function(x) return '<td style="padding-right:0.5em; text-align:right; white-space:nowrap;">' .. (x.length and ('<time itemprop="duration" datetime="'.. string.gsub(x.length, '^(%d+):(%d+)$', 'PT%1M%2S') ..'">' .. x.length .. '</time>') or '&nbsp;') .. '</td>' end
		else
			length = function(x) return '<td style="padding-right:0.5em; text-align:right; white-space:nowrap;">' .. (x.length and ('<time datetime="'.. string.gsub(x.length, '^(%d+):(%d+)$', 'PT%1M%2S') ..'">' .. x.length .. '</time>') or '&nbsp;') .. '</td>' end
		end
	
	result = result .. '</tr>'
	
	return result
end


--[[
本体部
]]
local function body()
	local result = ''
	local trackA = {}	--ソート用テーブル
	for k, v in pairs(track) do
		trackA[#trackA + 1] = v
	end
	table.sort(trackA,
		function (a, b) return a[1] < b[1] end
	)
	if md then
		for k, v in ipairs(trackA) do
			local color = (v[1] % 2 == 0) and '' or ''	--偶数/奇数で別色指定
			result = result .. '<tr itemprop="track" itemscope itemtype="http://schema.org/MusicRecording" style="background-color:' .. color .. '; vertical-align:top;"><td style="padding-left:0.5em; text-align:right;"><span itemprop="position">' .. (v['#'] or v[1]) .. '</span>.</td><td>' .. (v.title and ('<span itemprop="name">' .. v.title .. '</span>') or 'タイトルなし') .. (v.note and ('<small>(' .. v.note .. ')</small>') or '') .. '</td>' .. writer(v) .. lyrics(v) .. music(v) .. arranger(v) ..  extra1(v) .. extra2(v) .. extra3(v) .. extra4(v) .. length(v) .. '</tr>'
		end
	else
		for k, v in ipairs(trackA) do
			local color = (v[1] % 2 == 0) and '' or ''
			result = result .. '<tr style="background-color:' .. color .. '; vertical-align:top;"><td style="padding-left:0.5em; text-align:right;">' .. (v['#'] or v[1]) .. '.</td><td>' .. (v.title and ('' .. v.title .. '') or 'タイトルなし') .. (v.note and ('<small>(' .. v.note .. ')</small>') or '') .. '</td>' .. writer(v) .. lyrics(v) .. music(v) .. arranger(v) ..  extra1(v) .. extra2(v) .. extra3(v) .. extra4(v) .. length(v) .. '</tr>'
		end
	end
	return result
end


--[[
フッタ部(合計時間)
]]
local function footer()
	local total = args.total_length
	local hour, min, sec = 0, 0, 0
	if total == 'auto' then
		--合計時間計算
		for k, v in pairs(track) do
			if not v.length then v.length = '0:00' end
			local _min, _sec = string.match(v.length, '(%d+):(%d+)')
			min, sec = min + _min, sec + _sec
		end
		while sec > 59 do
			min = min + 1
			sec = sec - 60
		end
		if sec < 10 then sec = '0' .. sec end
		total = min .. ':' .. sec
	end
	if total and total == string.match(total, '%d*:%d*') then
		--<time>タグ
		hour, min, sec = string.match(total, '(%d-):?(%d+):(%d+)')
		hour = (hour ~= '') and tonumber(hour) or 0
		min = hour * 60 + tonumber(min)
		total = '<time datetime="PT' .. min .. 'M' .. sec .. 'S">'.. min .. ':' .. sec .. '</time>'
		--合計時間行追加
		return '<tr style="text-align:right; font-size:111%;"><th colspan="' .. (col - 1) .. '"><div style="width:7.5em; text-align:left; margin:0 0 0 auto; padding-left:0.5em; white-space:nowrap; font-weight:bold;">合計時間:</div></th><td style="padding-right:0.5em;">'.. total .. '</td></tr>'
	else
		return ''
	end
end


function p.main(frame)
	getArgs(frame)
	col = calc_columns()	--number
	width = calc_width()	--table
	
	--tableタグで囲んで出力
	local table = mw.html.create('table')
	table
		:wikitext(header() .. body() .. footer())	--tableタグ内
		:attr({class = 'tracklist', id = args.id or ''})
		:cssText('display:block; max-width:100%; width:auto; border-spacing:0px; border-collapse:collapse; padding:0.2em; font-size:90%; text-align:left;')
	if collapsed then
		--折りたたみ表示追加指定
		table
			:addClass('mw-collapsible mw-collapsed')
			:cssText('position:relative; overflow:hidden; outline:1px solid #aaa;')
	end
	if md then
		table:attr({itemtype = 'http://schema.org/MusicAlbum'})
	end
	return tostring(table)
end

return p