跳转到内容

模組:PJ:VG/PORTAL/TODAY

维基百科,自由的百科全书
require("strict")

local getArgs = require("Module:Arguments").getArgs

local p = {}

local DEFAULT_SOURCE_PAGE = "Portal:电子游戏/内容展示/今日条目/data"
local EXCERPT_TEMPLATE = "Transclude lead excerpt"

local cache = {}

local function makeInvokeFunc(funcName)
    return function(frame)
        local args = getArgs(frame)
        return p[funcName](args)
    end
end

local function trim(value)
    return mw.text.trim(value or "")
end

local function getSourcePage(args)
    local sourcePage = trim(args.source)
    if sourcePage ~= "" then
        return sourcePage
    end
    return DEFAULT_SOURCE_PAGE
end

local function setArg(target, key, value)
    if trim(value) ~= "" then
        target[key] = value
    end
end

local function normalizeDateKey(value)
    value = trim(value)
    if value == "" then
        return nil
    end

    if value:match("^%d%d%d%d$") then
        return value
    end

    if value:match("^%d+月%d+日$") then
        local month, day = value:match("^(%d+)月(%d+)日$")
        return string.format("%02d%02d", tonumber(month), tonumber(day))
    end

    local month, day = value:match("^(%d+)%s*[-/.]%s*(%d+)$")
    if month and day then
        return string.format("%02d%02d", tonumber(month), tonumber(day))
    end

    return nil
end

local function getDateKey(args)
    if trim(args.date) ~= "" then
        return normalizeDateKey(args.date) or trim(args.date)
    end

    local month = trim(args.month or args.m)
    local day = trim(args.day or args.d)
    if month ~= "" and day ~= "" then
        return string.format("%02d%02d", tonumber(month), tonumber(day))
    end

    return mw.getContentLanguage():formatDate("md", nil, true)
end

local function extractPageName(line)
    line = trim(line)
    if line == "" then
        return nil
    end

    local linkTarget = line:match("%[%[([^%]]+)%]%]")
    if linkTarget then
        line = linkTarget
    end

    line = line:gsub("|.*$", "")
    line = line:gsub("#.*$", "")
    line = trim(line)

    if line == "" then
        return nil
    end

    return line
end

local function parseSource(sourcePage)
    if cache[sourcePage] then
        return cache[sourcePage]
    end

    local title = mw.title.new(sourcePage)
    if not title then
        return nil, "Cannot open source page: " .. sourcePage
    end

    local content = title:getContent()
    if not content or content == "" then
        return nil, "Source page is empty: " .. sourcePage
    end

    local byDate = {}
    local allPages = {}
    local currentDateKey = nil

    for line in mw.text.gsplit(content, "\n", true) do
        local caseKey = trim(line:match("^|%s*(%d%d%d%d)%s*=") or "")
        if caseKey ~= "" then
            currentDateKey = caseKey
            if not byDate[currentDateKey] then
                byDate[currentDateKey] = {}
            end
        else
            local bullet = trim(line:match("^%*+%s*(.-)%s*$") or "")
            if currentDateKey and bullet ~= "" then
                local pageName = extractPageName(bullet)
                if pageName then
                    table.insert(byDate[currentDateKey], pageName)
                    table.insert(allPages, pageName)
                end
            end
        end
    end

    cache[sourcePage] = {
        byDate = byDate,
        allPages = allPages
    }

    return cache[sourcePage]
end

local function uniquePages(pages)
    local seen = {}
    local result = {}

    for _, pageName in ipairs(pages) do
        if not seen[pageName] then
            seen[pageName] = true
            table.insert(result, pageName)
        end
    end

    return result
end

local function sortDateKeys(byDate)
    local keys = {}

    for dateKey in pairs(byDate) do
        table.insert(keys, dateKey)
    end

    table.sort(keys, function(a, b)
        return tonumber(a) < tonumber(b)
    end)

    return keys
end

local function renderError(message)
    return '<span class="error">' .. message .. "</span>"
end

local function renderExcerpt(args, pageName)
    local templateArgs = {
        [1] = pageName
    }

    setArg(templateArgs, "paragraphs", args.paragraphs)
    setArg(templateArgs, "files", args.files)
    setArg(templateArgs, "fileargs", args.fileargs)
    setArg(templateArgs, "errors", args.errors)

    return mw.getCurrentFrame():expandTemplate {
        title = EXCERPT_TEMPLATE,
        args = templateArgs
    }
end

local function pickStablePage(pages, seedText)
    if not pages or #pages == 0 then
        return nil
    end

    local seed = tostring(seedText or "")
    local hashValue = 0

    for i = 1, #seed do
        hashValue = hashValue + seed:byte(i) * i
    end

    local index = (hashValue % #pages) + 1
    return pages[index]
end

p.main = makeInvokeFunc("_main")
p.listAll = makeInvokeFunc("_listAll")
p.listAllByDates = makeInvokeFunc("_listAllByDates")
p.forDate = makeInvokeFunc("_forDate")
p.randomForDate = makeInvokeFunc("_randomForDate")
p.showDate = makeInvokeFunc("_showDate")

function p._main(args)
    return p._randomForDate(args)
end

function p._listAll(args)
    local sourcePage = getSourcePage(args)
    local data, errorMessage = parseSource(sourcePage)
    if not data then
        return renderError(errorMessage)
    end

    local pages = data.allPages
    if trim(args.unique) ~= "no" then
        pages = uniquePages(pages)
    end

    if #pages == 0 then
        return renderError("No pages found")
    end

    local separator = args.sep or "、"
    local output = {}

    for _, pageName in ipairs(pages) do
        table.insert(output, "[[" .. pageName .. "]]")
    end

    return table.concat(output, separator)
end

function p._listAllByDates(args)
    local sourcePage = getSourcePage(args)
    local data, errorMessage = parseSource(sourcePage)
    if not data then
        return renderError(errorMessage)
    end

    local dateKeys = sortDateKeys(data.byDate)
    local months = {}

    for _, dateKey in ipairs(dateKeys) do
        local month = tonumber(dateKey:sub(1, 2))
        local day = tonumber(dateKey:sub(3, 4))

        if not months[month] then
            months[month] = {
                [1] = {},
                [2] = {},
                [3] = {}
            }
        end

        local columnIndex = 1
        if day >= 21 then
            columnIndex = 3
        elseif day >= 11 then
            columnIndex = 2
        end

        local block = {}
        table.insert(block, "<h3>" .. tostring(month) .. "月" .. tostring(day) .. "日</h3>")
        table.insert(block, "<ul>")

        for _, pageName in ipairs(data.byDate[dateKey]) do
            table.insert(block, "<li>[[" .. pageName .. "]]</li>")
        end

        table.insert(block, "</ul>")

        table.insert(months[month][columnIndex], table.concat(block, "\n"))
    end

    local output = {}

    for month = 1, 12 do
        if months[month] then
            table.insert(output, "<h2>" .. tostring(month) .. "月</h2>")
            table.insert(output, '<div style="display:flex; gap:1em; align-items:flex-start;">')

            for columnIndex = 1, 3 do
                table.insert(output, '<div style="flex:1; min-width:0;">')
                if #months[month][columnIndex] > 0 then
                    table.insert(output, table.concat(months[month][columnIndex], "\n"))
                end
                table.insert(output, "</div>")
            end

            table.insert(output, "</div>")
        end
    end

    return table.concat(output, "\n")
end

function p._forDate(args)
    local sourcePage = getSourcePage(args)
    local dateKey = getDateKey(args)
    local data, errorMessage = parseSource(sourcePage)

    if not data then
        return renderError(errorMessage)
    end

    local pages = data.byDate[dateKey]
    if not pages or #pages == 0 then
        return renderError('No pages found for "' .. dateKey .. '" in [[' .. sourcePage .. "]]")
    end

    local output = {}

    for _, pageName in ipairs(pages) do
        table.insert(output, renderExcerpt(args, pageName))
    end

    return table.concat(output, "\n\n----\n\n")
end

function p._randomForDate(args)
    local sourcePage = getSourcePage(args)
    local dateKey = getDateKey(args)
    local data, errorMessage = parseSource(sourcePage)

    if not data then
        return renderError(errorMessage)
    end

    local pages = data.byDate[dateKey]
    if not pages or #pages == 0 then
        return renderError('No pages found for "' .. dateKey .. '" in [[' .. sourcePage .. "]]")
    end

    local pageName = pickStablePage(pages, args.seed or dateKey)
    if not pageName then
        return renderError("No page could be selected")
    end

    return renderExcerpt(args, pageName)
end

function p._showDate(args)
    local sourcePage = getSourcePage(args)
    local dateKey = getDateKey(args)
    local data, errorMessage = parseSource(sourcePage)

    if not data then
        return renderError(errorMessage)
    end

    local pages = data.byDate[dateKey]
    if not pages or #pages == 0 then
        return renderError('No pages found for "' .. dateKey .. '" in [[' .. sourcePage .. "]]")
    end

    local month = tonumber(dateKey:sub(1, 2))
    local day = tonumber(dateKey:sub(3, 4))
    local output = {}

    table.insert(output, "<h2>當日展示(" .. tostring(month) .. "月" .. tostring(day) .. "日)</h2>")

    for _, pageName in ipairs(pages) do
        table.insert(output, "<h3>" .. pageName .. "</h3>")
        table.insert(output, renderExcerpt(args, pageName))
    end

    return table.concat(output, "\n")
end

return p