Modulo:Webarchive: differenze tra le versioni

Da Semi del Verbo, l'enciclopedia dell'influenza del Vangelo sulla cultura
(fix nolink, non mi ero accorto durante la revisione che non ha mai funzionato)
(Nessuna differenza)

Versione delle 17:06, 6 lug 2018

La documentazione per questo modulo può essere creata in Modulo:Webarchive/man

--[[ ----------------------------------
  Modulo Lua che implementa il template {{Webarchive}} e permette di
  decifrare la data negli URL di alcuni archivi anche ad altri moduli.
	]]

require('Module:No globals')
local getArgs = require('Modulo:Arguments').getArgs
local cfg = mw.loadData('Modulo:Webarchive/Configurazione')

local p = {}
local track = {}   -- array associativo per accumulare le categorie di tracciamento
local maxurls = 10 -- massimo numero di URL permessi
local encoded_date

--[[--------------------------< inlineError >-----------------------
	Errore critico. Formatta l'output completamente in rosso. Aggiunge una categoria di tracciamento.
 ]]
local function inlineError(arg, msg)
	track['Categoria:Errori di compilazione del template Webarchive'] = 1
	return '<span style="font-size:100%" class="error citation-comment">Errore di compilazione del template Webarchive: controllare il valore di <code style="color:inherit; border:inherit; padding:inherit;">&#124;' .. arg .. '=</code> (' .. msg .. ').</span>'
end

--[[--------------------------< inlineRed >-----------------------
	Formatta un frammento di testo in rosso, quale ad esempio un avvertimento da integrare nell'output finale.
	Aggiunge una categoria di tracciamento.
 ]]
local function inlineRed(msg, trackmsg)
	if trackmsg == 'warning' then
		track['Categoria:Errori di compilazione del template Webarchive - Avvisi'] = 1
	elseif trackmsg == 'error' then
		track['Categoria:Errori di compilazione del template Webarchive'] = 1
	end
	return '<span style="font-size:100%" class="error citation-comment">' .. msg .. '</span>'
end


--[[--------------------------< base62 >-----------------------
	Converte base-62 in base-10
	Crediti: https://de.wikipedia.org/wiki/Modul:Expr
	]]
local function base62( value )
	local r = 1
	if value:match('^%w+$') then
		local n = #value
		local k = 1
		local c
		r = 0
		for i = n, 1, -1 do
			c = value:byte( i, i )
			if c >= 48 and c <= 57 then
				c = c - 48
			elseif c >= 65 and c <= 90 then
				c = c - 55
			elseif c >= 97 and c <= 122 then
				c = c - 61
			else
				r = 1
				break
			end
			r = r + c * k
			k = k * 62
		end
	end
	return r
end

--[[--------------------------< tableLength >-----------------------
	Restituisce il numero di elementi in una tabella
	]]
local function tableLength(t)
	local count = 0
	for _ in pairs(t) do count = count + 1 end
	return count
end

--[[--------------------------< formatDate >-----------------------
	Verifica il formato di una data (dmy o iso) e se lo riconosce
	la riformatta in dmy, altrimenti restituisce il valore così com'è
	]]
local function formatDate(date)
	local y, m, d
	local try_year
	local split = mw.text.split(date, '-')
	if tableLength(split) == 3 then
		try_year = tonumber(split[1])
		if try_year and try_year > 1900 and try_year < 2200 then -- iso
			y, m, d = split[1], cfg.month_localized[tonumber(split[2])], split[3]
		end
	else
		split = mw.text.split(date, ' ')
		if tableLength(split) == 3 then
			try_year = tonumber(split[3])
			if try_year and try_year > 1900 and try_year < 2200 and
					(split[1] == '1º' or tonumber(split[1])) then -- dmy
				d, m, y = split[1], split[2], split[3]
			end
		end
	end
	d = tonumber(d) or d
	if d == 1 then d = '1º' end
	return m and mw.ustring.format('%s %s %s', d, m, y) or date
end

--[[--------------------------< formatUrlDate >-----------------------
	Controlla la data prelevata automaticamente dall'url di un archivio.
	Se è valida la formatta in dmy, altrimenti restituisce nil.
 ]]
local function formatUrlDate(y, m, d)
	local current_year = tonumber(os.date('%Y'))
	y, m, d = tonumber(y), tonumber(m), tonumber(d)
	if not y or y == '' or not m or m == '' or not d or d == '' or d > 31 or
			m < 1 or m > 12 or y < 1900 or y > current_year then
		return nil
	end
	m = cfg.month_localized[m]
	if d == 1 then d = '1º' end
	return mw.ustring.format('%s %s %s', d, m, y)
end

--[[--------------------------< decodeWebciteDate >-----------------------
	Ricava la data da un URI-path a Webcite (es. /67xHmVFWP)
	]]
local function decodeWebciteDate(path)
	local path_elements = mw.text.split(path, '/')

	-- formati URL validi che non sono base62:

	-- http://www.webcitation.org/query?id=1138911916587475
	-- http://www.webcitation.org/query?url=http..&date=2012-06-01+21:40:03
	-- http://www.webcitation.org/1138911916587475
	-- http://www.webcitation.org/cache/73e53dd1f16cf8c5da298418d2a6e452870cf50e
	-- http://www.webcitation.org/getfile.php?fileid=1c46e791d68e89e12d0c2532cc3cf629b8bc8c8e

	if not path_elements[2] or path_elements[2] == '' then
		return
	elseif mw.ustring.find(path_elements[2], 'query') or
			mw.ustring.find(path_elements[2], 'cache') or
			mw.ustring.find(path_elements[2], 'getfile') or
			tonumber(path_elements[2]) then
		encoded_date = false
		return
	end
	local snapdate = os.date('%Y %m %d', string.sub(string.format('%d', base62(path_elements[2])),1,10))
	local dt = mw.text.split(snapdate, ' ')
	local fulldate = formatUrlDate(dt[1], dt[2], dt[3])
	return fulldate
end

--[[--------------------------< snapDateToString >-----------------------
	Ricava la data da un URI-path a Wayback (es. /web/20160901010101/http://example.com ).
	Gestisce anche le non cifre come "re_", "-" e "*".
 ]]
local function decodeWaybackDate(path)
	local snapdate = string.gsub(path, '^/all/', '') -- rimuove la sequenza iniziale "/all/"
	snapdate = string.gsub(snapdate, '^/w?e?b?/?', '') -- rimuove la sequenza iniziale "/web/" o "/"
	local path_elements = mw.text.split(snapdate, '/')
	snapdate = path_elements[1]
	if snapdate == '*' then return end
	snapdate = string.gsub(snapdate, '[a-z][a-z]_[0-9]?$', '')
	snapdate = string.gsub(snapdate, '[-]', '')
	snapdate = string.gsub(snapdate, '[*]$', '')
	local fulldate
	if tonumber(snapdate) and string.len(snapdate) >= 8 then
		local year = string.sub(snapdate, 1, 4)
		local month = string.sub(snapdate, 5, 6)
		local day = string.sub(snapdate, 7, 8)
		fulldate = formatUrlDate(year, month, day)
	end
	return fulldate
end

--[[--------------------------< decodeArchiveisDate >-----------------------
	Ricava la data dall'URI-path di un link esteso ad Archive.is (es. /2016.08.28-144552/http://example.com).
	Gestisce "." e "-" nella data, rendendo 2016.08.28-144552 uguale a 20160828144552.
  ]]
local function decodeArchiveisDate(path)
    local path_elements = mw.text.split(path, '/')
    local snapdate = path_elements[2]
    if not path_elements[2] or path_elements[2] == '' then return end
    snapdate = string.gsub(snapdate, '[%.%-]', '')
    if not tonumber(snapdate) then encoded_date = false return end -- formato link breve
	local fulldate
	if string.len(snapdate) >= 8 then
		local year = string.sub(snapdate, 1, 4)
		local month = string.sub(snapdate, 5, 6)
		local day = string.sub(snapdate, 7, 8)
		fulldate = formatUrlDate(year, month, day)
	end
	return fulldate
 end

--[[--------------------------< serviceName >-----------------------
	Imposta la stringa di coda e l'ID del servizio in base al dominio
	estratto da mw.uri.new() (es. web.archive.org)
	]]
local function serviceName(url_data, nolink, notail)
	local tracking = 'Categoria:Template Webarchive - collegamenti ad altri archivi'
	local bracketopen, bracketclose = nolink and '' or '[[', nolink and '' or ']]'
	encoded_date = nil -- reset
	for _,servizio in ipairs(cfg.servizi) do
		if string.gsub(url_data.host, 'www%.', '') == servizio.signature then
			url_data.service = servizio.service or 'altri'
			if not notail and servizio.tailbracket then
				url_data.tail = mw.ustring.format(servizio.tailbracket, bracketopen, bracketclose)
			elseif not notail then
				url_data.tail = servizio.tail
			end
			tracking = servizio.tracking or tracking
			encoded_date = servizio.service and true
			break
		end
	end
	if url_data.service == nil then
		tracking = 'Categoria:Template Webarchive - collegamenti ad archivi sconosciuti'
		url_data.tail = ' su ' .. url_data.host .. ' ' .. inlineRed('URL di servizio di archiviazione sconosciuto')
	end
	track[tracking] = 1
end

--[[--------------------------< createTracking >-----------------------
	Restituisce le categorie di tracciamento inserite in track[]
	]]
local function createTracking()
	-- procede solo nel namespace 0
	local current_namespace = mw.title.getCurrentTitle().namespace
	if current_namespace ~= 0 then return '' end
	local sand = ''
	if tableLength(track) > 0 then
		for key,_ in pairs(track) do
			sand = sand .. '[[' .. key .. ']]'
		end
	end
	return sand
end

--[[--------------------------< createRendering >-----------------------
	Restituisce la resa dei dati in url_data[][]
	]]
local function createRendering(url_data)
	local sand
	local day = url_data[1].date and mw.ustring.match(url_data[1].date, '^%d+')
	local article = (day == '8' or day == '11') and 'l\'' or 'il '
	if not url_data[1].title and not url_data[1].date then
		sand = mw.ustring.format('[%s Archiviato]%s.', url_data[1].url, url_data[1].tail)
	elseif not url_data[1].title and url_data[1].date then
		sand = mw.ustring.format('[%s Archiviato] %s%s%s.', url_data[1].url, article, url_data[1].date, url_data[1].tail)
	elseif url_data[1].title and not url_data[1].date then
		sand = mw.ustring.format('[%s %s]%s.', url_data[1].url, url_data[1].title, url_data[1].tail)
	elseif url_data[1].title and url_data[1].date then
		sand = mw.ustring.format('[%s %s]%s&#32;(archiviato %s%s).', url_data[1].url, url_data[1].title, url_data[1].tail, article, url_data[1].date)
	else
		return nil
	end
	if #url_data > 1 then -- per più URL di archivio
		sand = sand .. ' Archivi aggiuntivi: '
		local archives_output = {}
		for i = 2, #url_data do
			archives_output[#archives_output+1] = mw.ustring.format('[%s %s]%s%s', url_data[i].url, url_data[i].title or url_data[i].date, url_data[i].title and (' (' .. url_data[i].date .. ')') or '', url_data[i].tail or '')
		end
		sand = sand .. table.concat(archives_output, ', ') .. '.'
	end
	return sand
end

--[[--------------------------------------------------------------------
	Entry point per chiamata diretta da un modulo.
	Riceve l'URL di un archivio e ne restituisce la data se riesce a decodificarla.
	]]
function p.decodeArchiveDate(url)
	local uri = mw.uri.new(url)
	local host, path = uri.host, uri.path
	if not url or not host or path == '' then return end
	host = string.gsub(host, 'www%.', '')
	for _, servizio in ipairs(cfg.servizi) do
		if host == servizio.signature then
			if servizio.service == 'wayback' then
				return decodeWaybackDate(path)
			elseif servizio.service == 'webcite' then
				return decodeWebciteDate(path)
			elseif servizio.service == 'archiveis' then
				return decodeArchiveisDate(path)
			end
		end
	end
	return
end

--[[--------------------------------------------------------------------
	Funzione di interfaccia principale per implementazione del
	Template:Webarchive
	]]
function p.webarchive(frame)
	-- carica in args i parametri e se sono nulli li ignora, eccetto che per il parametro nolink
	local args = getArgs(frame, {
		valueFunc = function(key, value)
			if value then
				if key == 'nolink' then
					return true
				else
					value = mw.text.trim(value)
					if value ~= '' then return value end
				end
			end
			return nil
		end
	})
	local url_data = {}
	local i = 1
	while true do
		local n = i == 1 and args.url and '' or i
		local url = i == 1 and (args.url or args.url1) or args['url' .. i]

		-- verifica eventuali errori nel parametro url
		if i == 1 and not url then
			return inlineError('url', 'vuoto') .. createTracking()
		elseif not url or i > maxurls then
			break
		elseif mw.ustring.find(url, 'https://web.http') then
			track['Categoria:Errori di compilazione del template Webarchive'] = 1
			return inlineError('url' .. n, 'https://web.http') .. createTracking()
		elseif url == 'https://web.archive.org/http:/' then
			track['Categoria:Errori di compilazione del template Webarchive'] = 1
			return inlineError('url' .. n, 'URL non valido') .. createTracking()
		end
		url_data[i] = {}
		url_data[i].url = url
		url_data[i].uri = mw.uri.new(url)
		url_data[i].host, url_data[i].path = url_data[i].uri.host, url_data[i].uri.path
		if not url_data[i].host or url_data[i].path == '' then
			return inlineError('url' .. n, 'URL non valido') .. createTracking()
		end
		serviceName(url_data[i], args.nolink, i > 1 and true)

		-- gestione delle date
		local date = i == 1 and (args.date or args.date1 or args.data or args.data1) or
				args['date' .. i] or args['data' .. i]
		if date then
			date = formatDate(date)
			local udate = url_data[i].service == 'wayback' and decodeWaybackDate(url_data[i].path) or
					url_data[i].service == 'webcite' and decodeWebciteDate(url_data[i].path) or
					url_data[i].service == 'archiveis' and decodeArchiveisDate(url_data[i].path)
			if udate and udate ~= date then
				date = date .. ' ' .. inlineRed('Data nell\'URL non combaciante: ' .. udate, 'warning')
			elseif not udate and encoded_date == true then
				date = date .. ' ' .. inlineRed('Data nell\'URL indecifrabile', 'error')
			end
		elseif url_data[i].service == 'wayback' then
			date = decodeWaybackDate(url_data[i].path)
		elseif url_data[i].service == 'webcite' then
			date = decodeWebciteDate(url_data[i].path)
		elseif url_data[i].service == 'archiveis' then
			date = decodeArchiveisDate(url_data[i].path)
		else
			date = inlineRed('Data mancante', 'warning')
		end
		if not date then
			date = encoded_date == false and inlineRed('Data mancante', 'warning') or
					inlineRed('Data nell\'URL indecifrabile', 'error')
		end
		url_data[i].date = date

		-- gestione del titolo
		url_data[i].title = i == 1 and (args.title or args.title1 or args.titolo or args.titolo1) or
				args['title' .. i] or args['titolo' .. i]

		i = i + 1
	end
	local rend = createRendering(url_data)
	if not rend then
		track['Categoria:Errori di compilazione del template Webarchive'] = 1
		rend = '<span style="font-size:100%" class="error citation-comment">Errori in [[:Template:Webarchive]]: problema sconosciuto. Si prega di segnalarlo nella [[Discussioni template:Webarchive|pagina di discussione]] del template.</span>'
	end

	return rend .. createTracking()
end

return p