Modulo:Webarchive/sandbox

Versione del 19 giu 2018 alle 00:41 di Sakretsu (discussione | contributi) (uniformo apici e finisco revisione)
--[[ ----------------------------------
  Modulo Lua che implementa il template {{Webarchive}} e offre alcune
  funzionalità ad altri moduli Lua per la gestione degli archivi.
	]]

require('Module:No globals')
local getArgs = require('Module:Arguments').getArgs

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

local servizi = {
	{ signature = 'archive.org', service = 'wayback',  tailbracket = ' in %sInternet Archive%s',  tracking = 'Categoria:Template Webarchive - collegamenti all\'Internet Archive' },
	{ signature = 'webcitation.org', service = 'webcite',  tailbracket = ' in %sWebCite%s',  tracking = 'Categoria:Template Webarchive - collegamenti a WebCite' },
	{ signature = 'archive.is', service = 'archiveis',  tailbracket = ' in %sArchive.is%s',  tracking = 'Categoria:Template Webarchive - collegamenti a archive.is' },
	{ signature = 'archive.fo', service = 'archiveis',  tailbracket = ' in %sArchive.is%s',  tracking = 'Categoria:Template Webarchive - collegamenti a archive.is' },
	{ signature = 'archive.today', service = 'archiveis',  tailbracket = ' in %sArchive.is%s',  tracking = 'Categoria:Template Webarchive - collegamenti a archive.is' },
	{ signature = 'archive.il', service = 'archiveis',  tailbracket = ' in %sArchive.is%s',  tracking = 'Categoria:Template Webarchive - collegamenti a archive.is' },
	{ signature = 'archive.ec', service = 'archiveis',  tailbracket = ' in %sArchive.is%s',  tracking = 'Categoria:Template Webarchive - collegamenti a archive.is' },
	{ signature = 'archive[-]it.org', service = 'archiveit',  tailbracket = ' in %sArchive-It%s' },
	{ signature = 'arquivo.pt', tail = ' nel Portuguese Web Archive' },
	{ signature = 'loc.gov', tailbracket = ' nella %sLibrary of Congress%s' },
	{ signature = 'webharvest.gov', tailbracket = ' nel %sNational Archives and Records Administration%s' },
	{ signature = 'bibalex.org', tail = ' nella [[Bibliotheca Alexandrina#Struttura e collezioni|Bibliotheca Alexandrina]]' },
	{ signature = 'collectionscanada', tail = ' nel Canadian Government Web Archive' },
	{ signature = 'haw.nsk', tail = ' nel Croatian Web Archive (HAW)' },
	{ signature = 'veebiarhiiv.digar.ee', tail = ' nell\'Estonian Web Archive' },
	{ signature = 'vefsafn.is', tailbracket = ' nella %sNational and University Library of Iceland%s]]' },
	{ signature = 'proni.gov', tailbracket = ' nel %sPublic Record Office of Northern Ireland%s' },
	{ signature = 'uni[-]lj.si', tail = ' nello Slovenian Web Archive' },
	{ signature = 'stanford.edu', tail = ' nello [[Stanford University Libraries|Stanford Web Archive]]' },
	{ signature = 'nationalarchives.gov.uk', tailbracket = ' in %sUK Government Web Archive%s' },
	{ signature = 'parliament.uk', tailbracket = ' in %sUK Parliament\'s Web Archive%s' },
	{ signature = 'webarchive.org.uk', tailbracket = ' in %sUK Web Archive%s' },
	{ signature = 'nlb.gov.sg', tail = ' in Web Archive Singapore' },
	{ signature = 'pandora.nla.gov.au', tailbracket = ' in %sPandora Archive%s' },
	{ signature = 'perma.cc', tailbracket = ' in %sPerma.cc%s' },
	{ signature = 'perma-archives.cc', tailbracket = ' in %sPerma.cc%s' },
	{ signature = 'screenshots.com', tail = ' in Screenshots' },
	{ signature = 'wikiwix.com', tail = ' in Wikiwix' },
	{ signature = 'freezepage.com', tail = ' in Freezepage' },
	{ signature = 'webcache.googleusercontent.com', tail = ' in Google Cache' }
}

local month_localized = { 'gennaio', 'febbraio', 'marzo', 'aprile', 'maggio', 'giugno',
						   'luglio', 'agosto', 'settembre', 'ottobre', 'novembre', 'dicembre'}

--[[--------------------------< 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], 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
	if tonumber(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 = 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).
	Restituisce false se l'URL è valido ma in formato senza data.
	]]
function p.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 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
		return false
	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 "*".
 ]]
function p.decodeWaybackDate(path)
	local snapdate = string.gsub(path, '^/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
	local dlen = string.len(snapdate)
	if tonumber(snapdate) and dlen >= 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_main, nolink)
	local tracking = 'Categoria:Template Webarchive - altri archivi'
	local bracketopen, bracketclose = nolink and '' or '[[',  nolink and '' or ']]'
	url_main.service = 'altri'
	for _,servizio in ipairs(servizi) do
		if mw.ustring.find(url_main.host, servizio.signature) then
			url_main.service = servizio['service'] or url_main.service
			if servizio['tailbracket'] then
				url_main.tail = mw.ustring.format(servizio.tailbracket, bracketopen, bracketclose)
			else
				url_main.tail = servizio['tail']
			end
			tracking = servizio['tracking'] or tracking
			break
		end
	end
	if url_main.tail == nil then
		url_main.tail = ' a ' .. url_main.host .. ' ' .. inlineRed('Errore: URL di servizio di archiviazione sconosciuto')
	end
	track[tracking] = 1
end

--[[--------------------------< parseExtraArgs >-----------------------
	Analizza gli argomenti numerati da 2 a maxurls, come url2..url10, date2..date10, title2..title10
	e li memorizza in una tabella.
	Per esempio: {{webarchive |url=.. |url4=.. |url7=..}}
		Tre argomenti url non in una sequenza numerica (1..4..7).
		La funzione processa solo gli argomenti numerati 2 o maggiore (in questo caso 4 e 7).
		Crea entrate in una tabella a sequenza numerica come:
	   		urlx[1].url = <valore argomento di url4>
	 		urlx[2].url = <valore argomento di url7>
	Restituisce la tabella elaborata.
 ]]
local function parseExtraArgs(args, maxurls)
	local i, index, argurl, argurl2, argdate, argtitle
	local ulx = {}
	index = 1
	for i = 2, maxurls do
		argurl = 'url' .. i
		if args[argurl] then
			ulx[index] = {}
			ulx[index]['url'] = args[argurl]
			ulx[index]['date'] = args['date' .. i] or args['data' .. i] or
					inlineRed('Data mancante', 'warning')
			ulx[index]['title'] = args['title' .. i] or args['titolo' .. i]
			index = index + 1
		end
	end
	return ulx
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 ulx[][]
	]]
local function createRendering(url_main, ulx)
	local sand
	if not url_main.title and not url_main.date then
		sand = mw.ustring.format('[%s Archiviato]%s.', url_main.url, url_main.tail)
	elseif not url_main.title and url_main.date then
		sand = mw.ustring.format('[%s Archiviato] il %s%s.', url_main.url, url_main.date, url_main.tail)
	elseif url_main.title and not url_main.date then
		sand = mw.ustring.format('[%s %s]%s.', url_main.url, url_main.title, url_main.tail)
	elseif url_main.title and url_main.date then
		sand = mw.ustring.format('[%s %s]%s&#32;(archiviato il %s).', url_main.url, url_main.title, url_main.tail, url_main.date)
	else
		return nil
	end
	if #ulx > 0 then -- per più URL di archivio
		sand = sand .. ' Archivi aggiuntivi: '
		local archives_output = {}
		for _,urlx in ipairs(ulx) do
			archives_output[#archives_output+1] = mw.ustring.format('[%s %s]', urlx['url'], urlx['title'] or formatDate(urlx['date']) )
		end
		sand = sand .. table.concat(archives_output, ', ') .. '.'
	end
	return sand
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 key == 'nolink' then
				return true
			elseif value then
				value = mw.text.trim(value)
				if value ~= '' then return value end
			end
			return nil
		end
	})

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

	-- gestione delle date
	local date = args.date or args.date1 or args.data or args.data1
	if date then
		date = formatDate(date)
		local udate = url_main.service == 'wayback' and p.decodeWaybackDate(uri1.path) or
				url_main.service == 'webcite' and p.decodeWebciteDate(uri1.path)
		if udate and udate ~= date then
			date = udate .. inlineRed('<sup>[Date non combacianti]</sup>', 'warning')
		end
	elseif url_main.service == 'wayback' then
		date = p.decodeWaybackDate(uri1.path) or inlineRed('Collegamento non valido', 'error')
	elseif url_main.service == 'webcite' then
		date = p.decodeWebciteDate(uri1.path)
		if date == false then
			date = inlineRed('Data mancante', 'warning')
		elseif not date then
			date = inlineRed('Collegamento non valido', 'error')
		end
	else
		date = inlineRed('Data mancante', 'warning')
	end
	url_main.date = date

	-- gestione del titolo
	url_main.title = args.title or args.title1 or args.titolo or args.titolo1
	local ulx = parseExtraArgs(args, maxurls)
	local rend = createRendering(url_main, ulx)
	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