Module:Cite Web

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.."" warn(" or   parameter is required.") return "Twitter", categories end if archive then local archivedUrl = string.match(archive, "https?://twitter%.com.*$") url = url or archivedUrl if url ~= archivedUrl then warn(" does not match the archived url in  \n:Url: %s\n:Archived Url: %s", url, archivedUrl) categories = categories.."" end else categories = categories.."" end local _, _, user, tweetId = string.find(url, "https?://twitter%.com/([^/]+)/status/([%d]+)/?") if not user or not tweetId then warn("Invalid tweet url detected: %s", url) categories = categories.."" 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: %s\n:Derived date: %s\n:Url: %s", args.date, autoDate, url) categories = categories.."" 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("%s" — %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 references. Can also be used in the  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  is provided.", trim = true, nilIfEmpty = true, },			archive = { type = "url", desc = "A link to a web archive of the Tweet.", suggested = true, trim = true, nilIfEmpty = true, },			date = { type = "date", desc = " Date the tweet was posted in the format .  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. ", 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", },			{				quote = "", url = "", archive = "http://web.archive.org/web/20220108160756/https://twitter.com/Dom_Auf/status/1100314210343505921", },			{				desc = " must be a full, valid URL to a specific tweet", args = { url = "https://twitter.com/not-a-real-url", },			},			{				desc = "If both  and   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 = " and   cannot both be empty.", args = {quote = "", url = "", archive = ""}, },			{				desc = " 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 references. Can also be used in the  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 .", 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.,  , etc.)", trim = true, nilIfEmpty = true, },			archive = { type = "url", desc = "The URL of a 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  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 = ", , and   cannot be empty.", args = {title = "", channel = "", url = ""}, },		}	} }

return p