Jump to content
Wikipedia The Free Encyclopedia

Module:SocialMediaStats

From Wikipedia, the free encyclopedia
Module documentation[view] [edit] [history] [purge]
This module is rated as beta. It is considered ready for widespread use, but as it is still relatively new, it should be applied with some caution to ensure results are as expected.

This module fetches social media stats count from a page's Wikidata entity. That data should be automatically updated on Wikidata's side.

Usage

[edit ]

Currently there are three methods YTsubscribers, YTviews and YTdate. They can be used with a YouTube channel ID like below:

{{#invoke:SocialMediaStats|YTsubscribers|youtube_id=YouTube channel ID}}

{{#invoke:SocialMediaStats|YTviews|youtube_id=YouTube channel ID}}

{{#invoke:SocialMediaStats|YTdate|youtube_id=YouTube channel ID}}

Or used with a YouTube handle like below:

{{#invoke:SocialMediaStats|YTsubscribers|youtube_handle=YouTube handle}}

{{#invoke:SocialMediaStats|YTviews|youtube_handle=YouTube handle}}

{{#invoke:SocialMediaStats|YTdate|youtube_handle=YouTube handle}}

You can use up to three of these and you can mix and match them as in:

{{#invoke:SocialMediaStats|YTsubscribers|youtube_handle=YouTube handle|youtube_id2=YouTube channel ID}}

They can be also used with a QID like below to specify where to load the data from but you generally won't need this.

{{#invoke:SocialMediaStats|YTsubscribers|qid=Wikidata entity ID|youtube_handle=YouTube handle }}


Error tracking category

[edit ]

Category:Pages with SocialMediaStats module errors (0)

The above documentation is transcluded from Module:SocialMediaStats/doc. (edit | history)
Editors can experiment in this module's sandbox (create | mirror) and testcases (edit | run) pages.
Subpages of this module.

 -- scribunto module to get YouTube channel statistics from Wikidata for social media personality infoboxes

 require('strict')
 localautoDate=require("Module:Auto date formatter")

 localPOINT_IN_TIME_PID="P585"
 localYT_CHAN_ID_PID="P2397"
 localYT_HANDLE_PID="P11245"
 localSUB_COUNT_PID="P8687"
 localVIEW_COUNT_PID="P5436"

 localp={}

 -- taken from https://en.wikipedia.org/wiki/Module:Wd
 localfunctionparseDate(dateStr,precision)
 precision=precisionor"d"

 locali,j,index,ptr
 localparts={nil,nil,nil}

 ifdateStr==nilthen
 returnparts[1],parts[2],parts[3]-- year, month, day
 end

 -- 'T' for snak values, '/' for outputs with '/Julian' attached
 i,j=dateStr:find("[T/]")

 ifithen
 dateStr=dateStr:sub(1,i-1)
 end

 localfrom=1

 ifdateStr:sub(1,1)=="-"then
 -- this is a negative number, look further ahead
 from=2
 end

 index=1
 ptr=1

 i,j=dateStr:find("-",from)

 ifithen
 -- year
 parts[index]=tonumber(mw.ustring.gsub(dateStr:sub(ptr,i-1),"^%+(.+)$","%1"),10)-- remove '+' sign (explicitly give base 10 to prevent error)

 ifparts[index]==-0then
 parts[index]=tonumber("0")-- for some reason, 'parts[index] = 0' may actually store '-0', so parse from string instead
 end

 ifprecision=="y"then
 -- we're done
 returnparts[1],parts[2],parts[3]-- year, month, day
 end

 index=index+1
 ptr=i+1

 i,j=dateStr:find("-",ptr)

 ifithen
 -- month
 parts[index]=tonumber(dateStr:sub(ptr,i-1),10)

 ifprecision=="m"then
 -- we're done
 returnparts[1],parts[2],parts[3]-- year, month, day
 end

 index=index+1
 ptr=i+1
 end
 end

 ifdateStr:sub(ptr)~=""then
 -- day if we have month, month if we have year, or year
 parts[index]=tonumber(dateStr:sub(ptr),10)
 end

 returnparts[1],parts[2],parts[3]-- year, month, day
 end

 -- taken from https://en.wikipedia.org/wiki/Module:Wd
 localfunctiondatePrecedesDate(aY,aM,aD,bY,bM,bD)
 ifaY==nilorbY==nilthen
 returnnil
 end
 aM=aMor1
 aD=aDor1
 bM=bMor1
 bD=bDor1

 ifaY<bYthen
 returntrue
 elseifaY>bYthen
 returnfalse
 elseifaM<bMthen
 returntrue
 elseifaM>bMthen
 returnfalse
 elseifaD<bDthen
 returntrue
 end

 returnfalse
 end

 localfunctiongetClaimDate(claim)
 ifclaim['qualifiers']andclaim['qualifiers'][POINT_IN_TIME_PID]then
 localpointsInTime=claim['qualifiers'][POINT_IN_TIME_PID]
 if#pointsInTime~=1then
 -- be conservative in what we accept
 error("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")
 end
 localpointInTime=pointsInTime[1]
 ifpointInTimeand
 pointInTime['datavalue']and
 pointInTime['datavalue']['value']and
 pointInTime['datavalue']['value']['time']
 then
 returnparseDate(pointInTime['datavalue']['value']['time'])
 end
 end
 returnnil
 end

 -- for a given list of statements find the newest one with a matching qualifier
 localfunctionnewestMatchingStatement(statements,qual,targetQualValue)
 localnewestStatement=nil
 localnewestStatementYr=nil
 localnewestStatementMo=nil
 localnewestStatementDay=nil
 fork,vinpairs(statements)do
 ifv['rank']~="deprecated"andv['qualifiers']andv['qualifiers'][qual]then
 localquals=v['qualifiers'][qual]
 -- should only have one instance of the qualifier on a statement
 if#quals==1then
 localqual=quals[1]
 ifqual['datavalue']andqual['datavalue']['value']then
 localqualValue=qual['datavalue']['value']
 ifqualValue==targetQualValuethen
 localtargetYr,targetMo,targetDay=getClaimDate(v)
 iftargetYrthen
 localolder=datePrecedesDate(targetYr,targetMo,targetDay,newestStatementYr,newestStatementMo,newestStatementDay)
 ifolder==nilornotolderthen
 newestStatementYr,newestStatementMo,newestStatementDay=targetYr,targetMo,targetDay
 newestStatement=v
 end
 end
 end
 end
 end
 end
 end
 returnnewestStatement
 end

 -- for a given property and qualifier pair returns the newest statement that matches
 localfunctionnewestMatching(e,prop,qual,targetQualValue)
 -- first check the best statements
 localstatements=e:getBestStatements(prop)
 localnewestStatement=newestMatchingStatement(statements,qual,targetQualValue)
 ifnewestStatementthen
 returnnewestStatement
 end
 -- try again with all statements if nothing so far
 statements=e:getAllStatements(prop)
 newestStatement=newestMatchingStatement(statements,qual,targetQualValue)
 ifnewestStatementthen
 returnnewestStatement
 end
 returnnil
 end

 localfunctiongetValidStatements(e,prop)
 -- call getAllStatements and filter out deprecated ones
 localallStatements=e:getAllStatements(prop)
 localvalidStatements={}
 for_,statementinpairs(allStatements)do
 ifstatement['rank']~="deprecated"then
 table.insert(validStatements,statement)
 end
 end
 returnvalidStatements
 end

 localfunctiongetEntity(frame)
 localqid=nil
 ifframe.argsthen
 qid=frame.args["qid"]
 end
 ifnotqidormw.text.trim(qid)==""then
 qid=mw.wikibase.getEntityIdForCurrentPage()
 end
 ifnotqidthen
 locale=nil
 returne
 end
 locale=mw.wikibase.getEntity(qid)
 assert(e,"No such item found: "..qid)
 returne
 end

 -- Convert YouTube handle to channel ID if needed
 localfunctionnormalizeChannelId(channelParam)
 ifnotchannelParamthen
 returnnil
 end

 ifchannelParam:sub(1,1)=="@"then
 returnchannelParam:sub(2)
 else
 returnchannelParam
 end
 end

 -- Get all YouTube channel IDs from the entity
 localfunctiongetAllYtChannelIds(e)
 localchannelIds={}
 localchanIdStatements=getValidStatements(e,YT_CHAN_ID_PID)

 for_,statementinpairs(chanIdStatements)do
 ifstatementand
 statement["mainsnak"]and
 statement["mainsnak"]["datavalue"]and
 statement["mainsnak"]["datavalue"]["value"]
 then
 table.insert(channelIds,statement["mainsnak"]["datavalue"]["value"])
 end
 end

 returnchannelIds
 end

 localfunctiongetHandlesToChannelIds(e)
 -- get a mapping of handles to channel IDs and vice versa
 localmapping={}
 mapping["handles"]={}
 mapping["channelIds"]={}
 localchanIdStatements=getValidStatements(e,YT_CHAN_ID_PID)

 -- Iterate over each channel ID statement and find associated handles as qualifiers
 for_,chanStatementinpairs(chanIdStatements)do
 localchannelId=nil
 ifchanStatementand
 chanStatement["mainsnak"]and
 chanStatement["mainsnak"]["datavalue"]and
 chanStatement["mainsnak"]["datavalue"]["value"]
 then
 channelId=chanStatement["mainsnak"]["datavalue"]["value"]
 end
 -- Now look for handle qualifiers on this statement
 ifchanStatement['qualifiers']then
 localhandleQuals=chanStatement['qualifiers'][YT_HANDLE_PID]
 ifhandleQualsthen
 for_,handleQualinpairs(handleQuals)do
 ifhandleQual['datavalue']andhandleQual['datavalue']['value']then
 localhandleValue=handleQual['datavalue']['value']
 locallowerHandle=handleValue:lower()
 mapping["handles"][lowerHandle]=channelId
 mapping["channelIds"][channelId]=handleValue
 end
 end
 end
 end
 end

 localhandleStatements=getValidStatements(e,YT_HANDLE_PID)
 -- Iterate over each handle statement and find associated channel IDs as qualifiers
 for_,handleStatementinpairs(handleStatements)do
 localhandleValue=nil
 ifhandleStatementand
 handleStatement["mainsnak"]and
 handleStatement["mainsnak"]["datavalue"]and
 handleStatement["mainsnak"]["datavalue"]["value"]
 then
 handleValue=handleStatement["mainsnak"]["datavalue"]["value"]
 end
 -- Now look for channel ID qualifiers on this statement
 ifhandleStatement['qualifiers']then
 localchanIdQuals=handleStatement['qualifiers'][YT_CHAN_ID_PID]
 ifchanIdQualsthen
 for_,chanIdQualinpairs(chanIdQuals)do
 ifchanIdQual['datavalue']andchanIdQual['datavalue']['value']then
 localchannelId=chanIdQual['datavalue']['value']
 locallowerHandle=handleValue:lower()
 mapping["handles"][lowerHandle]=channelId
 mapping["channelIds"][channelId]=handleValue
 end
 end
 end
 end
 end


 returnmapping
 end


 -- Find the best matching channel ID for a given parameter
 localfunctionfindMatchingChannelId(e,channelParam)
 ifnotchannelParamthen
 returnnil
 end

 localnormalizedParam=normalizeChannelId(channelParam)
 localallChannelIds=getAllYtChannelIds(e)

 -- First try exact match
 for_,channelIdinpairs(allChannelIds)do
 ifchannelId==normalizedParamorchannelId==channelParamthen
 returnchannelId
 end
 end

 -- If no exact match then we assume it's a handle and look for it
 -- first check if it starts with UC
 localhandleToChannelId=getHandlesToChannelIds(e)
 ifhandleToChannelId["handles"][normalizedParam:lower()]then
 returnhandleToChannelId["handles"][normalizedParam:lower()]
 end

 returnnil
 end

 localfunctionreturnError(frame,eMessage)
 returnframe:expandTemplate{title='error',args={eMessage}}.."[[Category:Pages with SocialMediaStats module errors]]"
 end

 -- Get the statistic value from a statement
 localfunctiongetStatisticValue(statement)
 ifstatementand
 statement["mainsnak"]and
 statement['mainsnak']["datavalue"]and
 statement['mainsnak']["datavalue"]["value"]and
 statement['mainsnak']["datavalue"]['value']['amount']
 then
 returntonumber(statement['mainsnak']["datavalue"]['value']['amount'])
 end
 returnnil
 end

 -- Get formatted date from a statement
 localfunctiongetFormattedDate(frame,statement)
 ifstatementthen
 localyt_year,yt_month,yt_day=getClaimDate(statement)
 ifyt_yearthen
 returnautoDate._access_archive_format(frame:expandTemplate{title="Format date",args={yt_year,yt_month,yt_day}})
 end
 end
 returnnil
 end

 -- Get subscriber count for a channel
 localfunctiongetSubscriberCount(e,channelId)
 localstatement=newestMatching(e,SUB_COUNT_PID,YT_CHAN_ID_PID,channelId)
 returngetStatisticValue(statement)
 end

 -- Get view count for a channel
 localfunctiongetViewCount(e,channelId)
 localstatement=newestMatching(e,VIEW_COUNT_PID,YT_CHAN_ID_PID,channelId)
 returngetStatisticValue(statement)
 end

 -- Get the date for statistics (assumes subscriber and view counts have same date)
 localfunctiongetStatsDate(frame,e,channelId)
 localstatement=newestMatching(e,SUB_COUNT_PID,YT_CHAN_ID_PID,channelId)
 returngetFormattedDate(frame,statement)
 end

 localfunctionpassedArgs(frame)
 -- iterate over frame.args and check if any non-qid and non-number args are present
 fork,vinpairs(frame.args)do
 ifk~="qid"andtype(k)~="number"andtonumber(k)==nilthen
 returntrue
 end
 end
 returnfalse
 end


 -- Main function to get subscriber counts for up to 3 channels
 functionp.YTsubscribersInt(frame)
 ifnotpassedArgs(frame)then
 return""
 end

 locale=getEntity(frame)
 ifnotethen
 return""
 end

 localresults={}
 localsingleResult=nil
 localhasData=false

 localhandleMapping=getHandlesToChannelIds(e)

 -- Check each of the 3 possible channels
 fori=1,3do
 localhandleParam="youtube_handle"..(i==1and""ortostring(i))
 localidParam="youtube_id"..(i==1and""ortostring(i))

 localchannelParam=frame.args[handleParam]
 ifchannelParam==nilorchannelParam==""then
 channelParam=frame.args[idParam]
 end

 ifchannelParamthen
 localchannelId=findMatchingChannelId(e,channelParam)
 ifchannelIdthen
 localsubCount=getSubscriberCount(e,channelId)
 ifsubCountandsubCount>0then
 localformattedCount=frame:expandTemplate{title="Format price",args={subCount}}
 localchannelName=channelParam:gsub("^@","")

 ifhandleMapping["channelIds"][channelName]then
 channelName=handleMapping["channelIds"][channelName]
 end

 table.insert(results,formattedCount.." ("..channelName..")")
 singleResult=formattedCount
 hasData=true
 end
 end
 end
 end

 ifnothasDatathen
 localparams=""
 fork,vinpairs(frame.args)do
 params=params..k.."="..v.."; "
 end
 returnreturnError(frame,"No subscriber data found for "..e:getId().." with the provided parameters: "..params)
 end

 -- If only one result, return it directly
 if#results==1andsingleResult~=nilthen
 returnsingleResult
 end

 -- Multiple results, use {{ubl}}
 returnframe:expandTemplate{title="ubl",args=results}
 end

 -- Main function to get view counts for up to 3 channels
 functionp.YTviewsInt(frame)
 ifnotpassedArgs(frame)then
 return""
 end


 locale=getEntity(frame)
 ifnotethen
 return""
 end

 localresults={}
 localsingleResult=nil
 localhasData=false
 localhandleMapping=getHandlesToChannelIds(e)

 -- Check each of the 3 possible channels
 fori=1,3do
 localhandleParam="youtube_handle"..(i==1and""ortostring(i))
 localidParam="youtube_id"..(i==1and""ortostring(i))

 localchannelParam=frame.args[handleParam]
 ifchannelParam==nilorchannelParam==""then
 channelParam=frame.args[idParam]
 end

 ifchannelParamthen
 localchannelId=findMatchingChannelId(e,channelParam)
 ifchannelIdthen
 localviewCount=getViewCount(e,channelId)
 ifviewCountandviewCount>0then
 localformattedCount=frame:expandTemplate{title="Format price",args={viewCount}}
 localchannelName=channelParam:gsub("^@","")-- Remove @ if present for display

 ifhandleMapping["channelIds"][channelName]then
 channelName=handleMapping["channelIds"][channelName]
 end

 table.insert(results,formattedCount.." ("..channelName..")")
 singleResult=formattedCount
 hasData=true
 end
 end
 end
 end

 ifnothasDatathen
 return""
 end

 -- If only one result, return it directly
 if#results==1andsingleResult~=nilthen
 returnsingleResult
 end

 -- Multiple results, use {{ubl}}
 returnframe:expandTemplate{title="ubl",args=results}
 end

 -- Function to get the date of statistics
 functionp.YTdateInt(frame)
 locale=getEntity(frame)
 ifnotethen
 return""
 end

 -- Try to get date from any available channel
 fori=1,3do
 localhandleParam="youtube_handle"..(i==1and""ortostring(i))
 localidParam="youtube_id"..(i==1and""ortostring(i))

 localchannelParam=frame.args[handleParam]
 ifchannelParam==nilorchannelParam==""then
 channelParam=frame.args[idParam]
 end

 ifchannelParamthen
 localchannelId=findMatchingChannelId(e,channelParam)
 ifchannelIdthen
 localdate=getStatsDate(frame,e,channelId)
 ifdatethen
 returndate
 end
 end
 end
 end

 return""
 end

 -- Safe wrapper functions
 functionp.YTsubscribers(frame)
 localstatus,obj=pcall(p.YTsubscribersInt,frame)
 ifstatusthen
 returnobj
 else
 returnreturnError(frame,obj)
 end
 end

 functionp.YTviews(frame)
 localstatus,obj=pcall(p.YTviewsInt,frame)
 ifstatusthen
 returnobj
 else
 returnreturnError(frame,obj)
 end
 end

 functionp.YTdate(frame)
 localstatus,obj=pcall(p.YTdateInt,frame)
 ifstatusthen
 returnobj
 else
 returnreturnError(frame,obj)
 end
 end

 returnp


 --[[
 -- useful for debugger testing
 local f = mw.getCurrentFrame()
 local args = {}
 args['qid'] = 'Q111862397'
 args['youtube_handle'] = 'LinusTechTips'
 f['args'] = args
 p.YTsubscribersInt(f)
 p.YTviewsInt(f)

 local e = mw.wikibase.getEntity('Q57618112')
 print(mw.dumpObject(getHandlesToChannelIds(e)))
 --]]

AltStyle によって変換されたページ (->オリジナル) /