跳转到内容

模組:Selected recent additions

维基百科,自由的百科全书

local randomModule = require('Module:Random')

function cleanupArgs(argsTable)
	local cleanArgs = {}
	for key, val in pairs(argsTable) do
		if type(val) == 'string' then
			val = val:match('^%s*(.-)%s*$')
			if val ~= '' then
				cleanArgs[key] = val
			end
		else
			cleanArgs[key] = val
		end
	end
	return cleanArgs
end

function isAffirmed(val)
	if not(val) then return false end
	local affirmedWords = ' add added affirm affirmed include included on true yes y '
	return string.find(affirmedWords, ' '..string.lower(val)..' ', 1, true ) and true or false
end

function makeOutput(allItems, maxItems, more, notRandom)
	local output
	if notRandom then
		output = ''
		local itemIndex = 1
		local maxCount = math.min(#allItems, maxItems)
		while itemIndex <= maxCount do
			output = output .. allItems[itemIndex] .. '\n'
			itemIndex = itemIndex + 1
		end
	else
		local randomiseArgs = {
			['t'] = allItems,
			['limit'] = maxItems
		}
		local randomisedItems = randomModule.main('array', randomiseArgs )
		output = table.concat(randomisedItems, '\n')
	end
	if more then
		output = output .. more
	end
	return mw.text.trim(output)
end

function cleanForPatternMatching(wikitext)
	local cleaned = wikitext

	-- 处理字词转换标记 -{...}-和-{R|...}-
	cleaned = mw.ustring.gsub(cleaned, '%-%{(.-)%}%-', function(content)
		local variants = {}
		-- R|标记处理,如果存在,则移除它
		content = mw.ustring.gsub(content, '^R%s*|%s*', '') 
		for part in mw.ustring.gmatch(content, '([^;]+)') do
			part = part:match('^%s*(.-)%s*$') -- 去除首尾空格
			local actual_text = part
			-- 移除语言代码前缀,如 zh-cn:
			local colon_pos = mw.ustring.find(part, ':', 1, true)
			if colon_pos then
				actual_text = mw.ustring.sub(part, colon_pos + 1)
				actual_text = actual_text:match('^%s*(.-)%s*$') -- 再次去除首尾空格
			end
			if actual_text ~= '' then
				table.insert(variants, actual_text)
			end
		end
		return table.concat(variants, ' ') -- 用空格连接所有变体
	end)

	-- 移除维基链接的方括号,保留链接文本
	cleaned = mw.ustring.gsub(cleaned, "%[%[(.-)%]%]","%1")
	-- 移除管道符(原用于管道链接),替换为空格
	cleaned = mw.ustring.gsub(cleaned, "%|"," ")
	-- 移除外部链接的方括号
	cleaned = mw.ustring.gsub(cleaned, "%[.-%]"," ")
	return cleaned
end

function makeCollapsed(outerText, innerText)
	return "{{Hidden begin | titlestyle = font-weight:normal | title = " .. outerText .. "}}" .. innerText .. "{{Hidden end}}"
end

-- 获取指定子页面(按月份)的新条目推荐。返回一个列表项的表。
function getRecentAdditions(subpage, keepPatterns, skipPatterns, showWikitext)
	-- 中文维基百科新条目推荐存档路径
	local title = mw.title.new('Wikipedia:新条目推荐/存档' .. subpage)
	if not title or not title.exists then -- 检查页面是否存在
		return {}
	end
	local raw = title:getContent()
	if not raw then return {} end -- 如果页面内容为空,也返回空表

	-- 中文维基百科DYK项目通常以 '*' 开头
	local itemPattern = '%*%s?[^\n]*' -- 匹配以 '*' 开头直到行尾的任何内容
	local items = {}
	for item in mw.ustring.gmatch(raw, itemPattern) do
		local keep = false
		local skip = false
		-- 确保它是一个列表项(虽然itemPattern应该已经保证了这一点)
		if mw.ustring.sub(item, 1, 1) == '*' then
			local text = cleanForPatternMatching(item) -- 使用更新的清理函数
			for _, keepPatt in ipairs(keepPatterns) do -- 使用ipairs以保证顺序(虽然此处顺序不重要)
				if not keep and mw.ustring.find(text, keepPatt, 1, false) then -- 使用mw.ustring.find进行不区分大小写的模式匹配
					keep = true
				end
			end
			if #skipPatterns > 0 then
				for _, skipPatt in ipairs(skipPatterns) do
					if not skip and mw.ustring.find(text, skipPatt, 1, false) then
						skip = true			
					end
				end
			end
		end
		if keep and not skip then
			local cleanItem = item -- 原始英文模块中 (pictured) 和 (illustrated) 的清理在此处不需要
			if showWikitext then
				-- 移除HTML注释
				cleanItem = mw.ustring.gsub(cleanItem, "%<%!%-%-(.-)%-%-%>", "")
				local itemWikitext = "<pre>" .. mw.text.nowiki( cleanItem ) .. "</pre>"
				cleanItem = makeCollapsed(cleanItem, itemWikitext)
			end
			table.insert(items, cleanItem)
		end
	end
	return items
end

-- 获取过去数月的新条目推荐项
function getItems(maxMonths, patterns, skipPatterns, showWikitext)
	local allItems = {}
	local lang = mw.language.new('zh') -- 设置语言为中文
	local currentYear  = tonumber(lang:formatDate('Y', 'now'))
	local currentMonth = tonumber(lang:formatDate('n', 'now')) -- 'n' 为不带前导零的月份

	local monthsAgo = 0
	while monthsAgo < maxMonths do
		local subpage
		local yearForSubpage, monthForSubpage
		
		-- 计算目标年月
		-- 使用规范月份数进行计算,避免复杂的跨年逻辑
		local canonicalCurrentMonthIndex = (currentYear - 1) * 12 + currentMonth
		local canonicalTargetMonthIndex = canonicalCurrentMonthIndex - monthsAgo
		
		yearForSubpage = math.floor((canonicalTargetMonthIndex - 1) / 12) + 1
		monthForSubpage = (canonicalTargetMonthIndex - 1) % 12 + 1
		
		-- 构建子页面路径,格式如 /2023年5月
		subpage = '/' .. yearForSubpage .. '年' .. monthForSubpage .. '月'
		
		local monthlyItems = getRecentAdditions(subpage, patterns, skipPatterns, showWikitext)
		for i, item in ipairs(monthlyItems) do
			table.insert(allItems, item)
		end
		monthsAgo = monthsAgo + 1
	end
	return allItems
end

function getPatterns(args, prefix)
	local patterns = {}
	local ii = 1
	while args[prefix and prefix..ii or ii] do
		patterns[ii] = args[prefix and prefix..ii or ii]
		ii = ii + 1
	end
	return patterns
end

local p = {}

p.main = function(frame)
	local parent = frame:getParent()
	local parentArgs = parent.args
	local args = cleanupArgs(parentArgs)

	if args['not'] and not args['not1'] then
		args['not1'] = args['not']
	end
	
	local patterns = getPatterns(args)
	if #patterns < 1 then
		return error("错误:未设置搜索模式(必须至少提供一个匿名参数或参数1)。")
	end

	local skipPatterns = getPatterns(args, 'not')

	local months = tonumber(args.months) or 30
	
	local showWikitext = isAffirmed(args.wikitext)

	local allItems = getItems(months, patterns, skipPatterns, showWikitext)
	if #allItems < 1 then
		return args.header and '' or args.none or '没有符合条件的新条目推荐。'
	end

	local maxItems = tonumber(args.max) or 6

	local more = args.more
	if isAffirmed(args.more) then
		more = "\n'''[[Wikipedia:新条目推荐|更多新条目推荐…]]'''"
	end

	local nonRandom = isAffirmed(args.latest)

	local output = makeOutput(allItems, maxItems, more, nonRandom)
	if args.header then
		output = args.header .. '\n' .. output .. '\n' .. (args.footer or '{{Box-footer}}')
	end
	local needsExpansion = mw.ustring.find(output, '{{', 1, true)	
	if needsExpansion then
		return frame:preprocess(output)
	else 
		return output
	end
end

return p