モジュール:Rotten Tomatoes data

local Error = require('Module:Error')
local getArgs = require('Module:Arguments').getArgs
local p = {}
local months = {'January', 'February', 'March', 'April', 'May', 'June',
	'July', 'August', 'September', 'October', 'November', 'December'}
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 ------------------------------------------------------------
local function falsy(x)
	return x == false or x == nil or x ==  or x == 0 or type(x) == 'table' and next(x) == nil
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 parts1, parts2, parts3  -- 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
partsindex = tonumber(mw.ustring.gsub(dateStr:sub(ptr, i-1), "^\+(.+)$", "%1"), 10)  -- remove '+' sign (explicitly give base 10 to prevent error)
if partsindex == -0 then
partsindex = tonumber("0")  -- for some reason, 'partsindex = 0' may actually store '-0', so parse from string instead
end
if precision == "y" then
-- we're done
return parts1, parts2, parts3  -- year, month, day
end
index = index + 1
ptr = i + 1
i, j = dateStr:find("-", ptr)
if i then
-- month
partsindex = tonumber(dateStr:sub(ptr, i-1), 10)
if precision == "m" then
-- we're done
return parts1, parts2, parts3  -- 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
partsindex = tonumber(dateStr:sub(ptr), 10)
end
return parts1, parts2, parts3  -- year, month, day
end
-- nil dates precede all 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 false end
if aM  bM then return false end
if aD < bD then return true end
return false
end
-- format options: 'dmy', 'mdy', 'ymd', 'iso'
local function format_date(Y, M, D, format)
	format = format or 'MDY'
	local s = (D or ) .. (monthsM or ) .. (Y or )
	return mw.getCurrentFrame():expandTemplate{title='Date', args={s, format}}
end
--------------------------------------------------------------------------------
-- Returns either QID, true, or ErrorString, false
local function getentityID(args)
	local entityID = args.qid
	if falsy(entityID) then
		local title = args.title
		if falsy(title) then
			local currentID = mw.wikibase.getEntityIdForCurrentPage()
			if currentID then
				return currentID, true
			end
			return Error.error({'No Wikidata item connected to current page. Need qid or title argument.'}), 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 .. '" does not exist or has no 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 point_in_time(statement)
	if not statement.qualifiers then
		return nil, nil, nil
	end
	local pointintime = statement.qualifiersaliasesP.pointInTime
	if pointintime then
		return parseDate(pointintime1.datavalue.value.time)
	end
	return nil, nil, nil
end
local function access_date(statement)
	if statement.references then
		local accessdate = statement.references1.snaksaliasesP.retrieved
		if accessdate then
			return parseDate(accessdate1.datavalue.value.time)
		end
	end
	return nil, nil, nil
end
local function date_from_statement(statement)
	local Y, M, D = point_in_time(statement)
	if Y then
		return Y, M, D
	end
	Y, M, D = access_date(statement)
	if Y then
		return Y, M, D
	end
	if statement.rank == 'preferred' then
		return 1, 1, 3
	elseif statement.rank == 'normal' then
		return 1, 1, 2
	end
	return 1, 1, 1
end
local function reviewedby_RT(statement)
	if not statement.qualifiers then return false end
	local x = statement.qualifiersaliasesP.reviewScoreBy
	return x and x1.datavalue.value.id == aliasesQ.RottenTomatoes
end
local function score_type(statement)
	local x = nil
	if statement.qualifiers then
		x = statement.qualifiersaliasesP.determinationMethod
	end
	if x then
		x = x1.datavalue.value.id
	end
	local y = 
	if statement.mainsnak.snaktype == 'value' then
		y = statement.mainsnak.datavalue.value
	end
	if x == aliasesQ.RottenTomatoesScore then
		return 'percent'
	elseif x == aliasesQ.RottenTomatoesAverage then
		return 'average'
	elseif string.match(y, '^0-9%%$') or string.match(y, '^1-90-9%%$') or string.match(y, '^100%%$') then
		return 'percent'
	elseif string.match(y, '^0-9 percent$') or string.match(y, '^1-90-9 percent$') or string.match(y, '^100 percent$') then
		return 'percent'
	elseif string.match(y, '^%d/10$') or string.match(y, '^%d%.%d%d?/10$') then
		return 'average'
	elseif 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)
	local newest, nY, nM, nD
	for i, v in ipairs(score_statements) do
		local Y, M, D = date_from_statement(v)
		if v.rank ~= 'deprecated' and v.mainsnak.snaktype == 'value'
				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 == nil then
		return nil
	end
	return x.mainsnak.datavalue.value
end
local function get_count(entityID, args)
	local x = most_recent_score_statement(entityID)
	if x == nil then
		return nil
	end
	local y = x.qualifiersaliasesP.numberOfReviews
	if y == nil then
		return nil
	end
	local retval = string.match(y1.datavalue.value.amount, '%d+') -- dont get sign
	return retval
end
local function get_rtid(entityID, noprefix)
	local rtid_statements = mw.wikibase.getBestStatements(entityID, aliasesP.RottenTomatoesId)
	local newest, nY, nM, nD
	for i, v in ipairs(rtid_statements) do
		local Y, M, D = date_from_statement(v)
		if not datePrecedesDate(Y, M, D, nY, nM, nD) then
			nY, nM, nD = Y, M, D
			newest = v
		end
	end
	if newest == nil then
		return nil
	end
	newest = newest.mainsnak.datavalue.value
	if noprefix then
		newest = string.sub(newest, string.find(newest, '/') + 1)
	end
	return newest
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)
	return (string.gsub(x1.mainsnak.datavalue.value, '$1', rtid))
end
local function get_date(entityID, part, format)
	local z = most_recent_score_statement(entityID)
	if z == nil then
		return nil
	end
	local Y, M, D = date_from_statement(z)
	if     part == 'year' then
		return Y or 
	elseif part == 'month' then
		return monthsM or 
	elseif part == 'day' then
		return D or 
	end
	return format_date(Y, M, D, format)
end
local function get_access_date(entityID, format)
	local z = most_recent_score_statement(entityID)
	if z == nil then
		return nil
	end
	local Y, M, D = access_date(z)
	if not Y then
		Y, M, D = point_in_time(z)
	end
	return format_date(Y, M, D, format)
end
local function get_asof(entityID, args)
	local s = {}
	for key, val in pairs(args) do
		if key == 1 or key == 'qid' or key == 'title' then
			
		elseif key == 2 then
			s1 = get_date(entityID, 'year')
		elseif key == 3 then
			s2 = get_date(entityID, 'month')
		elseif key == 4 then
			s3 = get_date(entityID, 'day')
		elseif type(key) == 'number' then
			skey-1 = val
		else
			skey = val
		end
	end
	return mw.getCurrentFrame():expandTemplate{title='As of', args=s}
end
local function get_rtprose(entityID, args)
	local s = {get_score(entityID), get_score(entityID, 'average'), get_count(entityID)}
	s1 = string.match(s1, '%d+')
	s2 = string.match(s2, '%d%.%d%d?') or string.match(s2, '%d')
	s"access-date" = get_access_date(entityID, args.df)
	for key, val in pairs(args) do
		if key == 1 or key == 'qid' or key == 'title' then
			
		elseif type(key) == 'number' then
			skey + 2 = val
		else
			skey = val
		end
	end
	return mw.getCurrentFrame():expandTemplate{title='Rotten Tomatoes prose', args=s}
end
local function get_edit_icon(entityID)
	return mw.getCurrentFrame():expandTemplate{title='EditAtWikidata', args={qid=entityID, pid='P444'}}
end
local function get_table(entityID)
	return get_score(entityID) .. ' (' .. get_count(entityID) .. ' reviews)'
end
function p.main(frame)
	local args = getArgs(frame, {
		wrappers = 'Template:Rotten Tomatoes data',
		removeBlanks = false,
	})
	return p._main(args)
end
function p._main(args)
	local entityID, is_good = getentityID(args)
	if not is_good then
		return entityID -- which is the error message in this case
	end
	local command = args1
	if falsy(command) then
		return Error.error({'Missing command.'})
	end
	command = string.lower(command)
	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, args)
	elseif command == 'rtid' then
		retval = get_rtid(entityID, args.noprefix)
	elseif command == 'url' then
		retval = get_url(entityID)
	elseif command == 'date' then
		retval = get_date(entityID, 'date', args.df)
	elseif command == 'year' then
		retval = get_date(entityID, command)
	elseif command == 'month' then
		retval = get_date(entityID, command)
	elseif command == 'day' then
		retval = get_date(entityID, command)
	elseif command == 'access date' or command == 'accessdate' or command == 'access-date' then
		retval = get_access_date(entityID, args.df)
	elseif command == 'as of' or command == 'asof' then
		retval = get_asof(entityID, args)
	elseif command == 'prose' then
		retval = get_rtprose(entityID, args)
	elseif command == 'edit' then
		retval = get_edit_icon(entityID)
	elseif command == 'table' then
		retval = get_table(entityID)
	else
		return Error.error({'Invalid command.'})
	end
	if falsy(retval) then
		return Error.error({'RT data for "' .. command .. '" unavailable.'})
	end
	return retval
end
return p