Module:YouTubeSubscribers
Appearance
![]() | This Lua module is used on approximately 3,400 pages and changes may be widely noticed. Test changes in the module's /sandbox or /testcases subpages, or in your own module sandbox. Consider discussing changes on the talk page before implementing them. |
![]() | This module is rated as beta, and is ready for widespread use. It is still new and should be used with some caution to ensure the results are as expected. |
![]() | This module is subject to page protection. It is a highly visible module in use by a very large number of pages, or is substituted very frequently. Because vandalism or mistakes would affect many pages, and even trivial editing might cause substantial load on the servers, it is protected from editing. |
This module fetches a YouTube channel's subscriber count from its Wikidata entity.
Usage
{{#invoke:YouTubeSubscribers|subCount|qid=Wikidata entity ID (optional)}}
{{#invoke:YouTubeSubscribers|subCountNice|qid=Wikidata entity ID (optional)}}
– formats the subscriber count
{{#invoke:YouTubeSubscribers|date|qid=Wikidata entity ID (optional)}}
{{#invoke:YouTubeSubscribers|dateNice|qid=Wikidata entity ID (optional)}}
Data retrieval problem codes
- -404 – 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
- -412 – Found an associated YouTube channel ID but could not find a most recent value for social media followers (i.e. P8687 qualified with P585 and P2397)
- -424 – No qid found for page. Please make a Wikidata item for this article
Error tracking category
POINT_IN_TIME_PID = "P585"
YT_CHAN_ID_PID= "P2397"
SUB_COUNT_PID = "P8687"
local p = {}
-- taken from https://en.wikipedia.org/wiki/Module:Wd
function parseDate(dateStr, precision)
precision = precision or "d"
local i, j, index, ptr
local parts = {nil, nil, nil}
if dateStr == nil then
return parts[1], parts[2], parts[3] -- year, month, day
end
-- 'T' for snak values, '/' for outputs with '/Julian' attached
i, j = dateStr:find("[T/]")
if i then
dateStr = dateStr:sub(1, i-1)
end
local from = 1
if dateStr:sub(1,1) == "-" then
-- this is a negative number, look further ahead
from = 2
end
index = 1
ptr = 1
i, j = dateStr:find("-", from)
if i then
-- year
parts[index] = tonumber(mw.ustring.gsub(dateStr:sub(ptr, i-1), "^\+(.+)$", "%1"), 10) -- remove '+' sign (explicitly give base 10 to prevent error)
if parts[index] == -0 then
parts[index] = tonumber("0") -- for some reason, 'parts[index] = 0' may actually store '-0', so parse from string instead
end
if precision == "y" then
-- we're done
return parts[1], parts[2], parts[3] -- year, month, day
end
index = index + 1
ptr = i + 1
i, j = dateStr:find("-", ptr)
if i then
-- month
parts[index] = tonumber(dateStr:sub(ptr, i-1), 10)
if precision == "m" then
-- we're done
return parts[1], parts[2], parts[3] -- year, month, day
end
index = index + 1
ptr = i + 1
end
end
if dateStr:sub(ptr) ~= "" then
-- day if we have month, month if we have year, or year
parts[index] = tonumber(dateStr:sub(ptr), 10)
end
return parts[1], parts[2], parts[3] -- year, month, day
end
-- taken from https://en.wikipedia.org/wiki/Module:Wd
local function datePrecedesDate(aY, aM, aD, bY, bM, bD)
if aY == nil or bY == nil then
return nil
end
aM = aM or 1
aD = aD or 1
bM = bM or 1
bD = bD or 1
if aY < bY then
return true
end
if aY > bY then
return false
end
if aM < bM then
return true
end
if aM > bM then
return false
end
if aD < bD then
return true
end
return false
end
function serializeTable(val, name, skipnewlines, depth)
skipnewlines = skipnewlines or false
depth = depth or 0
local tmp = string.rep(" ", depth)
if name then tmp = tmp .. name .. " = " end
if type(val) == "table" then
tmp = tmp .. "{" .. (not skipnewlines and "\n" or "")
for k, v in pairs(val) do
tmp = tmp .. serializeTable(v, k, skipnewlines, depth + 1) .. "," .. (not skipnewlines and "\n" or "")
end
tmp = tmp .. string.rep(" ", depth) .. "}"
elseif type(val) == "number" then
tmp = tmp .. tostring(val)
elseif type(val) == "string" then
tmp = tmp .. string.format("%q", val)
elseif type(val) == "boolean" then
tmp = tmp .. (val and "true" or "false")
else
tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\""
end
return tmp
end
function getClaimDate(claim)
if claim['qualifiers'] and claim['qualifiers'][POINT_IN_TIME_PID] then
local pointsInTime = claim['qualifiers'][POINT_IN_TIME_PID]
if #pointsInTime ~= 1 then
-- be conservative in what we accept
return nil
end
local pointInTime = pointsInTime[1]
if pointInTime and pointInTime['datavalue'] and pointInTime['datavalue']['value'] and pointInTime['datavalue']['value']['time'] then
return parseDate(pointInTime['datavalue']['value']['time'])
end
end
return nil
end
function newestMatching(claims, chanId)
--if v['qualifiers'] and v['qualifiers'][POINT_IN_TIME_PID] then
end
function getEntity ( frame )
local qid = nil
if frame.args then
qid = frame.args["qid"]
end
if not qid then
qid = mw.wikibase.getEntityIdForCurrentPage()
end
if not qid then
error("No qid found for page")
end
local e = mw.wikibase.getEntity(qid)
if not e then
error("No such item found: " .. qid)
end
return e
end
-- find the channel ID we are going to be getting the sub counts for
function getBestYtChanId(e)
local chanIds = e:getBestStatements(YT_CHAN_ID_PID)
if #chanIds == 1 then
local chan = chanIds[1]
if chan and chan["mainsnak"] and chan["mainsnak"]["datavalue"] and chan["mainsnak"]["datavalue"]["value"] then
return chan["mainsnak"]["datavalue"]["value"]
end
end
return nil
end
function p.date( frame )
local e = getEntity(frame)
local chanId = getBestYtChanId(e)
local subCounts = e:getBestStatements(SUB_COUNT_PID)
local subCount = nil
for k, v in pairs(subCounts) do
if v['qualifiers'] and v['qualifiers'][YT_CHAN_ID_PID] then
local yt_qualifier = v['qualifiers'][YT_CHAN_ID_PID]
local yt_year = nil
local yt_month = nil
local yt_day = nil
yt_year, yt_month, yt_day = getClaimDate(v)
if not yt_year then
return nil
end
local dateString = yt_year .. "|"
-- construct YYYY|mm|dd date string
if yt_month then
dateString = dateString .. yt_month .. "|"
if yt_day then
dateString = dateString .. yt_day
end
end
return "{{Format date|" ..dateString .. "}}"
end
end
end
function p.subCount( frame )
local e = getEntity(frame)
local subCount = nil
local chanId = getBestYtChanId(e)
if chanId then
local subCounts = e:getBestStatements(SUB_COUNT_PID)
for k, v in pairs(subCounts) do
if v['qualifiers'] and v['qualifiers'][YT_CHAN_ID_PID] then
local yt_qualifier = v['qualifiers'][YT_CHAN_ID_PID]
if yt_qualifier[1]['datavalue']['value'] == chanId then
subCount = v["mainsnak"]["datavalue"]["value"]["amount"]
end
end
end
end
if subCount then
return tonumber(subCount)
else
error("could not find sub count")
return "?"
end
end
return p