Star Wars Wiki
Star Wars Wiki

La documentation pour ce module peut être créée à Module:ArchiveAccess/doc

-- ArchiveAccess implements rendering for web page archive links.bo
local p = {}

-- NS_MAIN holds the namespace number for the Main namespace.
local NS_MAIN = 0
-- NS_FILE holds the namespace number for the File namespace.
local NS_FILE = 6
--NS_INDEX holds the namespace number for the Index namespace
local NS_INDEX = 120
local NS_MODULE = 828
local title = mw.title.getCurrentTitle()

local UPDATED_YEARLY = {'news/happy-star-wars-day', 'news/star-wars-black-friday-and-cyber-week-deals', 'news/star-wars-day-deals', 'news/star-wars-day-merchandise', 'news/star-wars-day-video-game-deals', 'news/star-wars-fathers-day-gift-guide', 'news/star-wars-halloween-shopping-guide', 'news/star-wars-holiday-gift-guide', 'news/star-wars-mothers-day-gift-guide', 'news/star-wars-reads', 'news/star-wars-valentines-day-gift-guide'}

-- isCurrentPageMainSpaceOrFile determines whether the page being parsed is a mainspace or file page.
local function isCurrentPageMainSpaceOrFile()
	return title.namespace == NS_MAIN or title.namespace == NS_FILE or title.namespace == NS_MODULE or string.find(title.fullText, 'Wookieepedia:Sources') or string.find(title.fullText, 'Wookieepedia:Appearances')
end

function string.startswith(String,Start)
   return string.sub(String,1,string.len(Start))==Start
end

function string.endswith(String, suffix)
    return string.sub(String, -#suffix) == suffix
end
	
function yes(s)
	return s ~= nil and s ~= '' and s ~= false
end

function category(c)
	return string.format('[[Category:%s|%s]]', c, title.text)
end

local DEFUNCT = {"SWArchive", "Hnn", "Blog", "WizardsCite", "Hyperspace", "CargoBay", "DHBoards", "Titan"}

local function hasValue(tab, val)
	for index, value in ipairs(tab) do
        if value == val then
            return true
        end
    end
    return false
end

-- getArchiveTrackingCategories returns tracking categories based on whether the explicit archive date used for this invocation
-- matches the implicit archive date sourced from the /Archive subpage of the template on behalf of which this module is invoked.
-- This is generally only useful if said /Archive subpage exists.
local function getArchiveTrackingCategories(explicitArchiveDate, knownArchiveDate, templateName, noLive, partialMatch, exempt)
	if not isCurrentPageMainSpaceOrFile() or title.namespace == NS_INDEX then
		return ''
	end
	
	local cx = ''
	if explicitArchiveDate and string.startswith(explicitArchiveDate, '20') and string.endswith(explicitArchiveDate, 'com') then
		cx = category('Broken archivedate values') .. '\n'
	end
	if exempt then
		return cx
	end

	-- User-provided explicit archive date parameter matches the implicit archive date from template data.
	if knownArchiveDate ~= nil and explicitArchiveDate ~= nil and knownArchiveDate:gsub('https://', ''):gsub('http://', '') == explicitArchiveDate:gsub('https://', ''):gsub('http://', '') then
		return cx .. category(templateName .. ' usages with the same archivedate value')
	elseif partialMatch and explicitArchiveDate and knownArchiveDate and string.find(knownArchiveDate, explicitArchiveDate, 1, true) then
		return cx .. category(templateName .. ' usages with the same newurl value')
	end

	-- User-provided explicit archive date parameter does not match the implicit archive date from template data.
	if knownArchiveDate then
		if noLive and not hasValue(DEFUNCT, templateName) then
			return cx .. category('Internet citations with custom archivedate and nolive flag') .. ' §'
		else
			return cx .. category(templateName .. ' usages with custom archivedate')
		end
	end
	
	return cx .. category(templateName .. ' usages with archived URLs not in Archive')
end

-- getMissingPermalinkTrackingCategory returns the tracking category to be used for the current owning template
-- if this invocation contained an archival link without a permalink timestamp.
-- It prefers to use a template-specific tracking category if one exists and a generic one otherwise.
local function getMissingPermalinkTrackingCategory(citationType, templateName, isProfile, noArchive)
	if not isCurrentPageMainSpaceOrFile() then
		return ''
	end
	
	if isProfile and (templateName == 'Instagram' or templateName == 'LinkedIn') then
		return '[[Category:Web citations with missing archival screenshots|'.. templateName..']]'
	elseif noArchive and templateName then
		return '[[Category:' .. citationType .. ' with missing permanent archival links|' .. templateName .. ']]'
	elseif templateName then
		return '[[Category:' .. citationType .. ' with missing shared permanent archival links|' .. templateName .. ']]'
	elseif noArchive then
		return category(citationType .. ' with missing permanent archival links')
	else
		return category(citationType .. ' with missing shared permanent archival links')
	end
end

local function findMatch(target, templateData)
	local match = templateData.knownArchiveDates[string.lower(target)]
	if not match and string.lower(target) ~= target then
		match = templateData.knownArchiveDates[target]
	end
	if not match and target:sub(0, 1) == '/' and #target > 1 then
		match = templateData.knownArchiveDates[string.lower(target:sub(2))]
	end
	return match
end

local function checkHttpOrHttps(target, templateData)
	local match = findMatch(target, templateData)
	if not match and string.startswith(target, 'http:') and string.endswith(target, '/') then
		match = findMatch(target:gsub("http:", "https:"):sub(0, -2), templateData)
	end
	if not match and string.startswith(target, 'http:') and not string.endswith(target, '/') then
		match = findMatch(target:gsub("http:", "https:") .. '/', templateData)
	end
	if not match and string.startswith(target, 'http:') then
		match = findMatch(target:gsub("http:", "https:"), templateData)
	end
	if not match and string.startswith(target, 'https:') then
		match = findMatch(target:gsub("https:", "http:"), templateData)
	end
	return match
end

local function determineArchiveValue(target, moduleName, simple)
	local templateData = require(moduleName)
	if simple then
		return templateData.knownArchiveDates[target]
	end
	if moduleName == "Module:ArchiveAccess/Rebelscum" then
		local _, i = target:find('rebelscum.com/')
		if i ~= nil then
			local tx = string.lower(target:sub(i + 1))
			if templateData.knownArchiveDates[tx] then
				return templateData.knownArchiveDates[tx]
			end
		end
	end
	
	local match = checkHttpOrHttps(target, templateData)
	if not match and not target:find('www.') then
		match = checkHttpOrHttps(target:gsub('://', '://www.'), templateData)
	end
	if not match and target:find('www.') then
		match = checkHttpOrHttps(target:gsub('www.', ''), templateData)
	end
	if not match and string.endswith(target, '//') then
		match = checkHttpOrHttps(target:sub(0, -3), templateData)
	end
	if not match and string.endswith(target, '/') then
		match = checkHttpOrHttps(target:sub(0, -2), templateData)
	end
	if not match and not string.endswith(target, '/') then
		match = checkHttpOrHttps(target .. '/', templateData)
	end
	return match
end

local function determineArchiveDate(target, templateName, simple)
	return determineArchiveValue(target, 'Module:ArchiveAccess/' .. templateName, simple)
end

local function determineArchiveNewUrl(target, templateName, simple)
	return determineArchiveValue(target, 'Module:NewUrlAccess/' .. templateName, false)
end

local function buildArchiveLink(archiveDate, fullUrl)
	if mw.ustring.find(archiveDate, 'http') then
		return archiveDate 
	end
	return 'https://web.archive.org/web/' .. archiveDate .. '/' .. fullUrl
end 

local function decideBoldOrItalics(known, explicit, old)
	if old then
		return ""
	elseif known == explicit then
		return "'''"
	elseif not known then
		return "''"
	else
		return ""
	end
end

local function buildArchiveUrl(archiveUrl, fullUrl, target, noArchive, useLuaSubpage, notLive, isOldVersion, isVideo, templateName, archiveLinkText, obsoleteDisclaimer, categories, suppress, exempt)
	local trackingCategories = category('Archiveurl usages with non-Wayback URLs')
	if archiveUrl:find('web%.archive%.org/web') and isCurrentPageMainSpaceOrFile() then
		trackingCategories = ''
		if fullUrl then
			local st = string.lower(fullUrl:gsub('http://', ''):gsub('https://', ''):gsub('www%.', ''):gsub('%/$', ''))
			local tx = string.lower(archiveUrl:gsub('http://', ''):gsub('https://', ''):gsub('www%.', ''))
			if tx:find(st, 1, true) then
				trackingCategories = category('Archiveurl usages instead of archivedate')
			end
		end
		if trackingCategories == '' and not suppress then
			if templateName ~= "JCFCite" and templateName ~= "LCCN" and not archiveUrl:find('cdn') then
				trackingCategories = category('Archiveurl usages with Wayback URLs')
			end
		end
	end
	local bold = ""
	if target and not noArchive and useLuaSubpage then
		local knownArchiveValue = determineArchiveDate(target, templateName, isVideo)
		if isOldVersion and knownArchiveValue:gsub('https://', ''):gsub('http://', '') == archiveUrl and not hasValue(UPDATED_YEARLY, target) then
			trackingCategories = trackingCategories .. category('Usages of oldversion with common archivedate value')
		elseif not isOldVersion and knownArchiveValue and hasValue(UPDATED_YEARLY, target) then
			trackingCategories = trackingCategories .. category('Yearly-updated webpages listed without oldversion') .. ' §'
		elseif not isOldVersion then
			bold = decideBoldOrItalics(knownArchiveValue, archiveUrl, isOldVersion)
			if bold then
				trackingCategories = trackingCategories .. getArchiveTrackingCategories(archiveUrl, knownArchiveValue, templateName, notLive, true, exempt)
			end
		end
	end
	return {disclaimer = obsoleteDisclaimer, highlight = bold, link = archiveUrl, text = archiveLinkText, categories = trackingCategories .. categories}
end

local function decideTemplateCategory(sharedSiteTemplate, templateName, target)
	if not sharedSiteTemplate then
		return templateName
	elseif sharedSiteTemplate == "Rebelscum" and target:find('rebelscum') then
		return "Rebelscum"
	elseif sharedSiteTemplate == "SW" and target:find('starwars.com') then
		return "SW"
	elseif sharedSiteTemplate == "SWYouTube" then
		return "SWYouTube"
	end
	return templateName
end

local function addScreenshotToList(ft, file, i)
	if yes(file) then
		return ft..'; [[:'..file..'|screenshot '..i..']]', i + 1
	end
	return ft, i
end

function p.addScreenshotIfExists(archive, args)
	if yes(args.archivefile) and noLive and not yes(archive.disclaimer) then
		archive.disclaimer = 'content now obsolete'
	end

	if yes(args.archivefile) and yes(args.archivefile2) and yes (args.archivefile3) then
		archive.file = 'screenshots [[:'..args.archivefile..'|1]], [[:'..args.archivefile2..'|2]], [[:'..args.archivefile3..'|3]]'
		local i = 4
		if yes(args.archivefile4) then
			archive.file = archive.file..', [[:'..args.archivefile4..'|'..i..']]'
			i = i + 1
		end
		if yes(args.archivefile5) then
			archive.file = archive.file..', [[:'..args.archivefile5..'|'..i..']]'
		end
	elseif yes(args.archivefile) and yes(args.archivefile2) then
		archive.file = '[[:'..args.archivefile..'|screenshot 1]] & [[:'..args.archivefile2..'|screenshot 2]]'
	elseif yes(args.archivefile) then
		archive.file = '[[:'..args.archivefile..'|screenshot]]'
	end
	return archive
end

-- getBackupLink generates a Wayback machine archive URL based on invocation parameters
-- with appropriate tracking categories appended.
function p.getBackupLink(args)
	local results = p.buildBackupLinkPieces(args)
	if results.file ~= nil then
		return (results.disclaimer or '') .. results.file
	end
		
	local ret = {}
	ret[#ret + 1] = results.disclaimer
	if results.highlight ~= nil then
		ret[#ret + 1] = results.highlight
	end
	if results.link ~= nil and results.text ~= nil then
		ret[#ret + 1] = '['..results.link..' '..results.text..']'
	end
	if results.highlight ~= nil then
		ret[#ret + 1] = results.highlight
	end
	if results.extra ~= nil then
		ret[#ret + 1] = results.extra
	end
	if results.warning ~= nil then
		ret[#ret + 1] = results.warning
	end
	if results.categories ~= nil then
		ret[#ret + 1] = results.categories
	end
	return table.concat(ret)
end

local function buildDisclaimer(target, hasArchive, isProfile, templateForCategory)
	local linkTitle = hasArchive and 'Module:ArchiveAccess/' or 'Template:'
	local tx = hasArchive and ' ('..target..')' or ''
	if isProfile then
		return ' [['..linkTitle..templateForCategory..'|needs confirmation]]'..tx
	else
		return ' [['..linkTitle..templateForCategory..'|<span style="color: red">\'\'\'non vérifié !\'\'\'</span>]]'..tx
	end
end

function p.buildBackupLinkPieces(args)
	return p.addScreenshotIfExists(p._buildBackupLinkPieces(args), args)
end

function p._buildBackupLinkPieces(args)
	-- if no backup exists but we have a screenshot, then exclude the 'backup not available' text and bypass the rest of the logic
	if yes(args.nobackup) and yes(args.nolive) and yes(args.archivefile) then
		return {disclaimer = 'contenu désormais obsolète'}
	elseif yes(args.nobackup) and yes(args.archivefile) then
		return {}
	-- No backup link is available, so return a customizable disclaimer
	elseif yes(args.nobackup) and yes(args.nolive) then
		return {disclaimer = (args.nobackup_text or 'contenu obsolète et lien de sauvegarde non disponible')}
	elseif yes(args.nobackup) then
		return {disclaimer = (args.nobackup_text or 'lien de sauvegarde non disponible')}
	end

	-- If the original link is now inaccessible, render a customizable disclaimer
	local obsoleteDisclaimer = ''
	if yes(args.oldversion) then
		obsoleteDisclaimer = args.nolive_text or 'content only found on older version of webpage;&#32;'
	elseif yes(args.nolive) then
		obsoleteDisclaimer = args.nolive_text or 'contenu désormais obsolète;&#32;'
	end
	
	if title.fullText:sub(0, 9) == "User:Cade" then
		obsoleteDisclaimer = ''
	end

	local target = args.target or ''
	target = target:gsub('&ndash;', '–')
	local templateName = args.template_name or ''
	local noArchive = args.no_archive or false
	local isVideo = args.is_video or false
	local archiveUrl = args.archiveurl or ''
	local fullUrl = args.full_url or ''
	local hasNewUrl = yes(args.has_new_url)
	local explicitArchiveDate = args.archivedate
	local explicitNewUrl = args.new_url

	local trackingCategories = ''
	local bold = ""
	local archiveLinkText = args.text or 'lien de sauvegarde'
	local useLuaSubpage = args.use_lua_subpage
	local sharedSiteTemplate = args.shared_site
	if args.simple then
		archiveLinkText = 'article'
		obsoleteDisclaimer = ''
	end
	
	local exempt = target == '/' or target == ''
	
	-- flag legacy oldversion=1 values, otherwise use URL/date from oldversion
	local isOldVersion = yes(args.oldversion)
	local notLive = yes(args.nolive) or isOldVersion
	local oldVersion = args.oldversion
	local ovCat = ''
	if isOldVersion then
		if oldVersion == '1' and not yes(archiveUrl) then
			ovCat = category('Legacy usages of oldversion parameter')
		elseif oldVersion:find('http') then
			if yes(archiveUrl) then
				ovCat = category('Invalid usages of oldversion parameter')
			else
				archiveUrl = oldVersion
			end
		elseif #oldVersion > 4 and string.startswith(oldVersion, '2') then
			if yes(explicitArchiveDate) then
				ovCat = category('Invalid usages of oldversion parameter')
			else
				explicitArchiveDate = oldVersion
			end
		end
	end

	-- Full Wayback URL given, so return it with appropriate tracking categories
	if yes(archiveUrl) then
		return buildArchiveUrl(archiveUrl, fullUrl, target, noArchive, useLuaSubpage, notLive, isOldVersion, isVideo, templateName, archiveLinkText, obsoleteDisclaimer, ovCat, args.suppress, exempt)
	end
	
	-- Determine the Wayback URL to use based on the archive date and full_url params, if given.
	local knownArchiveDate
	local knownNewUrl
	local templateForCategory = decideTemplateCategory(sharedSiteTemplate, templateName, target)

	-- If the 'target' parameter was forwarded to this invocation, attempt fetch known archive dates from a Lua module subpage
	if target and not noArchive then
		if useLuaSubpage then
			knownArchiveDate = determineArchiveDate(target, templateName, isVideo)
		end
		
		if sharedSiteTemplate and not knownArchiveDate then
			knownArchiveDate = determineArchiveDate(target, sharedSiteTemplate, isVideo)
			if knownArchiveDate then
				templateForCategory = sharedSiteTemplate
			end
		end
	end
	
	local newHost = ''
	if yes(args.new_host) then
		newHost = ' sur ' .. args.new_host
	end
	
	if target and hasNewUrl then
		knownNewUrl = determineArchiveNewUrl(target, templateName, isVideo)
	end
	
	if noArchive and yes(explicitNewUrl) then
		return {disclaimer = obsoleteDisclaimer, link = explicitNewUrl, text = archiveLinkText, extra = newHost, categories = ovCat}
	elseif noArchive and yes(explicitArchiveDate) then
		return {disclaimer = obsoleteDisclaimer, link = buildArchiveLink(explicitArchiveDate, fullUrl), text = archiveLinkText, categories = ovCat}
	end
	
	-- If an explicit backup host URL was given, use that.
	if yes(explicitNewUrl) then
		if isOldVersion and explicitNewUrl == knownNewUrl then
			trackingCategories = category('Usages of oldversion with common archivedate value')
		elseif not (noArchive or isOldVersion) then
			trackingCategories = getArchiveTrackingCategories(explicitNewUrl, knownNewUrl, templateForCategory, notLive, true, exempt)
			bold = decideBoldOrItalics(knownNewUrl, explicitNewUrl, false)
		end
		return {disclaimer = obsoleteDisclaimer, highlight = bold, link = explicitNewUrl, text = archiveLinkText, extra = newHost, categories = trackingCategories .. ovCat}
	end

	-- If an explicit archive date was given, use it to point to the Wayback snapshot at that given time
	-- and append appropriate tracking categories.
	if yes(explicitArchiveDate) then
		if isOldVersion and explicitArchiveDate == knownArchiveDate and not hasValue(UPDATED_YEARLY, target) then
			trackingCategories = category('Usages of oldversion with common archivedate value')
		elseif not isOldVersion and knownArchiveDate and hasValue(UPDATED_YEARLY, target) then
			trackingCategories = category('Yearly-updated webpages listed without oldversion') .. ' §'
		elseif not (noArchive or isOldVersion) then
			trackingCategories = getArchiveTrackingCategories(explicitArchiveDate, knownArchiveDate, templateForCategory, notLive, false, exempt)
			bold = decideBoldOrItalics(knownArchiveDate, explicitArchiveDate, false)
		end
		return {disclaimer = obsoleteDisclaimer, highlight = bold, link = buildArchiveLink(explicitArchiveDate, fullUrl), text = archiveLinkText, categories = trackingCategories .. ovCat}
	end
	
	-- No explicit backup host URL was given, so use the backup host URL from the archive subpage of the owning template if possible
	if knownNewUrl then
		return {disclaimer = obsoleteDisclaimer, link = knownNewUrl, text = archiveLinkText, extra = newHost}
	end
	
	if isOldVersion then
		ovCat = ovCat .. category('Usages of oldversion without explicit archivedate or archiveurl') .. ' §'
	elseif hasValue(UPDATED_YEARLY, target) then
		ovCat = ovCat .. category('Yearly-updated webpages listed without oldversion') .. ' §'
	end

	-- No explicit archive date was given, so use the archive date from the archive subpage of the owning template if possible
	if not noArchive and knownArchiveDate then
		return {disclaimer = obsoleteDisclaimer, link = buildArchiveLink(knownArchiveDate, fullUrl), text = archiveLinkText, categories = ovCat}
	end

	-- If optional param is given, then ignore tracking category
	if args.backup_optional then
		return {disclaimer = (args.nobackup_text or 'contenu obsolète et lien de sauvegarde non disponible') or obsoleteDisclaimer, categories = ovCat}
	elseif args.optional or yes(args.archivefile) then
		return {categories = ovCat}
	elseif fullUrl and fullUrl:find('tcdb.com') then
		return {}
	else
		-- Neither an explicit nor implicit archive date is available, so point to the latest Wayback snapshot with a disclaimer
		local citationType = args.citation_type or 'Pages'
		local notVerifiedDisclaimer = buildDisclaimer(target, not noArchive, args.is_profile, templateForCategory)
		local trackingCategory = getMissingPermalinkTrackingCategory(citationType, templateForCategory, args.is_profile, noArchive)
		return {disclaimer = obsoleteDisclaimer, link = 'https://web.archive.org/web/' .. fullUrl, text = archiveLinkText, warning = notVerifiedDisclaimer, categories = trackingCategory .. ovCat}
	end
end

-- render outputs a full Wayback link wrapped in a container.
function p.render(args)
	local isSmallFont = args.normal_size == nil or args.normal_size == ""
	local wrapInParentheses = args.par
	local useSpaceSeparator = args.space
	
	if not args.nobackup and not args.archivefile and not args.archiveurl and not args.archivedate and args.optional then
		return ''
	else
		local link = p.getBackupLink(args)
		if link ~= nil and link ~= "" then
			return mw.ustring.format(
				'%s%s%s%s%s',
				isSmallFont and '<small>' or '',
				wrapInParentheses and '&#32;(' or (useSpaceSeparator and '&#32;' or ''),
				link,
				wrapInParentheses and ')' or '',
				isSmallFont and '</small>' or ''
			)
		else
			return ''
		end
	end
end

local getArgs = require('Module:Arguments').getArgs
function p.main(frame)
	local args = getArgs(frame)
	return p.render(args)
end

return p