Module:Cite Web: Difference between revisions

From Zelda Wiki, the Zelda encyclopedia
Jump to navigation Jump to search
mNo edit summary
No edit summary
 
Line 25: Line 25:
end
end
if archive then
if archive then
local archivedUrl = string.match(archive, "https?://twitter%.com.*$")
local archivedUrl = string.match(archive, "https?://twitter%.com.*$") or string.match(archive, "https?://x%.com.*$")
url = url or archivedUrl
url = url or archivedUrl
if url ~= archivedUrl then
if url ~= archivedUrl then
Line 36: Line 36:
local _, _, user, tweetId = string.find(url, "https?://twitter%.com/([^/]+)/status/([%d]+)/?")
local _, _, user, tweetId = string.find(url, "https?://twitter%.com/([^/]+)/status/([%d]+)/?")
if not user or not tweetId then
_, _, user, tweetId = string.find(url, "https?://x%.com/([^/]+)/status/([%d]+)/?")
end
if not user or not tweetId then
if not user or not tweetId then
warn("Invalid tweet url detected: %s", url)
warn("Invalid tweet url detected: %s", url)
Line 141: Line 144:
},
},
{
{
quote = "",
desc = "Both <code>twitter.com</code> and <code>x.com</code> URLs are supported.",
url = "",
args = {
archive = "http://web.archive.org/web/20220108160756/https://twitter.com/Dom_Auf/status/1100314210343505921",
url = "https://x.com/NintendoUK/status/1569326012156059649",
},
},
},
{
{
desc = "<code>url</code> must be a full, valid URL to a specific tweet",
desc = "<code>url</code> must be a full, valid URL to a specific tweet.",
args = {
args = {
url = "https://twitter.com/not-a-real-url",
url = "https://twitter.com/not-a-real-url",
},
},
},
{
desc = "<code>url</code> is not required if <code>archive</code> is specified as the former can be inferred from the latter.",
quote = "",
url = "",
archive = "http://web.archive.org/web/20220108160756/https://twitter.com/Dom_Auf/status/1100314210343505921",
},
},
{
{

Latest revision as of 00:23, 20 May 2024

This is the main module for the following templates:
local p = {}

local utilsArg = require("Module:UtilsArg")

local CATEGORY_NEEDING_ARCHIVAL = "Web Citations Needing Archival"
local CATEGORY_INVALID_ARGS = require("Module:Constants/category/invalidArgs")

function warn(msg, ...)
	local utilsError = require("Module:UtilsError")
	msg = string.format(msg, ...)
	utilsError.warn(msg)
end

function p.Twitter(frame)
	local args, err = utilsArg.parse(frame:getParent().args, p.Templates["Cite Twitter"])
	local categories = err and err.categoryText or ""
	
	local quote, url, archive = args.quote, args.url, args.archive
	
	if not url and not archive then
		local utilsError = require("Module:UtilsError")
		categories = categories.."[[Category:"..CATEGORY_INVALID_ARGS.."]]"
		warn("<code>url</code> or <code>archive</code> parameter is required.")
		return "[https://twitter.com Twitter]", categories
	end
	if archive then
		local archivedUrl = string.match(archive, "https?://twitter%.com.*$") or string.match(archive, "https?://x%.com.*$")
		url = url or archivedUrl
		if url ~= archivedUrl then
			warn("<code>url</code> does not match the archived url in <code>archive</code>\n:Url:&nbsp;%s\n:Archived Url:&nbsp;%s", url, archivedUrl)
			categories = categories.."[[Category:"..CATEGORY_INVALID_ARGS.."]]"
		end
	else
		categories = categories.."[[Category:"..CATEGORY_NEEDING_ARCHIVAL.."]]"
	end
	
	local _, _, user, tweetId = string.find(url, "https?://twitter%.com/([^/]+)/status/([%d]+)/?")
	if not user or not tweetId then
		_, _, user, tweetId = string.find(url, "https?://x%.com/([^/]+)/status/([%d]+)/?")
	end
	if not user or not tweetId then
		warn("Invalid tweet url detected: %s", url)
		categories = categories.."[[Category:"..CATEGORY_INVALID_ARGS.."]]"
	end
	
	local timestamp = tweetId and p.getTimestamp(tweetId)
	local autoDate = timestamp and os.date("%B %e, %Y", timestamp)
	local date = args.date or autoDate
	if autoDate and args.date and autoDate ~= args.date then
		warn("The provided date does not match the date derived from the tweet url.\n:Provided date:&nbsp;%s\n:Derived date:&nbsp;%s\n:Url:&nbsp;%s", args.date, autoDate, url)
		categories = categories.."[[Category:"..CATEGORY_INVALID_ARGS.."]]"
	end
	
	local link = user 
		and string.format("[%s @%s] on Twitter", url, user or "Twitter")
		or string.format("[%s Twitter]", url)
	
	local source = link
	if date then
		source = source..", "..date
	end
	local citation = source
	if quote then
		citation = string.format([["<i>%s</i>" — %s]], quote, source)
	end
	if archive then
		citation = citation..string.format(" ([%s Archive])", archive)
	end
	
	return citation, categories
end

-- From https://en.wikipedia.org/wiki/Module:TwitterSnowflake
function p.getTimestamp(id_str)
	local epoch = 1288834974
	local hi, lo = 0, 0
	local hiexp = 1
	local two32 = 2^32
	for c in id_str:gmatch(".") do
		lo = lo * 10 + c
		if lo >= two32 then
			hi, lo = hi * 10^hiexp + math.floor(lo / two32), lo % two32
			hiexp = 1
		else hiexp = hiexp + 1 end
	end
	hi = hi * 10^(hiexp-1)
	local timestamp = math.floor((hi * 1024 + math.floor(lo / 4194304)) / 1000) + epoch
	-- Quick fix for Tweets before epoch with Tweet IDs >=two32
	if timestamp <= epoch + 10 then
		return nil
	else
		return timestamp
	end
end

p.Templates = {
	["Cite Twitter"] = {
		purpose = "For citing Twitter posts in [[Guidelines:References|references]]. Can also be used in the <code>source</code> field of [[Template:FileInfo]].",
		categories = {"Citation Templates", "File Source Templates"},
		paramOrder = {"quote", "url", "archive", "date"},
		boilerplate = {
			tabs = {
				{
					label = "Tweets posted on or after November 4, 2010",
					params = {"quote", "url", "archive"},
				},
				{
					label = "Tweets posted before November 4, 2010",
					params = {"quote", "url", "archive", "date"},
				}
			}	
		},
		params = {
			quote = {
				type = "content",
				desc = "An excerpt from the tweet. Leave this blank for file sources.",
				trim = true,
				nilIfEmpty = true,
			},
			url = {
				type = "url",
				desc = "The URL of the Tweet to cite. Optional if <code>archive</code> is provided.",
				trim = true,
				nilIfEmpty = true,
			},
			archive = {
				type = "url",
				desc = "A link to a [https://web.archive.org web archive] of the Tweet.",
				suggested = true,
				trim = true,
				nilIfEmpty = true,
			},
			date = {
				type = "date",
				desc = "<p>Date the tweet was posted in the format <code>Month Day, Year</code>.</p><p>Omit this parameter if the tweet was posted on or after November 4, 2010. For such tweets the date can be derived from the URL.</p>",
				trim = true,
				nilIfEmpty = true,
			}
		},
		examples = {
			{
				quote = "As a mark of respect during this period of national mourning, we will not livestream tomorrow’s Nintendo Direct. It will be published as a video-on-demand on our YouTube channel at 16:00 (UK time) tomorrow.",
				url = "https://twitter.com/NintendoUK/status/1569326012156059649",
			},
			{
				desc = "Both <code>twitter.com</code> and <code>x.com</code> URLs are supported.",
				args = {
					url = "https://x.com/NintendoUK/status/1569326012156059649",
				},
			},
			{
				desc = "<code>url</code> must be a full, valid URL to a specific tweet.",
				args = {
					url = "https://twitter.com/not-a-real-url",
				},
			},
			{
				desc = "<code>url</code> is not required if <code>archive</code> is specified as the former can be inferred from the latter.",
				quote = "",
				url = "",
				archive = "http://web.archive.org/web/20220108160756/https://twitter.com/Dom_Auf/status/1100314210343505921",
			},
			{
				desc = "If both <code>url</code> and <code>archive</code> are specified, the URLs must match.",
				args = {
					url = "https://twitter.com/Dom_Auf/status/1100314210343505921",
					archive = "http://web.archive.org/web/20220108160756/https://twitter.com/Dom_Auf/status/notthesame",
				},
			},
			{
				desc = "<code>url</code> and <code>archive</code> cannot both be empty.",
				args = {quote = "", url = "", archive = ""},
			},
			{
				desc = "<code>date</code> cannot be automatically generated for Tweets posted before November 4, 2010.",
				args = {
					quote = "just setting up my twttr", 
					url = "https://twitter.com/jack/status/20",
				},
			},
		}
	},
	["Cite YouTube"] = {
		purpose = "For citing YouTube posts in [[Guidelines:References|references]]. Can also be used in the <code>source</code> field of [[Template:FileInfo]].",
		categories = {"Citation Templates", "File Source Templates"},
		paramOrder = {"quote", "title", "channel", "date", "url", "archive", "time"},
		boilerplate = {
			tabs = {
				{
					label = "YouTube Video",
					params = {"quote", "title", "channel", "date", "url", "archive"},
				},
				{
					label = "YouTube Video with Timestamp",
					params = {"quote", "title", "channel", "date", "url", "archive", "time"},
				}
			}	
		},
		params = {
			quote = {
				type = "content",
				desc = "An quote from the YouTube video. Leave this blank for file sources."
			},
			title = {
				type = "content",
				desc = "The title of the YouTube video.",
				trim = true,
				nilIfEmpty = true,
			},
			channel = {
				type = "content",
				desc = "The handle of the channel the video was uploaded to. This is found underneath the display name on their channel page; this always starts with an \"\@\" symbol."
			},
			date = {
				type = "date",
				desc = "The upload date of the YouTube video in the format <code>Month Day, Year</code>.",
				trim = true,
				nilIfEmpty = true,
			},
			url = {
				type = "url",
				desc = "The URL of the YouTube to cite. Do not include any URL parameters other than the ID of the YouTube video (i.e. <code>&t=</code>, <code>&feature=</code>, etc.)",
				trim = true,
				nilIfEmpty = true,
			},
			archive = {
				type = "url",
				desc = "The URL of a [https://web.archive.org/ Web Archive] of the YouTube video.",
				suggested = true,
				trim = true,
				nilIfEmpty = true,
			},
			time = {
				type = "string",
				desc = "The timestamp of the exact point you are referencing in the video. Travel to the point in the video, right click, and select \"Copy video URL at current time.\" Paste it somewhere where you can see it, and the number after <code>?t=</code> is what you should enter here.",
				trim = true,
				nilIfEmpty = true,
			}
		},
		examples = {
			{
				quote = "5.12.2023",
				title = "The Legend of Zelda: Tears of the Kingdom – Official Trailer #2",
				channel = "@NintendoAmerica",
				date = "Feburary 8, 2023",
				url = "https://www.youtube.com/watch?v=fYZuiFDQwQw",
				archive = "https://web.archive.org/web/20230208233422/https://www.youtube.com/watch?v=fYZuiFDQwQw",
			},
			{
				desc = "With timestamp included",
				args = {
					quote = "5.12.2023",
					title = "The Legend of Zelda: Tears of the Kingdom – Official Trailer #2",
					channel = "@NintendoAmerica",
					date = "Feburary 8, 2023",
					url = "https://www.youtube.com/watch?v=fYZuiFDQwQw",
					archive = "https://web.archive.org/web/20230208233422/https://www.youtube.com/watch?v=fYZuiFDQwQw",
					time = "128s",
					
				},
			},
			{
				desc = "With bare minimum required parameters",
				args = {
					title = "The Legend of Zelda: Tears of the Kingdom – Official Trailer #2",
					channel = "@NintendoAmerica",
					url = "https://www.youtube.com/watch?v=fYZuiFDQwQw",
					
				},
			},
			{
				desc = "<code>title</code>, <code>channel</code>, and <code>url</code> cannot be empty.",
				args = {title = "", channel = "", url = ""},
			},
		}
	}
}

return p