--[[
Questo modulo è in appoggio al template Fumetto e animazione per gestirne
le funzioni di categorizzazione automatica
]]
local cfg = mw.loadData("Modulo:Fumetto e animazione/Configurazione/sandbox")
local getArgs = require('Module:Arguments').getArgs
local error_category = 'Errori di compilazione del template Fumetto e animazione'
-- =============================================================================
-- Funzioni di utilità
-- =============================================================================
-- Restituisce i valori di una tabella di alias nella configurazione
local function build_reverse_alias(table_name)
local reverse_alias = {}
for alias, name in pairs(cfg['alias_' .. table_name]) do
if not reverse_alias[name] then reverse_alias[name] = {} end
table.insert(reverse_alias[name], alias)
end
return reverse_alias
end
-- Restituisce un valore senza eventuale wikilink a inizio stringa
local function delink(value)
local pattern
if value:find('|') then
pattern = "^'*%[%[ *([^%|%[%]]-) *%|.-%]%]"
else
pattern = "^'*%[%[ *([^%[%]]-) *%]%]"
end
return value:match(pattern) or value
end
-- Restituisce liste di valori uno alla volta
local function extract_values(args, base_name)
local index = 0
return function()
while true do
index = index + 1
local value = args[base_name .. ' ' .. tostring(index)]
if not value and index == 1 then
value = args[base_name]
end
if not value then break end
return delink(value)
end
end
end
-- Converte la lettera iniziale di una stringa in minuscola
local function lcfirst(str)
return str:gsub('^%u', string.lower)
end
-- Parsifica i parametri rimuovendo le stringhe vuote
local function parse_args(args)
for key, value in pairs(args) do
if value and mw.text.trim(value) == '' then
args[key] = nil
end
end
return args
end
-- Sostituisce le parentesi in una stringa coi corrispondenti codici ascii
local function replace_braces(s)
local new_s = mw.ustring.gsub(s, "%[", "[")
new_s = mw.ustring.gsub(new_s, "%]", "]")
new_s = mw.ustring.gsub(new_s, "%(", "(")
new_s = mw.ustring.gsub(new_s, "%)", ")")
new_s = mw.ustring.gsub(new_s, " ", " ")
return new_s
end
-- =============================================================================
-- classe Media
-- =============================================================================
local Media = {}
-- Costruttore della classe Media
function Media:new(args)
local self = {}
setmetatable(self, { __index = Media })
self.tipo = args.tipo
self.sottotipo = args.sottotipo
self.name = self:_getName()
self.alias = self:_getAlias()
return self
end
-- Verifica se il medium corrisponde a uno di quelli indicati
function Media:inArray(...)
for _, value in ipairs({ ... }) do
if self.tipo == value or self.sottotipo == value or self.name == value then
return true
end
end
return false
end
-- Ottiene l'alias più generico del medium per le categorie
function Media:_getAlias()
return self:_getValue('alias_tipo', 'alias_sottotipo')
end
-- Ottiene il nome più preciso del medium per le categorie
function Media:_getName()
return self:_getValue('tipo', 'sottotipo')
end
-- Cerca il nome o l'alias del medium nella configurazione
function Media:_getValue(key_tipo, key_sottotipo)
local ret = cfg[key_sottotipo][self.tipo] and
cfg[key_sottotipo][self.tipo][self.sottotipo] or
cfg[key_tipo][self.tipo]
return ret and lcfirst(ret) or nil
end
-- =============================================================================
-- classe CategoryManager
-- =============================================================================
local CategoryManager = {}
-- Costruttore della classe CategoryManager
function CategoryManager:new(args)
local self = {}
setmetatable(self, { __index = CategoryManager })
self.args = parse_args(args)
self.media = Media:new(self.args)
self.year = self:_getYear()
self.categories = {}
self.tables_matched = {}
self:_addCategories(self.args.categorie == 'no')
return self
end
-- Restituisce l'elenco di categorie
function CategoryManager:listCategories()
return table.concat(self.categories)
end
-- Avvia la categorizzazione automatica dell'opera
function CategoryManager:_addCategories(error_only)
if (self.args['data inizio'] or self.args['data fine']) and not self.year then
self:_addCategory(error_category)
end
if error_only then return end
if self.media.name == "serie televisive d'animazione" then
self
:_addCategoriesBy('studio_cartoneTV')
:_addCategoriesBy('paese', 'fp', self._categorizeTVSeriesByCountry)
elseif self.media.name == "film d'animazione direct-to-video" then
self
:_addCategory(self.media.name)
:_addCategoriesBy('paese', 'mp', self._categorizeDTVFilmByCountry)
elseif self.media.name == "webserie d'animazione" then
self:_addCategoriesBy('paese', 'fp', self._categorizeWebseriesByCountry)
elseif self.media.name == "film d'animazione per la televisione" then
self:_addCategoriesBy('paese', 'mp', self._categorizeTVFilmByCountry)
elseif self.media.tipo == 'manga' then
self
:_addCategoriesBy('editore_manga')
:_addCategoriesBy('editore')
:_addCategoriesBy('target', nil, self.ucfirst)
elseif self.media:inArray('manhua', 'manhwa') then
self:_addCategoriesBy('editore')
elseif self.media.tipo == 'light novel' then
self
:_addCategory(self.media.tipo)
:_addCategory('Romanzi in giapponese')
:_addCategoriesBy('etichetta')
:_addCategoriesBy('editore')
elseif self.media.tipo == 'fumetto' and self.media.name ~= 'fumetti' then
self
:_addCategoriesBy('etichetta_sottotipo', nil, self._prependSubtype)
:_addCategoriesBy('etichetta')
:_addCategoriesBy('editore_sottotipo', nil, self._prependSubtype)
:_addCategoriesBy('editore')
:_addCategoriesBy('paese', 'mp', self._categorizeComicByCountry)
if not self.tables_matched['etichetta_sottotipo'] and
not self.tables_matched['editore_sottotipo'] then
self:_addCategory(self.media.name)
end
elseif self.media.tipo == 'fumetto' then
self
:_addCategoriesBy('etichetta')
:_addCategoriesBy('editore')
:_addCategoriesBy('paese', 'mp', self._categorizeComicByCountry)
end
if self.media:inArray('anime', 'cartone') then
self:_addCategoriesBy('studio')
local broadcaster
if self.media:inArray('film TV', 'serie TV') then
local network = self.args['rete 1'] or self.args.rete
broadcaster = self:_getCategory(delink(network), 'rete')
elseif self.media.alias == 'webserie' then
local platform = self.args['streaming 1'] or self.args.streaming
broadcaster = self:_getCategory(delink(platform), 'streaming')
end
if broadcaster then
self:_addCategory(self.media.alias .. ' ' .. broadcaster)
end
end
-- categorizzazione per tipo delle opere non suddivise per anno
if self.media:inArray('manhua', 'manhwa', 'ONA', 'webserie') then
self:_addCategory(self.media.name)
-- categorizzazione delle opere suddivise per anno
elseif self.year and self.media.sottotipo ~= 'film direct-to-video' then
local media = self.media.name ~= 'serie televisive anime' and
self.media.alias or self.media.name
self:_addCategory(string.format('%s del %s', media, self.year))
end
end
-- Aggiunge categorie per una lista di valori
function CategoryManager:_addCategoriesBy(table_name, gender, callback)
if self:_isCategoryRedundant(table_name) == false then
local base_name = table_name:match('[^_]+')
for value in extract_values(self.args, base_name) do
if table_name == 'paese' then
self:_getCategoryByCountry(value, gender, callback)
else
if callback then value = callback(self, value) end
local category = self:_getCategory(value, table_name)
if category then
self.tables_matched[table_name] = true
self:_addCategory(category)
end
end
end
end
return self
end
-- Formatta e aggiunge una categoria
function CategoryManager:_addCategory(category)
table.insert(self.categories, string.format('[[Categoria:%s]]', category))
return self
end
-- Categorizza un fumetto per Paese
function CategoryManager:_categorizeComicByCountry(adj)
if adj == 'giapponesi' or adj == 'cinesi' or adj == 'coreani' then
return
elseif adj == 'belgi' or adj == 'francesi' then
adj = 'franco-belgi'
end
self:_addCategory('Fumetti ' .. adj)
end
-- Categorizza una serie direct-to-video per Paese
function CategoryManager:_categorizeDTVFilmByCountry(adj)
self:_addCategory("Film d'animazione " .. adj)
if self.year then
self:_addCategory(string.format('Film %s del %s', adj, self.year))
end
end
-- Categorizza un film televisivo per Paese
function CategoryManager:_categorizeTVFilmByCountry(adj)
self:_addCategory(string.format("Film d'animazione %s per la televisione", adj))
end
-- Categorizza una serie TV per Paese
function CategoryManager:_categorizeTVSeriesByCountry(adj)
if adj ~= 'giapponesi' or self.args['paese 2'] then
self:_addCategory("Serie televisive d'animazione " .. adj)
end
end
-- Categorizza una webserie per Paese
function CategoryManager:_categorizeWebseriesByCountry(adj)
self:_addCategory('Webserie ' .. adj)
end
-- Cerca il nome di una categoria nella configurazione
function CategoryManager:_getCategory(key, table_name)
key = cfg['alias_' .. table_name] and cfg['alias_' .. table_name][key] or key
return cfg[table_name][key]
end
-- Restituisce la categoria per Paese se presente l'aggettivo adeguato
function CategoryManager:_getCategoryByCountry(value, gender, callback)
local adjective = self:_getCountryAdjective(value, gender)
if adjective then
return callback(self, adjective)
end
end
-- Ottiene l'aggettivo maschile o femminile, singolare o plurale per un dato Paese
function CategoryManager:_getCountryAdjective(country, gender)
local frame = mw.getCurrentFrame()
local success, result = pcall(frame.expandTemplate, frame, {
title = 'Template:AggNaz/' .. country,
args = { gender }
})
if success then return result end
end
-- Ricava l'anno dell'opera dalle date di inizio e fine
function CategoryManager:_getYear()
local start_date = self.args['data inizio'] or ''
local end_date = self.args['data fine'] or ''
return (start_date .. end_date):match('%d%d%d%d')
end
-- Verifica che non sia già stata aggiunta una sottocategoria
function CategoryManager:_isCategoryRedundant(table_name)
if cfg.sottocategorie[table_name] then
for _, value in ipairs(cfg.sottocategorie[table_name]) do
if self.tables_matched[value] then
return true
end
end
end
return false
end
-- Antepone il sottotipo dell'opera a una stringa
function CategoryManager:_prependSubtype(value)
return self.media.sottotipo .. value
end
-- Converte la lettera iniziale di una stringa in maiuscola
function CategoryManager:ucfirst(str)
return str:gsub('^%l', string.upper)
end
-- =============================================================================
-- Funzioni esportate
-- =============================================================================
local p = {}
-- Funzione per il template FeA, categorizza tranne che per genere
function p.categorie(frame)
if mw.title.getCurrentTitle().namespace ~= 0 then return end
return CategoryManager:new(frame:getParent().args):listCategories()
end
-- Funzione per il template FeA, elabora categorie e wikilink dei generi
function p.generi(frame)
local args = getArgs(frame, {parentOnly = not frame.args[1]})
local genre = frame.args[1]
if genre == '' then return end
local current_page = mw.title.getCurrentTitle()
local current_namespace = current_page.namespace
local category
local result = {}
for name, alias_name in pairs(cfg['alias_genere']) do
local piped = mw.ustring.match(genre, '%[%[[^%[]*|%s*' .. name .. '%s*%]%]')
local pattern = (piped and '%[%[[^%[]*|%s*' or '%[%[%s*') .. name .. '%s*%]%]%a*'
genre = mw.ustring.gsub( genre, pattern, '[[' .. alias_name .. ']]' )
end
for name, correct_name in pairs(cfg['genere']) do
if current_namespace == 0 and args.categorie ~= 'no' then
local tipo = {
['anime'] = correct_name[1],
['fumetto'] = correct_name[2],
['light novel'] = correct_name[3],
['manga'] = correct_name[1],
['manhua'] = correct_name[2],
['manhwa'] = correct_name[2]
}
tipo = tipo[args.tipo]
tipo = tipo and tipo[1] and tipo[1] .. ']][[Categoria:' .. tipo[2] or tipo
category = tipo and tipo ~= '' and '[[Categoria:' .. tipo .. ']]'
end
local piped = mw.ustring.match(genre, '%[%[[^%[]*|%s*' .. name .. '%s*%]%]')
local pattern = (piped and '%[%[[^%[]*|%s*' or '%[%[%s*') .. name .. '%s*%]%]%a*'
genre = mw.ustring.gsub( genre, pattern, correct_name[4] .. (category or '') )
-- Categoria d'errore in caso di genere senza corrispondenza
local list = mw.text.split( genre, ',' )
for i = 1, #list do
local s = replace_braces(list[i])
local p = replace_braces(correct_name[4])
if mw.ustring.match( s, p ) then
result[i] = ''
elseif result[i] == nil and current_namespace == 0 then
result[i] = '[[Categoria:' .. error_category .. ']]'
end
end
end
genre = genre .. table.concat(result)
return genre
end
-- Funzione per il manuale, restituisce la configurazione per aziende e target
function p.tabella_configurazione(frame)
local args = getArgs(frame)
local table_name = args[1]
if not(table_name) then return '' end
local reverse_alias = build_reverse_alias(table_name)
local root = mw.html.create('table')
root
:addClass('wikitable mw-collapsible mw-collapsed sortable')
:tag('tr')
:tag('th'):wikitext(table_name):done()
:tag('th'):wikitext('Alias'):done()
:tag('th'):wikitext('Categoria'):done()
for name, cat_name in pairs(cfg[table_name]) do
local name_code = table_name == 'genere' and
replace_braces(cat_name[4]) or
'[[' .. name .. ']]'
local cat_code = {}
if cat_name[1] then
for i, cat in ipairs(cat_name) do
if i > 3 then break end
cat = cat[1] and
cat[1] .. ']]<br />[[:Categoria:' .. cat[2] or cat
if cat ~= '' then
cat_code[#cat_code+1] = '[[:Categoria:' .. cat .. ']]'
end
end
cat_code = table.concat(cat_code, '<br />')
else
cat_code = '[[:Categoria:' .. cat_name .. ']]'
end
local alias_code = ' '
if reverse_alias[name] then
for i, alias in ipairs(reverse_alias[name]) do
reverse_alias[name][i] = '[[' .. alias .. ']]'
end
alias_code = table.concat(reverse_alias[name], '<br />')
end
root:tag('tr')
:tag('td'):wikitext(name_code):done()
:tag('td'):wikitext(alias_code):done()
:tag('td'):wikitext(cat_code):done()
end
return tostring(root)
end
return p