Aller au contenu

« Module:Episode/index » : différence entre les versions

De Stargate Wiki Sémantique
Contenu supprimé Contenu ajouté
mAucun résumé des modifications
Balise : Révocation manuelle
Aucun résumé des modifications
 
(3 versions intermédiaires par le même utilisateur non affichées)
Ligne 1 : Ligne 1 :
local p = {}
local p = {}


------------------------------------------------------------
-- GLOBAL CACHE (empêche la reconstruction multiple)
------------------------------------------------------------

local frame = mw.getCurrentFrame()
local globalCache = mw.getCurrentFrame().args

if globalCache.__EPISODE_INDEX_BUILT then
return globalCache.__EPISODE_INDEX
end

------------------------------------------------------------
-- List of source modules
-- List of source modules
------------------------------------------------------------

local sources = {
local sources = {
-- Stargate SG-1
-- Stargate SG-1
"Module:Episode/SG1Season1",
"Module:Episode/SG1Season1",
"Module:Episode/SG1Season2",
"Module:Episode/SG1Season2",
Ligne 14 : Ligne 28 :
"Module:Episode/SG1Season9",
"Module:Episode/SG1Season9",
"Module:Episode/SG1Season10",
"Module:Episode/SG1Season10",

-- Stargate Atlantis
-- Stargate Atlantis
"Module:Episode/SGASeason1",
"Module:Episode/SGASeason1",
Ligne 20 : Ligne 35 :
"Module:Episode/SGASeason4",
"Module:Episode/SGASeason4",
"Module:Episode/SGASeason5",
"Module:Episode/SGASeason5",

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

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

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

-- Film and TV movies
-- Films
"Module:Episode/SGUMovies",
"Module:Episode/SGUMovies",
}
}
Ligne 38 : Ligne 57 :


local function normalize(s)
local function normalize(s)
-- Default to empty string
s = s or ""
s = s or ""

-- Trim leading/trailing whitespace
s = mw.text.trim(s)
s = mw.text.trim(s)

-- Convert to NFD form (decomposed Unicode)
-- This allows stripping accents by removing combining marks
s = mw.ustring.toNFD(s)
s = mw.ustring.toNFD(s)


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


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

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

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

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


return mw.text.trim(mw.ustring.lower(s))
-- Convert to lowercase
s = mw.ustring.lower(s)

return mw.text.trim(s)
end
end


------------------------------------------------------------
------------------------------------------------------------
-- Alias variant generators
-- Alias variant generators + cache
------------------------------------------------------------
------------------------------------------------------------


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


-- Replace dash characters with spaces
local function alias_dash_to_space(a)
local function alias_dash_to_space(a)
return mw.ustring.gsub(a, "[-–—]", " ")
return mw.ustring.gsub(a, "[-–—]", " ")
end

local alias_cache = {}

local function get_variants(key)
if alias_cache[key] then
return alias_cache[key]
end

local variants = { key }

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

local sp = alias_dash_to_space(key)
if sp ~= key then table.insert(variants, sp) end

alias_cache[key] = variants
return variants
end
end


------------------------------------------------------------
------------------------------------------------------------
-- Build the multi‑key index
-- Build the multi-key index (optimized)
------------------------------------------------------------
------------------------------------------------------------


Ligne 93 : Ligne 112 :
if ok and mod.episodes then
if ok and mod.episodes then


-- Detect if this module contains movies instead of episodes
local isMovieModule = modname:match("SGUMovies")
local isMovieModule = modname:match("SGUMovies")


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



-- Clone the episode table to avoid mutating the source module
ep = mw.clone(ep)
ep = mw.clone(ep)


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


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


local variants = { key }

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

-- Variant: 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)
local nkey = normalize(raw)


if p.index[nkey] then
if not p.index[nkey] then
-- Collision detection
p.index[nkey] = ep
else
mw.log(string.format(
mw.log(string.format(
"[EpisodeIndex] Alias collision detected: '%s' → %s and %s",
"[EpisodeIndex] Alias collision: '%s' → %s / %s",
nkey,
nkey,
p.index[nkey].id or "(no id)",
p.index[nkey].id or "(no id)",
ep.id or "(no id)"
ep.id or "(no id)"
))
))
else
p.index[nkey] = ep
end
end
end
end
Ligne 163 : Ligne 165 :
}
}
end
end

------------------------------------------------------------
-- STORE IN GLOBAL CACHE
------------------------------------------------------------

globalCache.__EPISODE_INDEX_BUILT = true
globalCache.__EPISODE_INDEX = p


return p
return p

Dernière version du 30 mai 2026 à 18:34

Documentation icon Documentation module[créer]
local p = {}

------------------------------------------------------------
-- GLOBAL CACHE (empêche la reconstruction multiple)
------------------------------------------------------------

local frame = mw.getCurrentFrame()
local globalCache = mw.getCurrentFrame().args

if globalCache.__EPISODE_INDEX_BUILT then
    return globalCache.__EPISODE_INDEX
end

------------------------------------------------------------
-- 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
    "Module:Episode/SGUMovies",
}

p.index = {}

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

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

    local combining_start = mw.ustring.char(0x0300)
    local combining_end   = mw.ustring.char(0x036F)
    s = mw.ustring.gsub(s, "[" .. combining_start .. "-" .. combining_end .. "]", "")

    s = mw.ustring.gsub(s, "[’‘´`]", "'")
    s = mw.ustring.gsub(s, "[“”]", "\"")
    s = mw.ustring.gsub(s, "[–—−]", "-")
    s = mw.ustring.gsub(s, "%s+", " ")

    return mw.text.trim(mw.ustring.lower(s))
end

------------------------------------------------------------
-- Alias variant generators + cache
------------------------------------------------------------

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

local alias_cache = {}

local function get_variants(key)
    if alias_cache[key] then
        return alias_cache[key]
    end

    local variants = { key }

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

    local sp = alias_dash_to_space(key)
    if sp ~= key then table.insert(variants, sp) end

    alias_cache[key] = variants
    return variants
end

------------------------------------------------------------
-- Build the multi-key index (optimized)
------------------------------------------------------------

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

        local isMovieModule = modname:match("SGUMovies")

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

            ep = mw.clone(ep)

            if isMovieModule then
                ep.namespace = ep.namespace or ""
                ep.season    = ep.season    or ""
                ep.episode   = ep.episode   or ""
            end

            for _, key in ipairs(ep.alias or {}) do
                for _, raw in ipairs(get_variants(key)) do

                    local nkey = normalize(raw)

                    if not p.index[nkey] then
                        p.index[nkey] = ep
                    else
                        mw.log(string.format(
                            "[EpisodeIndex] Alias collision: '%s' → %s / %s",
                            nkey,
                            p.index[nkey].id or "(no id)",
                            ep.id or "(no id)"
                        ))
                    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_fr    = ep.title_fr,
        title_qc    = ep.title_qc,
        title_vo    = ep.title_vo,
        property    = ep.property,
        season      = ep.season,
        episode     = ep.episode,
    }
end

------------------------------------------------------------
-- STORE IN GLOBAL CACHE
------------------------------------------------------------

globalCache.__EPISODE_INDEX_BUILT = true
globalCache.__EPISODE_INDEX = p

return p