לדלג לתוכן

יחידה:תבנית מידע/מוזיקה

מתוך חב"דפדיה, אנציקלופדיה חב"דית חופשית

ניתן ליצור תיעוד על היחידה הזאת בדף יחידה:תבנית מידע/מוזיקה/תיעוד

-- New Functions for Tempalte:סינגל and Template:אלבום
-- * Automatic מאת per qid
-- * Automatic אלבום per qid (only for Template:סינגל)
-- * Automatic categories per qid, יצא לאור or הוקלט or תאריך כתיבה with Module:תאריך (for the earliest Year possible)
local dataTemplateModule = require('Module:תבנית מידע')
local Infobox = dataTemplateModule.Infobox
local PropertyLink = require('Module:PropertyLink')
local MusicalStyling = require('Module:עיצוב יצירות מוזיקליות')
local WikidataCrossValidation = require('Module:WikidataCrossValidation')

local function getPencilLink(entityId, prop)
	if not entityId then return '' end
	return string.format(' [[File:Blue pencil RTL.svg|15px|link=https://www.wikidata.org/wiki/%s?uselang=he#%s|עריכת הנתון בוויקינתונים]]', entityId, prop)
end

function fillWikidataParam(templateArgs, paramName, property, infoObj, opts)
	local usingWikidata = false
	
	if infoObj.args.entityId == nil then
		local matching = WikidataCrossValidation.crossValidate(templateArgs[paramName], property, infoObj.args.entityId )
		if matching then
			table.insert(infoObj.wikidataCats, WikidataCrossValidation.maintainceCategory(matching, property))
		end
		return false -- no wikidata entity
	end
	
	if templateArgs[paramName] == nil or templateArgs[paramName] == '' then
		opts = opts or {}
		templateArgs[paramName] = PropertyLink.getPropertyByOptions(property, infoObj.args.entityId, {
	        allowMulti = opts.multi or false,
	        seperator = opts.sep or ', ',
	        ['entity-gender-aware'] = opts.genderAware or false,
	        qualifiers = opts.qualifiers,
	        ['qualifiers-sep'] = opts.qualSep,
	        ['default-value'] = opts.qualDefault,
	        ['sort-order'] = opts.sortOrder,
	        ['img-width'] = '180px',
	        ['filter'] = opts.filter
	    })
	    
		if templateArgs[paramName] and #templateArgs[paramName] > 0 then
			usingWikidata = true
		end
	else
		local pageNs = mw.title.getCurrentTitle().namespace
		if pageNs==0 and not infoObj.isNonPerson then
			local matching = WikidataCrossValidation.crossValidate(templateArgs[paramName], property, infoObj.args.entityId )
			if matching then
				table.insert(infoObj.wikidataCats, WikidataCrossValidation.maintainceCategory(matching, property))
			end
		end
	end
	return usingWikidata
end

local function insertInOrder(templateStructure, row)
	local inserted = false
	for index, existingRow in ipairs(templateStructure) do
		if existingRow.indic and existingRow.indic > row.indic then
			table.insert(templateStructure, index, row)
			inserted = true
			break
		end
	end

	if not inserted then
		table.insert(templateStructure, row)
	end
end

local function useArgsOrWikidata(templateArgs, infoObj, disableWikidataFetch, label, propertyIds, paramName, opts)
	    opts = opts or {}
	    local content = templateArgs[paramName]

		if content == '-' then return end -- explicitly suppressed
	    if not disableWikidataFetch and (#propertyIds > 0) then
			if #propertyIds ==1 then
				local usingWikidata = fillWikidataParam(templateArgs, paramName, propertyIds[1], infoObj, opts)
				content = templateArgs[paramName]
				if usingWikidata then
					content = content .. (opts.pencil ~= false and getPencilLink(entityId, propertyIds[1]) or '')
				end
			else
				local values = {}
				for _, prop in ipairs(propertyIds) do
				    local result = PropertyLink.getPropertyByOptions(prop, entityId, {
				        allowMulti = opts.multi or false,
				        seperator = opts.sep or ', ',
				        ['entity-gender-aware'] = opts.genderAware or false,
				        qualifiers = opts.qualifiers,
				        ['qualifiers-sep'] = opts.qualSep,
				        ['default-value'] = opts.qualDefault,
				        ['sort-order'] = opts.sortOrder,
				        ['img-width'] = '180px',
				        ['filter'] = opts.filter
				    })
				    if result and result ~= '' then
						local cleaned_result = mw.ustring.gsub(result, '%[%[%s*[Cc]ategory:[^%[%]]-%]%]', '')
						cleaned_result = mw.ustring.gsub(cleaned_result, '%[%[%s*קטגוריה:[^%[%]]-%]%]', '')
				        if cleaned_result and cleaned_result ~= '' then
				            local valueWithPencil = result .. (opts.pencil ~= false and getPencilLink(entityId, prop) or '')
				            table.insert(values, valueWithPencil)
				        end
				    end
				end
				if #values == 0 then return end
				content = table.concat(values, opts.join or '<br/>')
	        end
	    end
		
	    if content == nil or content == '' then return end -- No local content, no display
	    local row = { label = label }
	    
        row.data = content
        
    	local MusicalStyling_frame = {
			getParent = function()
				return {
					args = {
						['שם'] = row.data,
						['סינגל'] = 'לא',
						['אלבום'] = opts.album,
						['הדגשה'] = 'לא'
					}
				}
			end
		}
		row.data = MusicalStyling.main(MusicalStyling_frame)
		
        if opts.data_starts_with and opts.data_starts_with ~= '' then
        	row.data = opts.data_starts_with .. row.data
        end
        
        if opts.image == true then
        	row.data = dataTemplateModule.getValueOrWikidataImage({
				valueArg=content,
				width='180px'
			})
        end
		
		row.datastyle = opts.datastyle or ''	
	    row.indic = opts.indic or 700
	    insertInOrder(infoObj.templateStructure, row)
end

local function getAlbumCategoryName(albumType, year)
	local map = {
		['EP'] = 'מיני-אלבומים מ-',
		['מיני-אלבום'] = 'מיני-אלבומים מ-',
		['אלבום הופעה'] = 'אלבומי הופעה מ-',
		['הופעה'] = 'אלבומי הופעה מ-',
		['פסקול'] = 'פסקולים מ-',
		['אלבום אוסף'] = 'אלבומי אוסף מ-',
		['אוסף'] = 'אלבומי אוסף מ-',
		['מארז תקליטורים'] = 'אלבומי אוסף מ-',
		['אלבום להיטים'] = 'אלבומי אוסף מ-',
		['להיטים'] = 'אלבומי אוסף מ-',
		['מיקסטייפ'] = 'מיקסטייפים מ-',
		['רמיקס'] = 'אלבומי רמיקס מ-',
		['וידאו'] = 'אלבומי וידאו מ-',
	}
	return (map[albumType] or 'אלבומי ' .. year)
end

local function trySingleCategory(infoObj, catBase, fullYear)
	if not fullYear or fullYear == '' then
		return false
	end
	fullYear = tostring(fullYear)
	
	local fullCat = 'קטגוריה:' .. catBase .. fullYear
	local fullTitle = mw.title.new(fullCat)
	if fullTitle and fullTitle.exists then
		table.insert(infoObj.wikidataCats, '[[' .. fullCat .. ']]')
		return true
	end
	
	if #fullYear < 2 then
		return false
	end
	
	local shortYear = mw.ustring.sub(fullYear, 1, 2)
	local shortCat = 'קטגוריה:' .. catBase .. shortYear
	local shortTitle = mw.title.new(shortCat)
	if shortTitle and shortTitle.exists then
		table.insert(infoObj.wikidataCats, '[[' .. shortCat .. ']]')
		return true
	end
	
	return false
end

local function tryAlbumCategory(infoObj, albumType, year)
	if not year or year == '' then
		return false
	end
	year = tostring(year)
	
	local category = getAlbumCategoryName(albumType, year)
	local fullCat = 'קטגוריה:' .. category
	local title = mw.title.new(fullCat)
	if title and title.exists then
		table.insert(infoObj.wikidataCats, '[[' .. fullCat .. ']]')
		return true
	end
	return false
end

local function addDateBasedCategories(templateArgs, entityId, infoObj, isSingle, single_or_album_type)
	local ns = mw.title.getCurrentTitle().namespace
	if ns ~= 0 or templateArgs['ללא קטגוריה'] then return end

	local dateModule = require('Module:תאריך')
	local datesToTry = {}
	local singlesDatesToTry = {}
	
	-- Local params first
	for _, param in ipairs({ 
		'יצא לאור', 
		'הוקלט',
		'תאריך כתיבה' 
	}) do
		local val = templateArgs[param]
		if val and val ~= '' then
			table.insert(datesToTry, val)
			if param == 'יצא לאור' then
				table.insert(singlesDatesToTry, val)
			end
		end
	end

	-- Wikidata fallback
	if entityId then
		for _, prop in ipairs({ 
			'P577', 
			'P10135'
		}) do
			local val = PropertyLink.getPropertyByOptions(prop, entityId, { allowMulti = false })
			if val and val ~= '' then
				table.insert(datesToTry, val)
				if prop == 'P577' then
					table.insert(singlesDatesToTry, val)
				end
			end
		end
	end

	local earliestYear = nil
	for _, rawDate in ipairs(datesToTry) do
		local success, parsed = pcall(function()
			return dateModule.parseStrDateSafe{ args = { rawDate, 'שנה' } }
		end)

		if success and parsed then
			local year = tonumber(parsed)
			if year and (not earliestYear or year < earliestYear) then
				earliestYear = year
			end
		end
	end

	if isSingle then
		if earliestYear then
			trySingleCategory(infoObj, 'שירי ', tostring(earliestYear))
		end
		
		for _, rawSingleDate in ipairs(singlesDatesToTry) do
			local success, parsed = pcall(function()
				return dateModule.parseStrDateSafe{ args = { rawSingleDate, 'שנה' } }
			end)
	
			if success and parsed then
				if single_or_album_type == 'סינגל' or single_or_album_type == 'שיר אירוויזיון' then
					trySingleCategory(infoObj, 'סינגלים מ-', tostring(parsed))
				end
			end
		end

	else
		if earliestYear then
			tryAlbumCategory(infoObj, single_or_album_type, earliestYear)
		end
	end
end

local function addArgs(frame, infoObj)
	local parentArgs = frame:getParent().args
	local directArgs = frame.args
	local templateArgs = setmetatable({}, { __index = function(_, key)
		return directArgs[key] ~= nil and directArgs[key] or parentArgs[key]
	end })
	local entityId = infoObj.args.entityId
	
	local isSingle = (templateArgs['שם תבנית'] == 'סינגל')
	local single_or_album_type = templateArgs['סוג']
	
	if not single_or_album_type or single_or_album_type == '' then
		if isSingle then
			single_or_album_type = 'סינגל'
		else
			single_or_album_type = 'אלבום אולפן'
		end
	end
	
	local single_label_map = {
		['רמיקס'] = '[[רמיקס]]',
		['קטע כלי'] = '[[קטע כלי]]',
		['סינגל שיווקי'] = '[[סינגל שיווקי]]',
		['שיר'] = '[[פזמון|שיר]]',
		['שיר אירוויזיון'] = 'שיר אירוויזיון',
		['סינגל'] = '[[סינגל]]'
	}
	
	local album_label_map = {
		['EP'] = '[[מיני-אלבום]]',
		['מיני-אלבום'] = '[[מיני-אלבום]]',
		['מיני-אלבום מחודש'] = '[[מיני-אלבום]] ([[הוצאה מחודשת]])',
		['פסקול'] = '[[פסקול]]',
		['גרסאות כיסוי'] = '[[גרסת כיסוי|אלבום גרסאות כיסוי]]',
		['אלבום הופעה'] = '[[אלבום הופעה]]',
		['הופעה'] = '[[אלבום הופעה]]',
		['אלבום מחזמר'] = '[[אלבום מחזמר]]',
		['מחזמר'] = '[[אלבום מחזמר]]',
		['סינגל אלבום'] = '[[אלבום סינגל]]',
		['אלבום סינגל'] = '[[אלבום סינגל]]',
		['אלבום להיטים'] = '[[אלבום להיטים]]',
		['להיטים'] = '[[אלבום להיטים]]',
		['אלבום דמו'] = '[[דמו (מוזיקה)|אלבום דמו]]',
		['דמו'] = '[[דמו (מוזיקה)|אלבום דמו]]',
		['מארז תקליטורים'] = '[[מארז תקליטורים]]',
		['אלבום אוסף'] = '[[אלבום אוסף]]',
		['אוסף'] = '[[אלבום אוסף]]',
		['מיקסטייפ'] = '[[מיקסטייפ]]',
		['וידאו'] = '[[וידאו]]',
		['אלבום רמיקס'] = '[[אלבום רמיקס]]',
		['רמיקס חוזר'] = '[[אלבום רמיקס]] ([[הקלטה חוזרת (מוזיקה)|הקלטה חוזרת]])',
		['הקלטה חוזרת'] = '[[אלבום מוזיקה|אלבום אולפן]] ([[הקלטה חוזרת (מוזיקה)|הקלטה חוזרת]])',
		['אלבום אולפן / פסקול'] = '[[אלבום מוזיקה|אלבום אולפן]] / [[פסקול]]',
		['הופעה / אולפן'] = '[[אלבום הופעה]] / [[אלבום אולפן]]',
		['הופעה / פסקול'] = '[[אלבום הופעה]] / [[פסקול]]',
		['אלבום מחודש'] = '[[אלבום מוזיקה|אלבום אולפן]] ([[הוצאה מחודשת]])',
		['אלבום אולפן'] = '[[אלבום מוזיקה|אלבום אולפן]]',
		['אולפן'] = '[[אלבום מוזיקה|אלבום אולפן]]',
		['אלבום אולפן ומיני-אלבום'] = '[[אלבום מוזיקה|אלבום אולפן]] ו[[מיני-אלבום]]',
		['אלבום אולפן מחודש ומיני-אלבום'] = '[[אלבום מוזיקה|אלבום אולפן]] ([[הוצאה מחודשת]]) / [[מיני-אלבום]]',
		['אלבום אוסף והופעה'] = '[[אלבום אוסף]] ו[[אלבום הופעה|הופעה]]',
	}

	local single_color_map = {
		['שיר'] = '#E6E8FA',
		['סינגל שיווקי'] = '#99CCFF',
		['שיר אירוויזיון'] = '#ccffcc',
		['רמיקס'] = '#FFF9C7',
		['קטע כלי'] = '#DEA7FF',
		['סינגל'] = '#F4CC50'
	}
	
	local album_color_map = {
		['EP'] = '#F4BF92',
		['מיני-אלבום'] = '#F4BF92',
		['מיני-אלבום מחודש'] = '#F4BF92',
		['פסקול'] = 'gainsboro',
		['מחזמר'] = 'gainsboro',
		['אלבום מחזמר'] = 'gainsboro',
		['גרסאות כיסוי'] = 'thistle',
		['הופעה / פסקול'] = 'burlywood',
		['אלבום הופעה'] = 'burlywood',
		['הופעה'] = 'burlywood',
		['סינגל אלבום'] = '#F4BF92',
		['אלבום סינגל'] = '#F4BF92',
		['אלבום להיטים'] = '#BFE0BF',
		['להיטים'] = '#BFE0BF',
		['אלבום אוסף והופעה'] = '#BFE0BF',
		['מארז תקליטורים'] = '#BFE0BF',
		['אוסף'] = '#BFE0BF',
		['אלבום אוסף'] = '#BFE0BF',
		['אלבום רמיקס'] = '#BFE0BF',
		['רמיקס'] = '#BFE0BF',
		['רמיקס חוזר'] = '#BFE0BF',
		['מיקסטייפ'] = '#BFE0BF',
		['וידאו'] = '#99CCFF',
		['הופעה / אולפן'] = 'lightsteelblue',
		['דמו'] = 'lightsteelblue',
		['אלבום אולפן / פסקול'] = 'lightsteelblue',
		['אלבום מחודש'] = 'lightsteelblue',
		['הקלטה חוזרת'] = 'lightsteelblue',
		['אלבום אולפן ומיני-אלבום'] = 'lightsteelblue',
		['אלבום אולפן מחודש ומיני-אלבום'] = 'lightsteelblue',
		['אולפן'] = 'lightsteelblue',
		['אלבום אולפן'] = 'lightsteelblue'
	}

	local type_label = (isSingle and single_label_map[single_or_album_type or "סינגל"]) or album_label_map[single_or_album_type or "אלבום אולפן"] or ''
	local type_color = (isSingle and single_color_map[single_or_album_type or "סינגל"]) or album_color_map[single_or_album_type or "אלבום אולפן"] or '#F4CC50'

	by_data = type_label .. (isSingle and ' בביצוע ' or ' מאת ')
	by_datastyle = 'background: ' .. type_color .. '; font-size:110%; font-weight: bold; text-align:center'

	useArgsOrWikidata(templateArgs, infoObj, false, nil, {'P175'}, 'מאת', {multi=true, pencil=true, indic=1, data_starts_with=by_data, datastyle=by_datastyle, album='לא'})
	
	if isSingle then
		album_data = 'מתוך '
		if single_or_album_type ~= 'שיר אירוויזיון' then
			album_data = album_data .. 'האלבום '
		end
	
		album_datastyle = 'background: ' .. type_color .. '; font-weight: bold; text-align:center'
		
		useArgsOrWikidata(templateArgs, infoObj, false, nil, {'P361'}, 'אלבום', {multi=true, pencil=true, indic=2, data_starts_with=album_data, datastyle=album_datastyle, album='כן'})
	end
	
	addDateBasedCategories(templateArgs, entityId, infoObj, isSingle, single_or_album_type)
end

function infobox(frame)
	local infoObj = Infobox:new()
	frame.args['תמונה-גודל'] = frame.args['תמונה-גודל'] or '220'
	infoObj:parseArgs(frame)
	
	addArgs(frame, infoObj)
	
	return infoObj:render()
end

return	{
	['מידע']=infobox
}