Jump to content

Module:Episode/index

From Semantic Stargate Wiki
Documentation icon Module documentation[create]
local p = {}

-- List of source modules
local sources = {
    -- Stargate SG-1
    "Module:Episode/SG1Season1",
    "Module:Episode/SG1Season2",
    "Module:Episode/SG1Season3",
    "Module:Episode/SG1Season4",
    "Module:Episode/SG1Season5",
    "Module:Episode/SG1Season6",
    "Module:Episode/SG1Season7",
    "Module:Episode/SG1Season8",
    "Module:Episode/SG1Season9",
    "Module:Episode/SG1Season10",

    -- Stargate Atlantis
    "Module:Episode/SGASeason1",
    "Module:Episode/SGASeason2",
    "Module:Episode/SGASeason3",
    "Module:Episode/SGASeason4",
    "Module:Episode/SGASeason5",

    -- Stargate Universe
    "Module:Episode/SGUSeason1",
    "Module:Episode/SGUSeason2",

    -- Stargate Infinity
    "Module:Episode/SGISeason1",

    -- Stargate Origins
    "Module:Episode/SGOSeason1",

    -- Films and TV movies
    "Module:Episode/SGUMovies",
}

p.index = {}

------------------------------------------------------------
-- Normalization
------------------------------------------------------------

local function normalize(s)
    s = s or ""
    s = mw.text.trim(s)

    -- Unicode NFD decomposition (allows accent stripping)
    s = mw.ustring.toNFD(s)

    -- Remove combining diacritics (U+0300–U+036F)
    local combining_start = mw.ustring.char(0x0300)
    local combining_end   = mw.ustring.char(0x036F)
    s = mw.ustring.gsub(s, "[" .. combining_start .. "-" .. combining_end .. "]", "")

    -- Normalize apostrophes
    s = mw.ustring.gsub(s, "[’‘´`]", "'")

    -- Normalize curly quotes
    s = mw.ustring.gsub(s, "[“”]", "\"")

    -- Normalize all dash types to a simple hyphen
    s = mw.ustring.gsub(s, "[–—−]", "-")

    -- Collapse multiple spaces
    s = mw.ustring.gsub(s, "%s+", " ")

    -- Lowercase
    s = mw.ustring.lower(s)

    return mw.text.trim(s)
end

------------------------------------------------------------
-- Alias variant generators
------------------------------------------------------------

local function alias_no_dash(a)
    return mw.ustring.gsub(a, "[-–—]", "")
end

local function alias_dash_to_space(a)
    return mw.ustring.gsub(a, "[-–—]", " ")
end

------------------------------------------------------------
-- Build the multi-key index
------------------------------------------------------------

for _, modname in ipairs(sources) do
    local ok, mod = pcall(require, modname)
    if ok and mod.episodes then

        -- Detect movie module
        local isMovieModule = modname:match("SGUMovies")

        for _, ep in ipairs(mod.episodes) do

            -- Clone to avoid mutating source data
            ep = mw.clone(ep)

            -- Movie-specific adjustments
            if isMovieModule then
                ep.namespace = ep.namespace or ""  -- Movies use main namespace
                ep.season    = ep.season    or ""  -- No season number
                ep.episode   = ep.episode   or ""  -- No episode number
            end

            -- Generate alias variants
            for _, key in ipairs(ep.alias or {}) do

                local variants = { key }

                -- Remove dashes
                local nd = alias_no_dash(key)
                if nd ~= key then table.insert(variants, nd) end

                -- Replace dashes with spaces
                local sp = alias_dash_to_space(key)
                if sp ~= key then table.insert(variants, sp) end

                -- Index all variants
                for _, raw in ipairs(variants) do
                    local nkey = normalize(raw)

                    if p.index[nkey] then
                        mw.log(string.format(
                            "[EpisodeIndex] Alias collision detected: '%s' → %s and %s",
                            nkey,
                            p.index[nkey].id or "(no id)",
                            ep.id or "(no id)"
                        ))
                    else
                        p.index[nkey] = ep
                    end
                end
            end
        end
    end
end

------------------------------------------------------------
-- Access function
------------------------------------------------------------

function p.get(key)
    local ep = p.index[normalize(key)]
    if not ep then return nil end

    return {
        id          = ep.id,
        namespace   = ep.namespace,
        page_title  = ep.page_title,
        title_en    = ep.title_en or ep.title_vo,  -- English wiki: keep only English/VO
        property    = ep.property,
        season      = ep.season,
        episode     = ep.episode,
    }
end

return p