モジュール:サンドボックス/にょきにょき/Scheduled

local DEFAULT_TZ_OFFSET = 9 --JST
function parseTextList(text)
	local list = mw.text.split(mw.text.trim(text), '\n')
	return list
end
function CJD(timestamp, tzOffset)
	local jd = timestamp / 86400 + 2440587.5
	return jd + 0.5 + tzOffset / 24
end
function makeTableContent(builder, sList)
	builder = builder:tag('tr')
	for i=1, #sList do
		builder:tag('td')
			:wikitext(sListi)
			:done()
	end
	builder = builder:done()
	return builder
end
local rotation = {}
--
rotation.dailyIndex() - periodで指定した周期のインデックスを日替わりで返す
（optionのパラメータは下記 Scheduled.daily() を参照）
rotation.dailyIndex = function(period, option)
	local adjuster = tonumber(option.adjuster or 0)
	local tzOffset = tonumber(option.tzOffset or DEFAULT_TZ_OFFSET)
	local step = tonumber(option.step or 1)
	local span = tonumber(option.span or 1)
	local spanAdjuster = tonumber(option.spanAdjuster or 0)
	local timestamp = tonumber(option.timestamp or os.time())
	local dateValue = CJD(timestamp, tzOffset) + spanAdjuster
	return (math.floor(dateValue / span) * step + adjuster) % period + 1
end
rotation.estimateAdjuster = function(period, option, index)
	local adjuster = tonumber(option.adjuster or 0)
	local tzOffset = tonumber(option.tzOffset or DEFAULT_TZ_OFFSET)
	local step = tonumber(option.step or 1)
	local span = tonumber(option.span or 1)
	local spanAdjuster = tonumber(option.spanAdjuster or 0)
	local timestamp = tonumber(option.timestamp or os.time())
	local dateValue = CJD(timestamp, tzOffset) + spanAdjuster
	local diff = index - ((math.floor(dateValue / span) * step + adjuster) % period + 1)
	return (diff + adjuster + period) % period
end
-----------
--interface
local p = {}
--
Scheduled.daily() - リストから日替わりで候補を取得する
必須パラメータ:
	data: 改行区切りの候補リスト
オプション:
	adjuster: 任意の候補を表示させるための調整値。初期値: 0
	tzOffset: 日付が切り替わるタイムゾーンのオフセット値。初期値: 9 (JST)
	step: 1回の更新で候補リストをいくつ進めるか。step=2とすると1,3,5番目...の順。初期値: 1
	span: 何日単位で結果を更新するか。初期値: 1
	spanAdjuster: spanに2以上を指定する場合、任意のタイミングで更新させるための調整値。初期値: 0
	timestamp: UNIX時刻。特定の日時での実行結果を見たいときに指定。初期値: 現在時刻
p.daily = function(frame)
	local data = frame.args.data
	if not data then error('引数 "data" は必須です。') end
	local dataList = parseTextList(data)
	local option = frame.args
	local index = rotation.dailyIndex(#dataList, option)
	local caller = mw.title.getCurrentTitle().baseText
	if caller == '良質スケジュール' or caller == '秀逸スケジュール' then
		local ret = "現在メインページに掲載されている記事は " .. dataListindex .. " です。"
		ret = ret .. '※もし表示が異なっている場合は' .. tostring(mw.uri.fullUrl(mw.title.getCurrentTitle().prefixedText, 'action=purge')) .. ' こちらをクリックしてキャッシュのクリアを試してください。'
		ret = ret .. 'データを追加する際に変更するAdjusterの値です。念のため必ずプレビューを行って正しい値であるか確認してください。'
		local builder = mw.html.create('table')
		builder:addClass('wikitable')
			:css('text-align', 'center')
		builder = makeTableContent(builder, {'追加データ数', 'Adjuster'})
		for i=1, 5 do
			builder = makeTableContent(builder, {i, rotation.estimateAdjuster(#dataList + i, option, index)})
		end
		ret = ret .. tostring(builder)
		ret = ret .. "リストから除去する場合は、除去する対象がリストにおいて" .. dataListindex .. "よりも上にある場合は、adjusterに" .. rotation.estimateAdjuster(#dataList - 1, option, index-1) .. 'を、'
		ret = ret .. '下にある場合はadjusterに' .. rotation.estimateAdjuster(#dataList - 1, option, index) .. 'を入力してください。'
		return ret
	else
		return dataListindex
	end
end
return p