モジュール:Tracklist

提供:MONACA Wiki
2024年4月19日 (金) 19: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, strings_arrange, brass_arrange, horn_arrange, orchestra_arrange, remix, singer, extra, 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, 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.extra = args.extra_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


--[[
列数計算
]]
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.strings_arrange then
        result = result .. '<th scope="col" style="width:' .. (args.strings_arrange_width or width.credits) .. ';">ストリングスアレンジ</th>'
        -- ストリングスアレンジセル関数再定義
        strings_arrange = function(x) return '<td>' .. (x.strings_arrange or '&nbsp;') .. '</td>' end
    end
	if credits.brass_arrange then
        -- ブラスアレンジ列追加
        result = result .. '<th scope="col" style="width:' .. (args.brass_arrange_width or width.credits) .. ';">ブラスアレンジ</th>'
        -- ブラスアレンジセル関数再定義
        brass_arrange = function(x) return '<td>' .. (x.brass_arrange or '&nbsp;') .. '</td>' end
    end
	if credits.horn_arrange then
        -- ホーンアレンジ列追加
        result = result .. '<th scope="col" style="width:' .. (args.horn_arrange_width or width.credits) .. ';">ホーンアレンジ</th>'
        -- ホーンアレンジセル関数再定義
        horn_arrange = function(x) return '<td>' .. (x.horn_arrange or '&nbsp;') .. '</td>' end
    end
	if credits.orchestra_arrange then
        -- オーケストラアレンジ列追加
        result = result .. '<th scope="col" style="width:' .. (args.orchestra_arrange_width or width.credits) .. ';">オーケストラアレンジ</th>'
        -- オーケストラアレンジセル関数再定義
        orchestra_arrange = function(x) return '<td>' .. (x.orchestra_arrange or '&nbsp;') .. '</td>' end
    end
	if credits.remix then
        -- リミックス列追加
        result = result .. '<th scope="col" style="width:' .. (args.remix_width or width.credits) .. ';">リミックス</th>'
        -- オーケストラアレンジセル関数再定義
        remix = function(x) return '<td>' .. (x.remix or '&nbsp;') .. '</td>' end
    end
	if credits.singer then
        -- 歌列追加
        result = result .. '<th scope="col" style="width:' .. (args.singer_width or width.credits) .. ';">歌</th>'
        -- オーケストラアレンジセル関数再定義
        singer = function(x) return '<td>' .. (x.singer or '&nbsp;') .. '</td>' end
    end
	if credits.extra then
		--extra列追加
		result = result .. '<th scope="col" style="width:' .. (args.extra_width or width.credits) .. ';">' .. credits.extra .. '</th>'
		--extraセル関数再定義
		extra = function(x) return '<td>' .. (x.extra or '&nbsp;') .. '</td>' 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
	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) ..  strings_arrange(v) .. brass_arrange(v) .. horn_arrange(v) .. orchestra_arrange(v) .. remix(v) .. singer(v) .. extra(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) ..  strings_arrange(v) .. brass_arrange(v) .. horn_arrange(v) .. orchestra_arrange(v) .. remix(v) .. singer(v) .. extra(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; vertical-align: middle; 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

-- calc_columns 関数に新しい変数に関する表示可否判定のロジックを追加
local function calc_columns()
    local col = 2 -- #, タイトル
    -- ...
    if credits.strings_arrange then col = col + 1 end
    if credits.brass_arrange then col = col + 1 end
    if credits.horn_arrange then col = col + 1 end
	if credits.orchestra_arrange then col = col + 1 end
    if credits.remix then col = col + 1 end
	if credits.singer then col = col + 1 end
    return col
end

-- ...

-- calc_width 関数に新しい変数に関する列幅の計算ロジックを追加
local function calc_width()
    local width = {}
    -- ...
    if not credits.strings_arrange then col = col + 1 end
    if not credits.brass_arrange then col = col + 1 end
    if not credits.horn_arrange then col = col + 1 end
    if not credits.orchestra_arrange then col = col + 1 end
	if not credits.singer then col = col + 1 end
    if not credits.remix then col = col + 1 end
    return width
end

return p