Módulo:Ficha de serie de televisión

Este módulo no tiene página de documentación[crear]
local z = {}

local Entidad        -- Tabla con los datos en Wikidata de la serie.
local Entidades = {} -- Tabla con los datos de Wikidata de otros elementos accedidos

-- Módulos utilizados
local ModuloFicha            = require('Módulo:Ficha')
local ModuloWikidata         = require('Module:Wikidata')
local 	getPropiedadEntidad  = ModuloWikidata.propiedad
local ModuloWikidataFormatos = require('Módulo:Wikidata/Formatos')
local   formatoId            = ModuloWikidataFormatos.formatoId
local ModuloPaginas	         = require('Módulo:Páginas')	
local elementoTabla          = require('Módulo:Tablas').elemento
local ModuloCategorizar			= require('Módulo:Categorizar')
local 	categoriza				= ModuloCategorizar.categoriza

-- Constantes

local categoriasGenerosSeries = {
	   [24925  ] = 'Series de televisión de ciencia ficción'  -- Debe hacerse por país
	 , [40831  ] = 'Series de televisión cómicas' -- comedia

 	 , [859369 ] = 'Series de televisión de comedia dramática'
	 , [208505]  = 'Series de televisión policíacas' -- No existe un género para crímenes.
	 , [2321734] = 'Series de televisión policíacas' -- "Policía procesal"
	 , [1366112] = 'Series de televisión dramáticas'
	 , [181001]  = 'Series de televisión eróticas' -- erotismo
--	 , ['espionaje']         = 'Categoría:Series de televisión de espionaje'
	 , [5434357] = 'Series de televisión de fantasía'
--	 , ['gastronomía']       = 'Categoría:Series de televisión sobre gastronomía'
	 , [1196408] = 'Series de televisión históricas' -- ficción histórica
	 , [53094  ] = 'Series de televisión de humor negro'
--	 , ['infantil']          = 'Categoría:Series de televisión infantiles'
--	 , ['romance']           = 'Categoría:Series de televisión románticas'
	 , [182015]          = 'Series de televisión de suspenso' -- suspenso, suspense, thriller
     , [200092] = 'Series de televisión de terror' -- Terror, género cinematográfico
     , [193606] = 'Series de televisión de terror' -- Terror, género literario	 
	 -- 6585139: misterio
	 -- 10728648: occult detective fiction

}

local categoriasGenerosProgramas = {
--   	   [15286013] = 'Anime y manga cómico' -- anime y manga de comedia
--	 , [581714 ] = 'Series de televisión animadas' -- animación
--	 , [24925  ] = 'Series de televisión de ciencia ficción'
--	 , [40831  ] = 'Series de televisión cómicas' -- comedia
--	 , [170238 ] = 'Series de televisión de comedia de situación'
-- 	 , [859369 ] = 'Series de televisión de comedia dramática'
--	 , [208505]  = 'Series de televisión policíacas' -- No existe un género para crímenes.
--	 , [2321734] = 'Series de televisión policíacas' -- "Policía procesal"
--	 , [7603925] = 'Series de televisión documentales' -- documental televisivo
--	 , [1366112] = 'Series de televisión dramáticas'
	   [181001]  = 'Programas de televisión eróticos' -- erotismo
----	 , ['espionaje']         = 'Categoría:Series de televisión de espionaje'
--	 , [5434357] = 'Series de televisión de fantasía'
----	 , ['gastronomía']       = 'Categoría:Series de televisión sobre gastronomía'
--	 , [1196408] = 'Series de televisión históricas' -- ficción histórica
--	 , [53094  ] = 'Series de televisión de humor negro'
----	 , ['infantil']          = 'Categoría:Series de televisión infantiles'
--	 , [2091526] = 'Series de televisión médicas' -- 'drama médico'
----	 , ['romance']           = 'Categoría:Series de televisión románticas'
--	 , [182015]          = 'Series de televisión de suspense' -- suspense, thriller
--	 , [193606] = 'Series de televisión de terror'
--	 -- 6585139: misterio
--	 -- 10728648: occult detective fiction
--	 , [275934] = 'Series de televisión Tokusatsu'
----	 , [23745 ] = 'Telenovelas'
--	 , [172980] = 'Westerns de televisión'
}

--Categorías según género para las cuales no existe una categoría diferente según
--se trate de una serie o un programa de televisión.

local categoriasGeneros = {
    [15286013] = 'Anime y manga cómico' -- anime y manga de comedia	
   -- 661436 Call TV. Sin categoría.
  , [170238 ] = 'Series de televisión de comedia de situación'
  , [846662 ] = 'Concursos televisivos' 
  , [622370 ] = 'Docudramas'                           -- docudrama
  , [399811 ] = 'Doramas'                              -- Drama japonés
  , [3634883 ] = 'Series de televisión de drama sobrenatural' -- Drama sobrenatural
  , [986699 ] = 'Late night shows'                     -- Late night show
  , [5778915] = 'Programas de televisión humorísticos' -- Comedia de sketches, humor
  , [1962634] = 'Programas de televisión informativos' -- programa informativo. FALTA. Esta categoría va por país
  , [182415 ] = 'Reality shows'	                       -- telerrealidad
  , [5227671] = 'Dating shows'  					   -- Dating show
  , [1107   ] =	'Series de anime'                      -- anime
  , [581714 ] = 'Series de televisión animadas'        
  , [93204  ] = 'Series de televisión documentales'    -- documental
  , [7603925] = 'Series de televisión documentales'    -- documental televisivo
  , [2091526] = 'Series de televisión médicas'         -- drama médico
  , [275934 ] = 'Series de televisión Tokusatsu'       -- Tokusatsu
  , [1760864] = 'Series documentales de naturaleza'    -- documental sobre naturaleza. FALTA crear la categoría
-- Ahora hay una categoría llamada Documentales de naturaleza pero incluye películas.

  -- comedia dramática (Q859369)
  -- Magazine (género televisivo). Sin categoría
  -- telecomedia (Q9082438)  
  , [1484397] = 'Talent shows'           -- Talent show
  , [622812 ] = 'Talk shows'             -- talk show
--	 , [23745 ] = 'Telenovelas'
  , [172980 ] = 'Westerns de televisión' -- western
}

local tipos = {
	['1']						= 'Serie de televisión',
	['serie']					= 'Serie de televisión',
	['serie de televisión'] 	= 'Serie de televisión',
	['serie de television']		= 'Serie de televisión',
	
	['2']						= 'Programa de televisión',
	['programa']				= 'Programa de televisión',
	['programa de televisión']	= 'Programa de televisión',
	['programa de television']	= 'Programa de televisión',
	
	['3']						= 'Especial de televisión',
	['especial']				= 'Especial de televisión',
	['especial de televisión']	= 'Especial de televisión',
	['especial de television']	= 'Especial de televisión',
	
	['4']						= 'Serie de televisión web',
	['serie web']				= 'Serie de televisión web',
	['serie de televisión web']	= 'Serie de televisión web',
	['serie de television web']	= 'Serie de televisión web',
	
	['temporada']               = 'Temporada',
}

local tiposWikidata = {
	['Q5398426']	= 'Serie de televisión', -- Serie de televisión
	['Q117467246']  = 'Serie de televisión', -- Serie de televisión de animación
	['Q1259759']    = 'Serie de televisión', -- Miniserie
	['Q63952888']   = 'Serie de televisión', -- Serie de televisión de anime
	['Q113687694']  = 'Serie de televisión', -- Serie de OVAs
	['Q15416']		= 'Programa de televisión', -- Programa de televisión
	['Q21232614']   = 'Programa de televisión', -- Serie de telerrealidad
	['Q1358344']    = 'Programa de televisión', -- Informativo
	['Q1261214']    = 'Especial de televisión', -- Especial de televisión
	['Q526877']     = 'Serie de televisión web', -- Serie web
	['Q117467240']  = 'Serie de televisión web', -- Serie web animada
	['Q3464665']    = 'Temporada', -- Temporada televisiva
}

-- Constantes de formato
local soloUno				= {['rangoMayor'] = 'sí', ['uno'] = 'sí' }
local rangoMayor			= {['rangoMayor'] = 'sí' }
local listaNoOrdenada		= {['lista'] = 'no ordenada', ['formatoTexto'] = 'mayúscula'}
local formatoCategorizar	= {['separador'] = '<br />', ['conjunción'] = '<br />', ['enlace'] = 'no'}
local formatoDuracion       = {['rangoMayor'] = 'sí', ['formatoUnidad'] = 'minutos'}
local formatoEnlace         = {['rangoMayor'] = 'sí', ['uno'] = 'sí', ['valor-función'] = z.obtenerSitelink}
local soloUnoQid            = {['rangoMayor'] = 'sí', ['uno'] = 'sí', ['valor-función'] = formatoId }
local unoSinEnlace          = {['rangoMayor'] = 'sí', ['uno'] = 'sí', ['enlace'] = 'no' }

function z.categorizar(frame)
	-- De momento no voy a utilizar los argumentos para las categorías. Hay que 
	-- duplicar el código y no creo que merezca la pena. Lo que se debería
	-- hacer es informar el género en Wikidata.
 
    local categorias = {}
    
    -- Obtener los datos de la página donde se inserta la ficha de Wikidata.
    Entidad = mw.wikibase.getEntityObject() or {}
    
    -- Salir si la página no tiene declaraciones en Wikidata.
    if not Entidad or not Entidad.claims then
        return
    end
    
    instancia = propiedad('P31', {['enlace']='no'}) or ''
    
    -- Categorías por género para las que no es necesario saber el tipo de instancia
    table.insert(categorias, ModuloWikidata.categorizar({['categoría'] = categoriasGeneros},Entidad.claims['P136']))      
    
    --Categorías según el tipo de instancia
    
    if instancia:match('[Pp]rograma de televisión') and 
       (instancia:match('[Ss]erie de televisión') or instancia:match('[Mm]iniserie')) then -- Q1259759

      table.insert(categorias,'[[Categoría:Wikipedia:Páginas con ficha de serie de televisión con dos instancias]]')
    elseif instancia:match('[Ss]erie de televisión') or instancia:match('[Mm]iniserie') then
        -- Miniseries de televisión
        if instancia:match('[Mm]iniserie') then -- Q1259759
            table.insert(categorias,[[Categoría:Miniseries de televisión]])
        end

    	-- Categorías para series de televisión por género
    	table.insert(categorias, ModuloWikidata.categorizar({['categoría'] = categoriasGenerosSeries},Entidad.claims['P136']))
    	
    	table.insert(categorias, ModuloWikidata.categorizar(
    		  {['categoría'] = 'Series de televisión iniciadas en $1'
    		  , ['formatoFecha']='año'}
    		  , Entidad.claims['P580']))  -- fecha de inicio

    	table.insert(categorias, ModuloWikidata.categorizar(
    		  {['categoría'] = ' Series de televisión finalizadas en $1'
    		  , ['formatoFecha']='año'}
    		  , Entidad.claims['P582']))    	-- fecha de fin. FALTA añadir un nuevo campo para que si no existe la fecha de fin ponga la categoría Series de televisión en curso
    		  
        --Idioma
        table.insert(categorias, ModuloWikidata.categorizar(
       	   {['categoría']     = 'Series de televisión en $1',
       	   },Entidad.claims['P364']))     		  
       	
       	-- Emisora original
        table.insert(categorias, ModuloWikidata.categorizar(
       	   {['categoría']     = 'Series de televisión de $1',
       	   },Entidad.claims['P449']))     		         	

    elseif instancia:match('[Pp]rograma de televisión') then	
    	-- Categorías para programas de televisión por género
    	table.insert(categorias, ModuloWikidata.categorizar({['categoría'] = categoriasGenerosProgramas},Entidad.claims['P136']))
    elseif instancia:match('[Tt]emporada') then
    	-- Categorías para temporadas de televisión
    else
    	-- La instancia no contiene ni serie ni programa de televisión.
        table.insert(categorias,'[[Categoría:Wikipedia:Páginas con ficha de serie de televisión sin instancia]]')
    end
    
    return table.concat(categorias)
end

-- Función que devuelve la lista de los valores de una propiedad en Wikidata formateados
function propiedad(idPropiedad, opciones)
    if Entidad and Entidad.claims and Entidad.claims[idPropiedad] then
    	if not opciones then
    		opciones = {}
    	end
    	opciones['propiedad'] = idPropiedad
    	return ModuloWikidata.getPropiedad(opciones,Entidad.claims[idPropiedad])
    end
end

function obtenerValorCalificativo(Propiedad, Calificativo, ValorPropiedad)
	-- Obtener el valor del primer calificativo de la propiedad con el valor recibido 
	if not Entidad or not Entidad.claims or not Entidad.claims[Propiedad] then
		return
	end
	
	for k,v in pairs(Entidad.claims[Propiedad]) do
		if	 v.mainsnak
		   and v.mainsnak.datavalue
		   and v.mainsnak.datavalue.value
		   and v.mainsnak.datavalue.value['id'] == ValorPropiedad
		   and v.qualifiers
		   and v.qualifiers[Calificativo]
		   and v.qualifiers[Calificativo][1]
		   and v.qualifiers[Calificativo][1].datavalue then 
			return ModuloWikidata.formatoDato(v.qualifiers[Calificativo][1], {['formatoTexto'] = 'mayúscula', ['lista'] = 'sí'})--.datavalue)--.value)
		end
	end
	
	return nil
end

function z.Ficha(frame)
	ModuloWikidata:setFrame(frame)  -- No funciona si se pone ModuloWikidata.setFrame(marco)	
	-- Obtener una copia de los argumentos eliminando los argumentos sin valor
	-- y dejando en blanco (aunque no nil) aquellos que valen "no"
	local argumento = obtenerArgumentosConValor(frame)
	
	local color		= '#C6C9FF'
	local estilotitulo = 'background-color:'..color.. '; font-style:italic'
	local estiloseccion = 'background-color:'..color
	
	Entidad = mw.wikibase.getEntityObject(argumento['entidad']) or {}
	
	local tipo
	if argumento['tipo'] and tipos[ mw.ustring.lower(argumento['tipo'])] then
		tipo = tipos[ mw.ustring.lower(argumento['tipo'])]
	else
		tipo = obtenerTipoWikidata()
	end
	
	local tituloFicha = argumento['título'] or propiedad('P1476', soloUno) or 
						(tipo == 'Temporada' and propiedad('P179', unoSinEnlace)) or
						obtenerEtiquetaWikidata() or ModuloPaginas.nombrePagina({desambiguar='sí'})
	
	local subtitulo = tipo
	if tipo == 'Temporada' and argumento['orden_temporada'] then
		subtitulo = argumento['orden_temporada'] .. ' temporada'
	elseif tipo == 'Temporada' then
		local wdNumTemporada = obtenerValorCalificativo('P179', 'P1545', propiedad('P179', soloUnoQid))
		if wdNumTemporada then
			wdNumTemporada = require('Módulo:ConvertNumeric').numeral_to_spanish({ ['args'] = { [1] = wdNumTemporada, ['case'] = 'U', ['ord'] = 'on' }})
			subtitulo = string.gsub(wdNumTemporada, 'o$', 'a') .. ' temporada'
		end
	end
	
	-- Imagen y pie de la imagen
	local imagen = argumento['imagen']
	local pieDeImagen
	
	if imagen then
		pieDeImagen = argumento['pie de imagen']
	else
		imagen, pieDeImagen = obtenerImagenWikidata()
	end
	
	local protagonistas = argumento['reparto'] or argumento['protagonistas'] or argumento['starring']
	if not protagonistas then
		protagonistas = propiedad('P161', listaNoOrdenada)
		if protagonistas then
			local _, count = string.gsub(protagonistas, "<li>", "")
			 
			-- Si la lista es muy larga hacerla collapsible
			if count > 10 then
				protagonistas = '<div class="mw-collapsible mw-collapsed"><span class="noprint">'..count..' personas</span><div class="mw-collapsible-content">' .. protagonistas .. '</div></div>'
			end
		end
	end
	
	local datosTemaPrincipal = formatearTema({
		['tema']       = argumento['tema principal'],
		['autor']      = argumento['autor tema principal'],
		['intérprete'] = argumento['intérprete principal'] or argumento['interprete principal']
	})

	local datosTemaPrincipal2 = formatearTema({
		['tema']       = argumento['tema principal 2'],
		['autor']      = argumento['autor tema principal 2'],
		['intérprete'] = argumento['intérprete principal 2'] or argumento['interprete principal 2']
	})

	local datosTemaCierre = formatearTema({
		['tema']       = argumento['tema de cierre'],
		['autor']      = argumento['autor tema cierre'],
		['intérprete'] = argumento['intérprete cierre'] or argumento['interprete cierre']
	})

	local datosTemaCierre2 = formatearTema({
		['tema']       = argumento['tema de cierre 2'],
		['autor']      = argumento['autor tema cierre 2'],
		['intérprete'] = argumento['intérprete cierre 2'] or argumento['interprete cierre 2']
	})

	local etiquetaTemaPrincipal = 'Tema principal'
	if datosTemaPrincipal and datosTemaPrincipal2 then
		etiquetaTemaPrincipal = 'Temas principales'
		datosTemaPrincipal = datosTemaPrincipal .. '<br />' .. datosTemaPrincipal2
	else
		datosTemaPrincipal = datosTemaPrincipal or datosTemaPrincipal2
	end
	
	local etiquetaTemaCierre = 'Tema de cierre'
	if datosTemaCierre and datosTemaCierre2 then
		etiquetaTemaPrincipal = 'Temas de cierre'
		datosTemaCierre = datosTemaCierre .. '<br />' .. datosTemaCierre2
	else
		datosTemaCierre = datosTemaCierre or datosTemaCierre2
	end
	
	local listaEpisodios = argumento['lista episodios'] or argumento['list_episodes'] or obtenerListaEpisodiosWikidata()
	if listaEpisodios then
		listaEpisodios = ' <span style="white-space:nowrap">([[' .. listaEpisodios .. '|lista de episodios]])</span>'
	end
	
	local sucesion = {}
	
	if argumento['precedido por'] or argumento['preceded_by'] or 
		argumento['sucedido por'] or argumento['followed_by'] then
		
		sucesion = {
			['tipo']			= 'sección',
			['título']			= argumento['criterio sucesión'] or 'Cronología de producción',
			['estilotitulo']	= estiloseccion,
			{
				['tipo']			= 'sucesión',
				['estilo fuente']	= 'italic',
				['anterior']		= argumento['precedido por'] or argumento['preceded_by'],
				['actual']			= tituloFicha,
				['siguiente']		= argumento['sucedido por'] or argumento['followed_by']
			}
		}
		elseif tipo == 'Temporada' and 
			(argumento['temporada anterior'] or argumento['temporada siguiente'] or 
				obtenerValorCalificativo('P179', 'P155', propiedad('P179', soloUnoQid)) or 
				obtenerValorCalificativo('P179', 'P156', propiedad('P179', soloUnoQid))) then
		sucesion = {
			['tipo']			= 'sección',
			['título']			= 'Temporadas de ' .. propiedad('P179', unoSinEnlace),
			['estilotitulo']	= estiloseccion,
			{
				['tipo']			= 'sucesión',
				['estilo fuente']	= 'italic',
				['anterior']		= argumento['temporada anterior'] or obtenerValorCalificativo('P179', 'P155', propiedad('P179', soloUnoQid)),
				['actual']			= subtitulo,
				['siguiente']		= argumento['temporada siguiente'] or obtenerValorCalificativo('P179', 'P156', propiedad('P179', soloUnoQid))
			}
		}
	end

	local etiquetaInicioEmision
	if tipo == 'Especial de televisión' then
		etiquetaInicioEmision = 'Fecha de emisión'
	elseif argumento['última emisión'] or argumento['última_emisión'] or propiedad('P582', rangoMayor) then
		etiquetaInicioEmision = 'Primera emisión'
	else
		etiquetaInicioEmision = 'Fecha de lanzamiento'
	end
	
	local imdbWikidata = propiedad('P345', soloUno) or (propiedad('P179') and getPropiedadWikidata(propiedad('P179', soloUnoQid), 'P345', soloUno))
	local filmaffinityWikidata = propiedad('P480', soloUno) or (propiedad('P179') and getPropiedadWikidata(propiedad('P179', soloUnoQid), 'P480', soloUno))
	
	local sitioWeb, imdbId, filmaffinityId
	sitioWeb = argumento['sitio web'] or propiedad('P856', soloUno)
	filmaffinityId = argumento['filmaffinity'] or filmaffinityWikidata
	imdbId = (argumento['imdb'] and ('tt' .. argumento['imdb'])) or imdbWikidata
		
	local Ficha = {
		entidad		= argumento['entidad'],
		clase		= 'plainlist plainlinks',

		-- Título
		tipocabecera		= 'televisión',
		estilotitulo		= estilotitulo,
		titulo				= tituloFicha,
		subtitulo1			= subtitulo or 'Programa o serie de televisión',
		
		--Imagen
		imagen			 = imagen,
		['tamañoimagen'] = argumento['tamaño de imagen'] or '250px',
		pie				 = pieDeImagen,
		
		{ tipo = 'sección',
			{ 'También conocido como', argumento['alt_name'] or argumento['título alternativo'] },
			{ 'Títulos en español', argumento['título español'] },
			{ 'Lema', argumento['lema'] or propiedad('P1546'), estilodatos='font-style:italic' },
			{ 'Género', argumento['género'] or argumento['genre'] or propiedad('P136', listaNoOrdenada), clase='categoría' },
			{ 'Creado por', argumento['creador'] or argumento['creator'] or propiedad('P170', listaNoOrdenada) },
			{ 'Basado en', argumento['basado en'] or argumento['based_on'] },
			{ 'Desarrollado por', argumento['desarrollador'] or argumento['developer'] },
			{ 'Escrito por', argumento['escritor'] or argumento['writer'] },
			{ 'Guion por', argumento['guionista'] or argumento['guion'] or argumento['screenplay'] },
			{ 'Historia por', argumento['historia'] or argumento['story'] },
			{ 'Dirigido por', argumento['director'], clase='attendee' },
			{ '<span style="white-space:nowrap">Director(es)</span> <span style="white-space:nowrap">creativo(s)</span>', argumento['director creativo'] or argumento['creative_director'], clase='attendee' },
			{ 'Presentado por', argumento['presentador'] or argumento['presenter'] or argumento['anfitrión'] or argumento['host'] or propiedad('P371', listaNoOrdenada), clase='attendee' },
			{ 'Protagonistas', protagonistas, clase='attendee' },
			{ 'Jurado', argumento['jurado'] or argumento['judges'], clase='attendee' },
			{ 'Voces de', argumento['voces'] or argumento['voices'], clase='attendee' },
			{ 'Voces de', argumento['narrador'] or argumento['narrated'], clase='attendee' },
			{ etiquetaTemaPrincipal, datosTemaPrincipal },
			{ etiquetaTemaCierre, datosTemaCierre },
			{ 'Compositor(es)', argumento['música'] or argumento['music'] or argumento['compositor'] or argumento['composer'] or propiedad('P86', listaNoOrdenada) },
			{ 'Ambientación', argumento['ambientación'] },
			{ 'País de origen', argumento['país de origen'] or argumento['country'] or propiedad('P495', listaNoOrdenada) },
			{ '<span style="white-space:nowrap">Idioma(s)</span> <span style="white-space:nowrap">original(es)</span>', argumento['idioma'] or argumento['language'] or propiedad('P364', listaNoOrdenada) },
			{ '<abbr title="Número">N.º</abbr> de temporadas', argumento['num temporadas'] or argumento['num_seasons'] or propiedad('P2437', rangoMayor) },
			{ '<abbr title="Número">N.º</abbr> de seriales', argumento['num serial'] or argumento['num_series'] },
			{ '<abbr title="Número">N.º</abbr> de partes', argumento['num partes'] },
			{ '<abbr title="Número">N.º</abbr> de episodios', (argumento['num episodios'] or argumento['num_episodes'] or propiedad('P1113', rangoMayor) or '') .. (listaEpisodios or '') },
		},
	
		{ tipo = 'sección',
			['título'] = 'Producción',
			estilotitulo = estiloseccion,
			{ '<span style="white-space:nowrap">Productor(es)</span> <span style="white-space:nowrap">ejecutivo(s)</span>', argumento['productor ejecutivo'] or argumento['executive_producer'] },
			{ '<span style="white-space:nowrap">Productor(es)</span>', argumento['productor'] or argumento['producer'] or propiedad('P162') },
			{ '<span style="white-space:nowrap">Editor(es)</span> de noticias', argumento['editor noticias'] or argumento['news_editor'] },
			{ '<span style="white-space:nowrap">Lugar(es)</span> de producción', argumento['localización'] or argumento['location'] },
			{ 'Cinematografía', argumento['cinematografía'] or argumento['cinematography'] },
			{ '<span style="white-space:nowrap">Animador(es)</span>', argumento['animador'] or argumento['animator'] },
			{ '<span style="white-space:nowrap">Editor(es)</span>', argumento['editor'] },
			{ 'Configuración de la cámara', argumento['cámara'] or argumento['camera'] },
			{ 'Duración', argumento['duración'] or argumento['runtime'] or propiedad('P2047', formatoDuracion) },
			{ '<span style="white-space:nowrap">Empresa(s)</span> <span style="white-space:nowrap">productora(s)</span>', argumento['empresa productora'] or argumento['company'] or argumento['estudio'] or argumento['studio'] },
			{ 'Distribuidor', argumento['distribuidor'] or argumento['distributor'] },
			{ 'Presupuesto', argumento['presupuesto'] or argumento['budget'] },
		},
		
		{ tipo = 'sección',
			['título'] = 'Lanzamiento',
			estilotitulo = estiloseccion,
			{ 'Medio de difusión', argumento['red'] or argumento['network'] or argumento['cadena'] or argumento['channel'] or argumento['medios de difusión'] or propiedad('P449', listaNoOrdenada) },
			{ 'Calificación por edades', argumento['edad'] },
			{ 'Horario', argumento['horario'] },
			{ 'Audiencia', argumento['audiencia'] or argumento['rating'] },
			{ 'Meta inicial', argumento['meta inicial'] },
			{ 'Recaudación', argumento['recaudación'] },
			{ 'Formato de imagen', argumento['formato de imagen'] or argumento['picture_format'] },
			{ 'Formato de audio', argumento['formato de audio'] or argumento['audio_format'] },
			{ 'Mostrado primero en', argumento['mostrado primero'] or argumento['first_run'] },
			{ etiquetaInicioEmision, argumento['primera emisión'] or argumento['primera_emisión'] or argumento['fecha de emisión'] or propiedad('P580', {['rangoMayor'] = 'sí', ['enlace'] = 'no'}) },
			{ 'Última emisión', argumento['última emisión'] or argumento['última_emisión'] or propiedad('P582', {['rangoMayor'] = 'sí', ['enlace'] = 'no'}) },
			{ 'Intervalos de emisión', argumento['intervalos de emisión'] or argumento['fechas de emisión'] },
		},
	
		sucesion,
		
		{tipo='sección',
			['título'] = 'Producciones relacionadas',
			estilotitulo = estiloseccion,
			{ '', argumento['relacionados'] or argumento['related'] },
		},
	
		{tipo='sección',
			['título'] = 'Enlaces externos',
			estilotitulo = estiloseccion,
			{ '', sitioWeb and ('[' .. sitioWeb .. ' Sitio web oficial]') },
			{ '', filmaffinityId and '[http://www.filmaffinity.com/es/film' .. filmaffinityId .. '.html Ficha] en [[FilmAffinity]]' },
			{ '', imdbId and '[http://www.imdb.com/title/' .. imdbId .. '/fullcredits Ver todos los créditos] <span style="font-size:smaller">([[Internet Movie Database|IMDb]])</span>' },
			{ '', imdbId and '[http://www.imdb.com/title/' .. imdbId .. '/ Ficha] en IMDb' },
		},
	}
	-- Si no hay que categorizar automáticamente terminar aquí e ignorar la
	-- generación de categorías
	namespace = mw.title.getCurrentTitle().namespace
	if argumento['categorías'] == 'no' or not (namespace == 0 or namespace == 104) then
		return ModuloFicha.infobox(Ficha)
	end
	
	-- A partir de aquí se generan y definen las distintas categorías
	-- automáticas
	ModuloCategorizar.setFrame(frame)
	categorias = ''
	
	local prefijoCategoria, categoriaInicio, categoriaFin
	
	if tipo == 'Serie de televisión' then
		prefijoCategoria = 'Series de televisión'
		categoriaInicio = 'Series de televisión iniciadas en $1'
		categoriaFin = 'Series de televisión finalizadas en $1'
	elseif tipo == 'Programa de televisión' then
		prefijoCategoria = 'Programas de televisión'
		categoriaInicio = 'Programas de televisión iniciados en $1'
		categoriaFin = 'Programas de televisión finalizados en $1'
	elseif tipo == 'Especial de televisión' then
		prefijoCategoria = 'Programas de televisión'
		categoriaInicio = 'Programas de televisión especiales de $1'
	end
	
	-- Normalizar argumentos para la categorización
	if argumento['género'] or argumento['genre'] then argumento['género'] = mw.ustring.lower(argumento['género'] or argumento['genre']) end
	if argumento['idioma'] or argumento['language'] then argumento['idioma'] = mw.ustring.lower(argumento['idioma'] or argumento['language']) end
	if argumento['país de origen'] or argumento['country'] then argumento['país de origen'] = argumento['país de origen'] or argumento['country'] end
	
	-- Arreglar parámetros que la gente acostumbra a introducir mal en la plantilla para que no rompan la categorización
	if argumento['idioma'] then argumento['idioma'] = string.gsub(argumento['idioma'], '<br>', '<br />') end
	if argumento['idioma'] then argumento['idioma'] = string.gsub(argumento['idioma'], '<br/>', '<br />') end
	if argumento['idioma'] then argumento['idioma'] = string.gsub(argumento['idioma'], ',%s', '<br />') end
	if argumento['idioma'] then argumento['idioma'] = string.gsub(argumento['idioma'], '%s/%s', '<br />') end
	if argumento['idioma'] then argumento['idioma'] = string.gsub(argumento['idioma'], '%se%s', '<br />') end
	if argumento['idioma'] then argumento['idioma'] = string.gsub(argumento['idioma'], '%sy%s', '<br />') end
	if argumento['género'] then argumento['género'] = string.gsub(argumento['género'], 'drama %(cine y televisión%)', 'drama') end
	if argumento['género'] then argumento['género'] = string.gsub(argumento['género'], '<br>', '<br />') end
	if argumento['género'] then argumento['género'] = string.gsub(argumento['género'], '<br/>', '<br />') end
	if argumento['género'] then argumento['género'] = string.gsub(argumento['género'], ',%s', '<br />') end
	if argumento['género'] then argumento['género'] = string.gsub(argumento['género'], '%s/%s', '<br />') end
	if argumento['género'] then argumento['género'] = string.gsub(argumento['género'], '%sy%s', '<br />') end
	if argumento['género'] then argumento['género'] = string.gsub(argumento['género'], '%se%s', '<br />') end
	
	if argumento['género'] then argumento['género'] = string.gsub(argumento['género'], '%[%[[^%|%]]*|drama histórico%]%]', 'drama<br />histórico') end
	if argumento['género'] then argumento['género'] = string.gsub(argumento['género'], 'drama histórico', 'drama<br />histórico') end
	if argumento['género'] then argumento['género'] = string.gsub(argumento['género'], '%[%[[^%|%]]*|drama romántico%]%]', 'drama<br />romance') end
	if argumento['género'] then argumento['género'] = string.gsub(argumento['género'], '%[%[[^%|%]]*|drama%]%] %[%[[^%|%]]*|romántico%]%]', 'drama<br />romance') end
	if argumento['género'] then argumento['género'] = string.gsub(argumento['género'], 'drama romántico', 'drama<br />romance') end
	if argumento['género'] then argumento['género'] = string.gsub(argumento['género'], '%[%[comedia%]%] %[%[musical%]%]', 'comedia<br />musical') end
	if argumento['género'] then argumento['género'] = string.gsub(argumento['género'], 'comedia musical', 'comedia<br />musical') end
	
	if argumento['idioma'] then argumento['idioma'] = string.gsub(argumento['idioma'], '%.$', '') end
	if argumento['país de origen'] then argumento['país de origen'] = string.gsub(argumento['país de origen'], '%.$', '') end
	
	function listaidiomas(str)
		-- Minúscula inicial para cada elemento de la lista de idiomas, no solo el primero
		local tab = mw.text.split(str, '<br />', true)
		local lang = mw.getContentLanguage()
		
		for k,v in pairs(tab) do
			tab[k] = lang:lcfirst(v)
		end
		return mw.text.listToText(tab, '<br />', '<br />')
	end
	
	if prefijoCategoria then
		
		-- Categorización por idioma
		categorias = categorias .. categoriza(prefijoCategoria .. ' en $1', '<br />', {[1] = argumento['idioma'] or listaidiomas(propiedad('P364', formatoCategorizar) or '' )}, { ['arreglar'] = 'nombre idioma', ['filtrar'] = false })
	
		-- Categorización por país
		categorias = categorias .. categoriza(prefijoCategoria .. ' de $1', '<br />', {[1] = argumento['país de origen'] or propiedad('P495', formatoCategorizar)}, { ['arreglar'] = 'nombre país', ['filtrar'] = false })
	
		-- Categorización por género
		if prefijoCategoria == 'Series de televisión' then
			categorias = categorias .. categoriza(prefijoCategoria .. ' de $1', '<br />', {[1] = argumento['género'] or propiedad('P136', formatoCategorizar)}, {['arreglar'] = 'géneros series tv', ['filtrar'] = true})
		elseif prefijoCategoria == 'Programas de televisión' then
			categorias = categorias .. categoriza(prefijoCategoria .. ' de $1', '<br />', {[1] = argumento['género'] or propiedad('P136', formatoCategorizar)}, {['arreglar'] = 'géneros programas tv', ['filtrar'] = true})
		end
	
		-- Categorización por cadena
		categorias = categorias .. categoriza(prefijoCategoria .. ' de $1', '<br />', {[1] = argumento['cadena'] or propiedad('P449', formatoCategorizar)}, { ['filtrar'] = true })
	
	end
	
	if categoriaInicio then
		categorias = categorias .. categoriza(categoriaInicio, '<br />', {[1] = propiedad('P580', {['rangoMayor'] = 'sí', ['formatoFecha'] = 'año', ['enlace'] = 'no', ['uno'] = 'sí'})}, {['filtrar'] = true})
	end
	
	if categoriaFin then
		categorias = categorias .. categoriza(categoriaFin, '<br />', {[1] = propiedad('P582', {['rangoMayor'] = 'sí', ['formatoFecha'] = 'año', ['enlace'] = 'no', ['uno'] = 'sí'})}, {['filtrar'] = true})
	end
	
	if argumento['año inicio'] or argumento['año final'] then 
		categorias = categorias .. '[[Categoría:Wikipedia:Artículos con ficha sin actualizar]]'
	end
	
	-- Añadir '0' delante del parámetro imdb en caso de que exista hasta que 
	-- tenga al menos 7 caracteres para asegurarse que cumpla con el formato
	-- establecido en Wikidata
	if argumento['imdb'] then
		while #argumento['imdb'] < 7 do
			argumento['imdb'] = '0'..argumento['imdb']
		end
	end
	
	if (argumento['imdb'] and 'tt'..argumento['imdb'] ~= imdbWikidata) or (argumento['filmaffinity'] and argumento['filmaffinity'] ~= filmaffinityWikidata) then
		categorias = categorias .. '[[Categoría:Wikipedia:Artículos con identificadores diferentes en Wikidata]]'
	end
	
	if not tipo then
		categorias = categorias .. '[[Categoría:Programas de televisión sin tipo identificado]]'
	end
	
	return ModuloFicha.infobox(Ficha) .. categorias
end

function obtenerImagenWikidata()
	local imagen, valorImagen, piesDeImagen, k, pieDeImagen
	if not Entidad then
		return
	end
	
	--  Obtener la primera imagen en Wikidata de la persona
	local imagen = elementoTabla(Entidad, 'claims','P18',1)
		or elementoTabla(Entidad, 'claims','P154',1)
	
	if not imagen then
		return
	end
	
	-- Obtener el nombre de la imagen
	valorImagen =  elementoTabla(imagen, 'mainsnak','datavalue','value') -- Por ejemplo, imagen.jpg
	
	-- Obtener los pies de la imagen, uno por idioma
	piesDeImagen =  elementoTabla(imagen, 'qualifiers','P2096')
	
	-- Encontrar el pie en español (aquel con datavalue.value.language = "es")
	if piesDeImagen then
		for k,pieDeImagen in pairs(piesDeImagen) do
			if pieDeImagen.datavalue.value.language=='es' then
				-- devolver la imagen y el texto del pie de la imagen en español
				return valorImagen, pieDeImagen.datavalue.value.text
			end
		end
	end
	
	-- Sin pie de imagen en español
	return valorImagen
end

function formatearTema(datos)
	
	local creadores = nil
	if datos['autor'] and datos['intérprete'] then
		creadores = 'Compuesto por ' .. datos['autor'] .. ', interpretado por ' .. datos['intérprete']
	elseif datos['autor'] then
		creadores = 'Compuesto por ' .. datos['autor']
	elseif datos['intérprete'] then
		creadores = 'Interpretado por ' .. datos['intérprete']
	end
	
	if datos['tema'] and creadores then
		return datos['tema'] .. '<br /><span style="font-size:90%">(' .. mw.getContentLanguage():lcfirst(creadores) .. ')</span>'
	else
		return datos['tema'] or creadores
	end
end

function obtenerArgumentosConValor(frame)
	local original
	
	if frame == mw.getCurrentFrame() then
		original = frame:getParent().args
	else
		original = frame.args or frame
	end
	
	local copia= {}
	
	for k,v in pairs(original) do
		if v == 'no' then
			--Si vale "no" dejar en blanco el argumento para no obtener el valor
			--de Wikidata
			copia[k] = ''
		elseif v~='' then
			--Si está en blanco dejarlo a nil para obtener en su caso el valor de 
			-- Wikidata si no hay otro argumento con un nombre similar
			copia[k] = original[k]
		end
	end	
	
	return copia
end

function obtenerEtiquetaWikidata()
	if Entidad and Entidad.labels and Entidad.labels.es then
		return Entidad.labels.es.value
	end
end

function obtenerTipoWikidata()
	
	str = propiedad('P31', {['rangoMayor'] = 'sí', ['separador'] = '<br />', ['conjunción'] = '<br />', ['enlace'] = 'no', ['valor-función'] = ModuloWikidataFormatos.formatoId})
	if not str then return nil end
	
	local tab = mw.text.split(str, '<br />', true)
	for k,v in pairs(tab) do
		if tab[k] and tiposWikidata[tab[k]] then
			return tiposWikidata[tab[k]]
		end
	end
	
	return nil
end

function obtenerListaEpisodiosWikidata()
	local idEntidad = propiedad('P1811', {['rangoMayor'] = 'sí', ['uno'] = 'sí', ['enlace'] = 'no', ['valor-función'] = ModuloWikidataFormatos.formatoId})
	if idEntidad then
        return mw.wikibase.sitelink( idEntidad )
    end
end

function getPropiedadWikidata(qid, propiedad, opciones)
	
	if Entidades and not Entidades[qid] then
		Entidades[qid] = mw.wikibase.getEntityObject(qid) or {}
	end
	
	return getPropiedadEntidad(Entidades[qid], propiedad, opciones)
end

return z