Module:Sandbox/Notsniwiast/learn

local Error = require('Module:Error')

local p = {}

local aliasesQ = { RottenTomatoes         = "Q105584", RottenTomatoesScore    = "Q108403393", RottenTomatoesAverage  = "Q108403540", Fandango               = "Q5433722", }

local aliasesP = { RottenTomatoesId       = "P1258", reviewScore            = "P444", reviewScoreBy          = "P447", numberOfReviews        = "P7887", pointInTime            = "P585", determinationMethod    = "P459", author                 = "P50", publisher              = "P123", statedIn               = "P248", language               = "P407", retrieved              = "P813", referenceURL           = "P854", archiveURL             = "P1065", title                  = "P1476", formatterURL           = "P1630", archiveDate            = "P2960", }

-- Helper functions function mw.ustring.startswith(s, pattern, plain) return mw.ustring.find(s, pattern, 1, plain) == 1 end

-- 0, nil, empty string, or empty table local function falsy(x) if x == nil or x ==  or x ==  then return true elseif type(x) == 'table' and next(x) == nil then return true end return false end

-- copied from Module:wd local 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

-- nil dates precede all other (reasonable) dates since year becomes 1 local function datePrecedesDate(aY, aM, aD, bY, bM, bD) aY, aM, aD = aY or 1, aM or 1, aD or 1 bY, bM, bD = bY or 1, bM or 1, 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

-- Returns either QID, true, or ErrorString, false local function getEntityId(frame) local entityId = frame.args.qid local title = frame.args.title if falsy(entityId) then if falsy(title) then local currentPageEntityId = mw.wikibase.getEntityIdForCurrentPage if currentPageEntityId then return currentPageEntityId, true end return Error.error({'No Wikidata item connected to current page. Need qid or title parameter.'}), false else if not mw.title.makeTitle(0, title).exists then return Error.error({'Article ' .. title .. ' does not exist.'}), false end entityId = mw.wikibase.getEntityIdForTitle(title) if not entityId then return Error.error({'Article "' .. title .. '" has no connected Wikidata item.'}), false end return entityId, true end end --At this point we should have an entityId. Check if valid. if not mw.wikibase.isValidEntityId(entityId) then return Error.error({'Invalid Q-identifier.'}), false end if not mw.wikibase.entityExists(entityId) then return Error.error({'Wikidata item ' .. entityId .. ' does not exist.'}), false end return entityId, true end

local function date_from_statement(statement) local pointintime = statement.qualifiers[aliasesP.pointInTime] if not falsy(pointintime) then pointintime = pointintime[1].datavalue.value.time return parseDate(pointintime) end if statement.references[1] then local accessdate = statement.references[1].snaks[aliasesP.retrieved] if not falsy(accessdate) then accessdate = accessdate[1].datavalue.value.time return parseDate(accessdate) end end return nil, nil, nil end

local function reviewedby_RT(statement) local x = statement.qualifiers[aliasesP.reviewScoreBy] if falsy(x) then return false end x = x[1].datavalue.value.id	if x ~= aliasesQ.RottenTomatoes then return false end return true end

-- statement should be a review score (P444) statement local function score_type(statement) local x = statement.qualifiers[aliasesP.determinationMethod] if falsy(x) then return nil end x = x[1].datavalue.value.id	if x == aliasesQ.RottenTomatoesScore then return 'percent' end if x == aliasesQ.RottenTomatoesAverage then return 'average' end local y = statement.mainsnak.datavalue.value if string.match(y, '^0%%$') or string.match(y, '^[1-9][0-9]%%$') or string.match(y, '^100%%$') then return 'percent' end if string.match(y, '^0 percent$') or string.match(y, '^[1-9][0-9] percent$') or string.match(y, '^100 percent$') then return 'percent' end if string.match(y, '^%d/10$') or string.match(y, '^%d.%d%d?/10$') then return 'average' end if string.match(y, '^%d out of 10$') or string.match(y, '^%d.%d%d? out of 10$') then return 'average' end return nil end

local function most_recent_score_statement(entityId, scoretype) scoretype = scoretype or 'percent' local score_statements = mw.wikibase.getAllStatements(entityId, aliasesP.reviewScore) if falsy(score_statements) then return nil end local newest = nil local nY, nM, nD = nil, nil, nil for i, v in ipairs(score_statements) do		local Y, M, D = date_from_statement(v) if v.rank ~= 'deprecated' and reviewedby_RT(v) and score_type(v)==scoretype and not datePrecedesDate(Y, M, D, nY, nM, nD) then nY, nM, nD = Y, M, D			newest = v		end end return newest end

local function get_score(entityId, scoretype) scoretype = scoretype or 'percent' local x = most_recent_score_statement(entityId, scoretype) if x then return x.mainsnak.datavalue.value end return nil end

local function get_count(entityId) local x = most_recent_score_statement(entityId) local y = x.qualifiers[aliasesP.numberOfReviews] if falsy(y) then return nil end return string.match(y[1].datavalue.value.amount, '%d+') -- dont get sign end

local function get_rtid(entityId) local x = mw.wikibase.getBestStatements(entityId, aliasesP.RottenTomatoesId) if falsy(x) then return nil end return x[1].mainsnak.datavalue.value end

local function get_url(entityId) local rtid = get_rtid(entityId) if rtid == nil then return nil end local x = mw.wikibase.getBestStatements(aliasesP.RottenTomatoesId, aliasesP.formatterURL) subbed, k = string.gsub(x[1].mainsnak.datavalue.value, '$1', rtid) return subbed end

local function get_date(entityId, part) local Y, M, D = date_from_statement(most_recent_score_statement(entityId)) local months = {'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'} if part == 'year' then if Y then return Y		else return '' end end if part == 'month' then if M then return months[M] else return '' end end if part == 'day' then if D then return D		else return '' end end local s = '' if Y then s = Y		if M then s = M .. ' ' .. s			if D then s = D .. ' ' .. s			end end end return s end

function p.test(frame) mw.log('starting') local entityId, is_good = getEntityId(frame) if not is_good then return entityId -- which is the error message end local command = frame.args[1] if falsy(command) then return Error.error({'Missing command.'}) end local retval = '' if command == 'score' then retval = get_score(entityId, 'percent') elseif command == 'average' then retval = get_score(entityId, 'average') elseif command == 'count' then retval = get_count(entityId) elseif command == 'rtid' then retval = get_rtid(entityId) elseif command == 'url' then retval = get_url(entityId) elseif command == 'date' or command == 'year' or command == 'month' or command == 'day' then retval = get_date(entityId, command) else return Error.error({'Invalid command.'}) end if falsy(retval) then return Error.error({'Data for ' .. command .. ' unavailable.'}) end return retval end

function p.test2(frame) end

return p