<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://the-democratika.com/wiki/index.php?action=history&amp;feed=atom&amp;title=Module%3AYouTubeSubscribers</id>
	<title>Module:YouTubeSubscribers - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://the-democratika.com/wiki/index.php?action=history&amp;feed=atom&amp;title=Module%3AYouTubeSubscribers"/>
	<link rel="alternate" type="text/html" href="https://the-democratika.com/wiki/index.php?title=Module:YouTubeSubscribers&amp;action=history"/>
	<updated>2026-04-04T22:31:34Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.0</generator>
	<entry>
		<id>https://the-democratika.com/wiki/index.php?title=Module:YouTubeSubscribers&amp;diff=8989&amp;oldid=prev</id>
		<title>&gt;Tom.Reding: Improve readability of long, compound if-statements</title>
		<link rel="alternate" type="text/html" href="https://the-democratika.com/wiki/index.php?title=Module:YouTubeSubscribers&amp;diff=8989&amp;oldid=prev"/>
		<updated>2024-02-24T03:12:47Z</updated>

		<summary type="html">&lt;p&gt;Improve readability of long, compound if-statements&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;POINT_IN_TIME_PID = &amp;quot;P585&amp;quot;&lt;br /&gt;
YT_CHAN_ID_PID= &amp;quot;P2397&amp;quot;&lt;br /&gt;
SUB_COUNT_PID = &amp;quot;P8687&amp;quot;&lt;br /&gt;
&lt;br /&gt;
local p = {} &lt;br /&gt;
&lt;br /&gt;
-- taken from https://en.wikipedia.org/wiki/Module:Wd&lt;br /&gt;
function parseDate(dateStr, precision)&lt;br /&gt;
	precision = precision or &amp;quot;d&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	local i, j, index, ptr&lt;br /&gt;
	local parts = {nil, nil, nil}&lt;br /&gt;
&lt;br /&gt;
	if dateStr == nil then&lt;br /&gt;
		return parts[1], parts[2], parts[3]  -- year, month, day&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- &amp;#039;T&amp;#039; for snak values, &amp;#039;/&amp;#039; for outputs with &amp;#039;/Julian&amp;#039; attached&lt;br /&gt;
	i, j = dateStr:find(&amp;quot;[T/]&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	if i then&lt;br /&gt;
		dateStr = dateStr:sub(1, i-1)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local from = 1&lt;br /&gt;
&lt;br /&gt;
	if dateStr:sub(1,1) == &amp;quot;-&amp;quot; then&lt;br /&gt;
		-- this is a negative number, look further ahead&lt;br /&gt;
		from = 2&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	index = 1&lt;br /&gt;
	ptr = 1&lt;br /&gt;
&lt;br /&gt;
	i, j = dateStr:find(&amp;quot;-&amp;quot;, from)&lt;br /&gt;
&lt;br /&gt;
	if i then&lt;br /&gt;
		-- year&lt;br /&gt;
		parts[index] = tonumber(mw.ustring.gsub(dateStr:sub(ptr, i-1), &amp;quot;^%+(.+)$&amp;quot;, &amp;quot;%1&amp;quot;), 10)  -- remove &amp;#039;+&amp;#039; sign (explicitly give base 10 to prevent error)&lt;br /&gt;
&lt;br /&gt;
		if parts[index] == -0 then&lt;br /&gt;
			parts[index] = tonumber(&amp;quot;0&amp;quot;)  -- for some reason, &amp;#039;parts[index] = 0&amp;#039; may actually store &amp;#039;-0&amp;#039;, so parse from string instead&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		if precision == &amp;quot;y&amp;quot; then&lt;br /&gt;
			-- we&amp;#039;re done&lt;br /&gt;
			return parts[1], parts[2], parts[3]  -- year, month, day&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		index = index + 1&lt;br /&gt;
		ptr = i + 1&lt;br /&gt;
&lt;br /&gt;
		i, j = dateStr:find(&amp;quot;-&amp;quot;, ptr)&lt;br /&gt;
&lt;br /&gt;
		if i then&lt;br /&gt;
			-- month&lt;br /&gt;
			parts[index] = tonumber(dateStr:sub(ptr, i-1), 10)&lt;br /&gt;
&lt;br /&gt;
			if precision == &amp;quot;m&amp;quot; then&lt;br /&gt;
				-- we&amp;#039;re done&lt;br /&gt;
				return parts[1], parts[2], parts[3]  -- year, month, day&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			index = index + 1&lt;br /&gt;
			ptr = i + 1&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if dateStr:sub(ptr) ~= &amp;quot;&amp;quot; then&lt;br /&gt;
		-- day if we have month, month if we have year, or year&lt;br /&gt;
		parts[index] = tonumber(dateStr:sub(ptr), 10)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return parts[1], parts[2], parts[3]  -- year, month, day&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- taken from https://en.wikipedia.org/wiki/Module:Wd&lt;br /&gt;
local function datePrecedesDate(aY, aM, aD, bY, bM, bD)&lt;br /&gt;
	if aY == nil or bY == nil then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	aM = aM or 1&lt;br /&gt;
	aD = aD or 1&lt;br /&gt;
	bM = bM or 1&lt;br /&gt;
	bD = bD or 1&lt;br /&gt;
&lt;br /&gt;
	if aY &amp;lt; bY then&lt;br /&gt;
		return true&lt;br /&gt;
	elseif aY &amp;gt; bY then&lt;br /&gt;
		return false&lt;br /&gt;
	elseif aM &amp;lt; bM then&lt;br /&gt;
		return true&lt;br /&gt;
	elseif aM &amp;gt; bM then&lt;br /&gt;
		return false&lt;br /&gt;
	elseif aD &amp;lt; bD then&lt;br /&gt;
		return true&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function getClaimDate(claim)&lt;br /&gt;
	if claim[&amp;#039;qualifiers&amp;#039;] and claim[&amp;#039;qualifiers&amp;#039;][POINT_IN_TIME_PID] then &lt;br /&gt;
		local pointsInTime = claim[&amp;#039;qualifiers&amp;#039;][POINT_IN_TIME_PID]&lt;br /&gt;
		if #pointsInTime ~= 1 then&lt;br /&gt;
			-- be conservative in what we accept&lt;br /&gt;
			error(&amp;quot;Encountered a statement with zero or multiple point in time (P85) qualifiers. Please add or remove point in time information so each statement has exactly one&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
		local pointInTime = pointsInTime[1]&lt;br /&gt;
		if pointInTime and &lt;br /&gt;
		   pointInTime[&amp;#039;datavalue&amp;#039;] and &lt;br /&gt;
		   pointInTime[&amp;#039;datavalue&amp;#039;][&amp;#039;value&amp;#039;] and &lt;br /&gt;
		   pointInTime[&amp;#039;datavalue&amp;#039;][&amp;#039;value&amp;#039;][&amp;#039;time&amp;#039;] &lt;br /&gt;
		then&lt;br /&gt;
			return parseDate(pointInTime[&amp;#039;datavalue&amp;#039;][&amp;#039;value&amp;#039;][&amp;#039;time&amp;#039;])&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return nil&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- for a given list of statements find the newest one with a matching qual&lt;br /&gt;
function newestMatchingStatement(statements, qual, targetQualValue)&lt;br /&gt;
	local newestStatement = nil&lt;br /&gt;
	local newestStatementYr = nil&lt;br /&gt;
	local newestStatementMo = nil&lt;br /&gt;
	local newestStatementDay = nil&lt;br /&gt;
    for k, v in pairs(statements) do&lt;br /&gt;
    	if v[&amp;#039;rank&amp;#039;] ~= &amp;quot;deprecated&amp;quot; and v[&amp;#039;qualifiers&amp;#039;] and v[&amp;#039;qualifiers&amp;#039;][qual] then&lt;br /&gt;
    		local quals = v[&amp;#039;qualifiers&amp;#039;][qual]&lt;br /&gt;
    		-- should only have one instance of the qualifier on a statement&lt;br /&gt;
    		if #quals == 1 then&lt;br /&gt;
    			local qual = quals[1]&lt;br /&gt;
    			if qual[&amp;#039;datavalue&amp;#039;] and qual[&amp;#039;datavalue&amp;#039;][&amp;#039;value&amp;#039;] then&lt;br /&gt;
    				local qualValue = qual[&amp;#039;datavalue&amp;#039;][&amp;#039;value&amp;#039;]&lt;br /&gt;
    				if qualValue == targetQualValue then&lt;br /&gt;
	    				local targetYr, targetMo, targetDay = getClaimDate(v)&lt;br /&gt;
	    				if targetYr then&lt;br /&gt;
	    					local older = datePrecedesDate(targetYr, targetMo, targetDay, newestStatementYr, newestStatementMo, newestStatementDay)&lt;br /&gt;
	    					if older == nil or not older then&lt;br /&gt;
	    						newestStatementYr, newestStatementMo, newestStatementDay = targetYr, targetMo, targetDay&lt;br /&gt;
	    						newestStatement = v&lt;br /&gt;
	    					end&lt;br /&gt;
	    				end&lt;br /&gt;
    				end&lt;br /&gt;
    			end&lt;br /&gt;
    		end&lt;br /&gt;
    	end&lt;br /&gt;
    end&lt;br /&gt;
	return newestStatement&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- for a given property and qualifier pair returns the newest statement that matches&lt;br /&gt;
function newestMatching(e, prop, qual, targetQualValue)&lt;br /&gt;
	-- first check the best statements&lt;br /&gt;
	local statements = e:getBestStatements(prop)&lt;br /&gt;
	local newestStatement = newestMatchingStatement(statements, qual, targetQualValue)&lt;br /&gt;
	if newestStatement then&lt;br /&gt;
		return newestStatement&lt;br /&gt;
	end&lt;br /&gt;
	-- try again with all statements if nothing so far&lt;br /&gt;
	statements = e:getAllStatements(prop)&lt;br /&gt;
	newestStatement = newestMatchingStatement(statements, qual, targetQualValue)&lt;br /&gt;
	if newestStatement then&lt;br /&gt;
		return newestStatement&lt;br /&gt;
	end&lt;br /&gt;
	return nil&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function getEntity ( frame )&lt;br /&gt;
	local qid = nil&lt;br /&gt;
	if frame.args then&lt;br /&gt;
		qid = frame.args[&amp;quot;qid&amp;quot;]&lt;br /&gt;
	end&lt;br /&gt;
	if not qid then&lt;br /&gt;
		qid = mw.wikibase.getEntityIdForCurrentPage()&lt;br /&gt;
	end&lt;br /&gt;
	if not qid then&lt;br /&gt;
		local e = nil&lt;br /&gt;
		return e&lt;br /&gt;
	end&lt;br /&gt;
	local e = mw.wikibase.getEntity(qid)&lt;br /&gt;
	assert(e, &amp;quot;No such item found: &amp;quot; .. qid)&lt;br /&gt;
	return e&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- find the channel ID we are going to be getting the sub counts for&lt;br /&gt;
function getBestYtChanId(e) &lt;br /&gt;
	local chanIds = e:getBestStatements(YT_CHAN_ID_PID)&lt;br /&gt;
	if #chanIds == 1 then&lt;br /&gt;
		local chan = chanIds[1]&lt;br /&gt;
		if chan and &lt;br /&gt;
		   chan[&amp;quot;mainsnak&amp;quot;] and &lt;br /&gt;
		   chan[&amp;quot;mainsnak&amp;quot;][&amp;quot;datavalue&amp;quot;] and &lt;br /&gt;
		   chan[&amp;quot;mainsnak&amp;quot;][&amp;quot;datavalue&amp;quot;][&amp;quot;value&amp;quot;] &lt;br /&gt;
		then&lt;br /&gt;
			return chan[&amp;quot;mainsnak&amp;quot;][&amp;quot;datavalue&amp;quot;][&amp;quot;value&amp;quot;]&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return nil&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function returnError(frame, eMessage)&lt;br /&gt;
	return frame:expandTemplate{ title = &amp;#039;error&amp;#039;, args = { eMessage } } .. &amp;quot;[[Category:Pages with YouTubeSubscribers module errors]]&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- the date of the current YT subscriber count&lt;br /&gt;
function p.date( frame )&lt;br /&gt;
	local e = getEntity(frame)&lt;br /&gt;
	assert(e, &amp;quot;No qid found for page. Please make a Wikidata item for this article&amp;quot;)&lt;br /&gt;
	local chanId = getBestYtChanId(e)&lt;br /&gt;
	assert(chanId, &amp;quot;Could not find a single best YouTube channel ID for this item. Add a YouTube channel ID or set the rank of one channel ID to be preferred&amp;quot;)&lt;br /&gt;
	local s = newestMatching(e, SUB_COUNT_PID, YT_CHAN_ID_PID, chanId)&lt;br /&gt;
	if s then&lt;br /&gt;
		local yt_year, yt_month, yt_day = getClaimDate(s)&lt;br /&gt;
		if not yt_year then&lt;br /&gt;
			return nil&lt;br /&gt;
		end&lt;br /&gt;
		local dateString = yt_year .. &amp;quot;|&amp;quot;&lt;br /&gt;
		-- construct YYYY|mm|dd date string&lt;br /&gt;
		if yt_month and yt_month ~= 0 then&lt;br /&gt;
			dateString = dateString .. yt_month .. &amp;quot;|&amp;quot;&lt;br /&gt;
			-- truncate the day of month&lt;br /&gt;
			--if yt_day and yt_day ~= 0 then&lt;br /&gt;
			--	dateString = dateString .. yt_day&lt;br /&gt;
			--end&lt;br /&gt;
		end&lt;br /&gt;
		return frame:expandTemplate{title=&amp;quot;Format date&amp;quot;, args = {yt_year, yt_month, yd_day}}&lt;br /&gt;
	end&lt;br /&gt;
	error(&amp;quot;Could not find a date for YouTube subscriber information. Is there a social media followers statement (P8687) qualified with good values for P585 and P2397?&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.dateNice( frame )&lt;br /&gt;
	local status, obj = pcall(p.date, frame)&lt;br /&gt;
	if status then&lt;br /&gt;
		return obj&lt;br /&gt;
	else &lt;br /&gt;
		return returnError(frame, obj)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- the most up to date number of subscribers&lt;br /&gt;
function p.subCount( frame )&lt;br /&gt;
	local subCount = nil&lt;br /&gt;
	local e = getEntity(frame)&lt;br /&gt;
	if not e then&lt;br /&gt;
		subCount = -424&lt;br /&gt;
    	return tonumber(subCount)&lt;br /&gt;
	end&lt;br /&gt;
	local chanId = getBestYtChanId(e)&lt;br /&gt;
	if chanId then&lt;br /&gt;
		local s = newestMatching(e, SUB_COUNT_PID, YT_CHAN_ID_PID, chanId)&lt;br /&gt;
		if s and &lt;br /&gt;
		   s[&amp;quot;mainsnak&amp;quot;] and &lt;br /&gt;
		   s[&amp;#039;mainsnak&amp;#039;][&amp;quot;datavalue&amp;quot;] and &lt;br /&gt;
		   s[&amp;#039;mainsnak&amp;#039;][&amp;quot;datavalue&amp;quot;][&amp;quot;value&amp;quot;] and &lt;br /&gt;
		   s[&amp;#039;mainsnak&amp;#039;][&amp;quot;datavalue&amp;quot;][&amp;#039;value&amp;#039;][&amp;#039;amount&amp;#039;]&lt;br /&gt;
		then&lt;br /&gt;
			subCount = s[&amp;#039;mainsnak&amp;#039;][&amp;quot;datavalue&amp;quot;][&amp;#039;value&amp;#039;][&amp;#039;amount&amp;#039;]&lt;br /&gt;
		end&lt;br /&gt;
	else &lt;br /&gt;
		subCount = -404&lt;br /&gt;
	end&lt;br /&gt;
    if subCount then&lt;br /&gt;
    	return tonumber(subCount)&lt;br /&gt;
    else&lt;br /&gt;
		subCount = -412&lt;br /&gt;
    	return tonumber(subCount)&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.subCountNice( frame )&lt;br /&gt;
	local status, obj = pcall(p.subCount, frame)&lt;br /&gt;
	if status then&lt;br /&gt;
		if obj &amp;gt;= 0 then&lt;br /&gt;
			return frame:expandTemplate{title=&amp;quot;Format price&amp;quot;, args = {obj}}&lt;br /&gt;
		else&lt;br /&gt;
			return obj&lt;br /&gt;
		end&lt;br /&gt;
	else &lt;br /&gt;
		return returnError(frame, obj)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>&gt;Tom.Reding</name></author>
	</entry>
</feed>