Module:Infobox television season name: Difference between revisions

From The Goon Show Depository

m (1 revision imported)
en>Gonnym
(fix for double digit seasons)
Line 1: Line 1:
require('strict')
local match = require("Module:String")._match
local match = require("Module:String")._match


Line 39: Line 40:
end
end


--- Returns the type of word used for "season" in the disambiguation.
--- Returns the type of word used for "season" in the title.
---
---
--- The returned value can be one of three options: "season", "series", "story arc" or "specials".
--- The returned value can be one of three options: "season", "series", "story arc" or "specials".
--- @param disambiguation string The article's disambiguation.
--- @param title string The article's title.
--- @return string
--- @return string
local function getSeasonType(disambiguation)
local function getSeasonType(title)
for _, seasonType in pairs({"season", "series", "story arc", "specials"}) do
for _, seasonType in pairs({"season", "series", "story arc", "specials"}) do
if string.find(disambiguation, seasonType) then
if string.find(title, seasonType) then
return seasonType
return seasonType
end
end
Line 53: Line 54:
end
end


--- Returns the disambiguation without the "(year) TV series," part.
--- Returns the season number from the title.
--- @param disambiguation string The article's disambiguation.
--- @param title string The article's title.
--- @return string
--- @return string | nil
local function getShortDisambiguation(disambiguation)
local function getSeasonNumber(title)
local shortDisambiguation, _ = string.gsub(disambiguation, "%d+ TV series, ", "")
return match(title , "%d+", 1, -1, false, "")
return shortDisambiguation
end
end


Line 66: Line 66:
local function getDisambiguation(title)
local function getDisambiguation(title)
local disambiguation = match(title, "%s%((.-)%)", 1, -1, false, "")
local disambiguation = match(title, "%s%((.-)%)", 1, -1, false, "")
if disambiguation == "" then
if disambiguation and disambiguation == "" then
return nil
return nil
end
end
return disambiguation
return disambiguation
end
--- Returns the title without its disambiguation.
--- @param title string The article's title.
--- @return string | nil
local function getTitleWithoutDisambiguation(title)
local disambiguation = getDisambiguation(title)
if disambiguation then
return string.gsub(title, "%(" .. disambiguation  .. "%)", "")
end
return title
end
end


Line 118: Line 129:
--- @return string
--- @return string
local function getShowName(title)
local function getShowName(title)
local name, _ = mw.ustring.gsub(title, "%s+%b()$", "")
local name, _ = mw.ustring.gsub(title, "season %d*$", "")
name, _ = mw.ustring.gsub(name, "series %d*$", "")
name, _ = mw.ustring.gsub(name, "specials", "")
name, _ = mw.ustring.gsub(name, "story arc %d*$", "")
name = string.match(name, "^%s*(.-)%s*$") -- Trim spaces.
return name
return name
end
end
Line 164: Line 179:
---
---
--- The following are the supported season naming styles:
--- The following are the supported season naming styles:
--- --  Style: <showName> (<seasonType> <seasonNumber>)
--- --  Style: <showName> <seasonType> <seasonNumber>
--- Example: Lost (season 2).
--- Example: Lost season 2.
--- Example: Doctor Who (series 2).
--- Example: Doctor Who series 2.
--- --  Style: <showName> (<country> <seasonType> <seasonNumber>)
--- --  Style: <showName> (<country> TV series) <seasonType> <seasonNumber>
--- Example: The Office (American season 2).
--- Example: The Office (American TV series) season 2.
--- Example: X Factor (British series 2).
--- Example: Teenage Mutant Ninja Turtles (1987 TV series) season 2
--- Example: X Factor (British TV series) series 2.
--- Example: Love Island (British TV series) series 2
--- --  Style: <showName> (<year> TV series) <seasonType> <seasonNumber>
--- Example: Love Island (2015 TV series) series 2
--- --  Style: <showName> (<country> <seasonType>)
--- --  Style: <showName> (<country> <seasonType>)
--- Example: Big Brother 2 (American season).
--- Example: Big Brother 2 (American season).
--- --  Style: <showName> (<year> TV series, <seasonType> <seasonNumber>)
 
--- Example: Teenage Mutant Ninja Turtles (1987 TV series, season 2)
--- --  Style: <showName> (<country> TV series, <seasonType> <seasonNumber>)
--- Example: Love Island (British TV series, series 2)
--- @param title string The article's title.
--- @param title string The article's title.
--- @param seasonNumberDiff number The number difference between the current season and the other season.
--- @param seasonNumberDiff number The number difference between the current season and the other season.
--- @return string, string
--- @return string, string
local function getArticleTitleAndPipedLink(title, seasonNumberDiff)
local function getArticleTitleAndPipedLink(title, seasonNumberDiff)
local seasonType = getSeasonType(title)
local currentSeasonNumber = getSeasonNumber(title)
if tonumber(currentSeasonNumber) == nil then
return "", nil
end
local seasonNumber = currentSeasonNumber + seasonNumberDiff
local modifiedTitle, numberOfReplacements = string.gsub(title, "%d+$", seasonNumber)
local pipedLink = seasonType:gsub("^%l", string.upper) .. " " .. seasonNumber
local disambiguation = getDisambiguation(title)
local disambiguation = getDisambiguation(title)
local shortDisambiguation
-- Titles such as "Big Brother 2 (American season) and Teenage Mutant Ninja Turtles (1987 TV series) season 2".
local seasonType
local seasonNumber
local pipedLink = ""
 
if disambiguation then
if disambiguation then
shortDisambiguation = getShortDisambiguation(disambiguation)
local titleWithoutDisambiguation = string.gsub(title, disambiguation, "_DAB_")
seasonType = getSeasonType(shortDisambiguation)
modifiedTitle, numberOfReplacements = string.gsub(titleWithoutDisambiguation, "%d+", seasonNumber)
seasonNumber = getCurrentSeasonNumberFromDisambiguation(shortDisambiguation)
pipedLink = seasonType:gsub("^%l", string.upper) .. " "
end


local showName = getShowName(title)
-- Articles, such as "Hawaii Five-0 (2010 TV series) season 2", that have a number
local showNameModified
-- as part of their title will need an additional fix in order for that number not to change.
if not seasonNumber or seasonNumber == "" then
if numberOfReplacements > 1 then
-- Not a valid next/prev season link
local titleFix = string.match(title, "%d+", 1)
if not string.match(showName, "%s+(%d+)$") then
modifiedTitle = string.gsub(modifiedTitle, "%d+", titleFix, 1)
return "", nil
end
end
modifiedTitle = string.gsub(modifiedTitle, "_DAB_", disambiguation)
return modifiedTitle, pipedLink


showNameModified, seasonNumber = getShowNameAndSeasonNumberFromShowName(showName)
-- Titles such as "Big Brother Brasil 2".
end
elseif not string.find(title, seasonType) then
return modifiedTitle, nil


if tonumber(seasonNumber) == nil then
-- Invalid usages of TV series articles with the television season infobox.
elseif disambiguation and string.find(disambiguation, "TV series") and not (string.find(disambiguation, ", season") or string.find(disambiguation, ", series"))  then
return "", nil
return "", nil
end


seasonNumber = seasonNumber + seasonNumberDiff
-- Standard titles such as "Lost season 1".
pipedLink = pipedLink .. seasonNumber
 
-- Titles such as "Big Brother 1 (American season)""
if showNameModified and disambiguation then
return showNameModified .. " " .. seasonNumber .. " (" .. disambiguation .. ")", pipedLink
 
-- Titles such as "Big Brother Brasil 1"
elseif showNameModified then
return showNameModified .. " " .. seasonNumber, nil
 
-- Standard titles such as "Lost (season 1)"
else
else
local newDisambiguation, _ = string.gsub(disambiguation, "%d+$", seasonNumber)
return modifiedTitle, pipedLink
return showName .. " (" .. newDisambiguation .. ")", pipedLink
end
end
end
end
Line 232: Line 241:
local getArgs = require("Module:Arguments").getArgs
local getArgs = require("Module:Arguments").getArgs
local args = getArgs(frame)
local args = getArgs(frame)
if args.italic_title then
return "no"
end
local title = args.title
local title = args.title
if not title then
if not title then
title = mw.title.getCurrentTitle().text
title = mw.title.getCurrentTitle().text
Line 303: Line 315:
function p.getSeasonWord(frame)
function p.getSeasonWord(frame)
local title = getTitle(frame)
local title = getTitle(frame)
local disambiguation = getDisambiguation(title)
title = getTitleWithoutDisambiguation(title)
if not disambiguation then
local seasonType = getSeasonType(title)
return seasonType
end
 
--- Returns an {{Italic title}} instance if title qualifies or a blank string.
 
--- @param frame table
--- @return string
function p.getItalicTitle(frame)
local getArgs = require("Module:Arguments").getArgs
local args = getArgs(frame)
-- If italic_title is set then "no" is the only valid value.
-- Don't set an italic title.
if args.italic_title then
return ""
return ""
end
end


local shortDisambiguation = getShortDisambiguation(disambiguation)
local title = getTitle(frame)
local seasonType = getSeasonType(shortDisambiguation)
title = getShowName(getTitleWithoutDisambiguation(title))
if seasonType == "specials" then
 
seasonType = "season"
-- If the infobox is used on List of articles don't set an italic title.
-- TODO: this can be fixed in the future but current usages use a manual display title.
if string.find(title, "List of") then
return ""
end
end


return seasonType
return frame:expandTemplate{title = "Italic title", args = {string = title}}
end
 
--- Returns the text used for the |above= field of the infobox.
---
--- @param frame table
--- @return string
function p.getAboveTitle(frame)
local getArgs = require("Module:Arguments").getArgs
local args = getArgs(frame)
local title = getTitle(frame)
title = getShowName(getTitleWithoutDisambiguation(title))
return title
end
end


--- Returns the relevant text for the sub-header field.
--- Returns the text used for the |subheader= field of the infobox.
---
---
--- The text is returned in the format of "Season #" or "Series #",
--- The text is returned in the format of "Season #" or "Series #",
Line 323: Line 364:
--- @param frame table The frame invoking the module.
--- @param frame table The frame invoking the module.
--- @return string | nil
--- @return string | nil
function p.getInfoboxSubHeader(frame)
function p.getSubHeader(frame)
local getArgs = require("Module:Arguments").getArgs
local getArgs = require("Module:Arguments").getArgs
local args = getArgs(frame)
local args = getArgs(frame)
Line 337: Line 378:
end
end


local title = getTitle(frame)
if not seasonNumber then
local disambiguation = getDisambiguation(title)
local title = getTitle(frame)
if not seasonNumber and disambiguation then
local titleWithoutDisambiguation = getTitleWithoutDisambiguation(title)
local shortDisambiguation = getShortDisambiguation(disambiguation)
seasonNumber = getSeasonNumber(titleWithoutDisambiguation)
 
seasonType = getSeasonType(titleWithoutDisambiguation)
seasonType = getSeasonType(shortDisambiguation)
-- For pages like "Doctor Who specials (2008–2010)".
if seasonType == "specials" then
if seasonType == "specials" then
return shortDisambiguation
local disambiguation = getDisambiguation(title) or ""
return disambiguation .. " " .. seasonType
end
end
seasonType = seasonType:sub(1, 1):upper() .. seasonType:sub(2)
seasonType = seasonType:sub(1, 1):upper() .. seasonType:sub(2)
seasonNumber = getCurrentSeasonNumberFromDisambiguation(shortDisambiguation)
end
end


Line 380: Line 422:


local title = getTitle(frame)
local title = getTitle(frame)
local showName = getShowName(title)
local showName = getShowName(getTitleWithoutDisambiguation(title))
 
if showName then
if showName then
local disambiguation = getDisambiguation(title)
local disambiguation = getDisambiguation(title)
local TVProgramDisambiguation = getTVProgramDisambiguation(disambiguation)
if disambiguation then
local listOfEpisodesArticle = string.format("List of %s%s episodes", showName, TVProgramDisambiguation)
disambiguation = " (" .. disambiguation .. ")"
end
local listOfEpisodesArticle = string.format("List of %s%s episodes", showName, disambiguation or "")
return getListOfEpisodesLink(listOfEpisodesArticle)
return getListOfEpisodesLink(listOfEpisodesArticle)
end
end

Revision as of 10:34, 22 April 2024

require('strict')
local match = require("Module:String")._match

local p = {}

--- Returns a formatted link to the list of episodes article.
--- @param listOfEpisodesArticle string
--- @return string
local function getListOfEpisodesLink(listOfEpisodesArticle)
	local listOfEpisodesPage = mw.title.new(listOfEpisodesArticle, 0)
	if listOfEpisodesPage and listOfEpisodesPage.exists and listOfEpisodesPage.redirectTarget ~= mw.title.getCurrentTitle() then
		return string.format("[[%s|List of episodes]]", listOfEpisodesArticle)
	end
end

--- Returns an article link.
--- @param article string The article's title.
--- @param pipedLink string The piped link.
--- @return string
local function getArticleLink(article, pipedLink)
	if not pipedLink or pipedLink == "" then
		return "[[" .. article .. "]]"
	end
	return "[[" .. article .. "|" .. pipedLink .. "]]"
end

--- Returns the show name and season number from a title.
--- @param showName string The show's title.
--- @return nil | number | string, nil | number | string
local function getShowNameAndSeasonNumberFromShowName(showName)
	local _, _, showNameModified, seasonNumber = string.find(showName, "(.*)%s+(%d+)$")
	return showNameModified, seasonNumber
end

--- Returns the current season number from the disambiguation.
--- @param disambiguation string The article's disambiguation.
--- @return string
local function getCurrentSeasonNumberFromDisambiguation(disambiguation)
	return match(disambiguation , "%d+", 1, -1, false, "")
end

--- Returns the type of word used for "season" in the title.
---
--- The returned value can be one of three options: "season", "series", "story arc" or "specials".
--- @param title string The article's title.
--- @return string
local function getSeasonType(title)
	for _, seasonType in pairs({"season", "series", "story arc", "specials"}) do
		if string.find(title, seasonType) then
			return seasonType
		end
	end
	return "season"
end

--- Returns the season number from the title.
--- @param title string The article's title.
--- @return string | nil
local function getSeasonNumber(title)
	return match(title , "%d+", 1, -1, false, "")
end

--- Returns the disambiguation from the title.
--- @param title string The article's title.
--- @return string | nil
local function getDisambiguation(title)
	local disambiguation = match(title, "%s%((.-)%)", 1, -1, false, "")
	if disambiguation and disambiguation == "" then
		return nil
	end
	return disambiguation
end

--- Returns the title without its disambiguation.
--- @param title string The article's title.
--- @return string | nil
local function getTitleWithoutDisambiguation(title)
	local disambiguation = getDisambiguation(title)
	if disambiguation then
		return string.gsub(title, "%(" .. disambiguation  .. "%)", "")
	end
	return title
end

--- Returns the TV program's disambiguation.
--- @param disambiguation string The disambiguation used in the season's article title.
--- @return string
local function getTVProgramDisambiguation(disambiguation)
	if not disambiguation then
		return ""
	end

	-- Check if the disambiguation is normal 'season #' or 'series #'.
	-- If so, remove disambiguation.
	if string.match(disambiguation, "^season %d*$") or string.match(disambiguation, "^series %d*$") then
		return ""
	end

	local disambiguationStyle = " (%s)"
	-- Check if the disambiguation is extended and has 'TV series' and isn't just season #.
	-- Only leave the TV series disambiguation, not including the season #.
	-- Example: Teenage Mutant Ninja Turtles (1987 TV series, season 5) will return '1987 TV series'.
	if string.find(disambiguation, "TV series") then
		local shortDisambiguation, _ = disambiguation:match("^(.*),")
		if shortDisambiguation then
			return string.format(disambiguationStyle, shortDisambiguation)
		end
	end

	-- Check if the disambiguation is extended with country adjective.
	-- Example: The Office (American season 2) will return "American season 2".
	-- Keep only country adjective.
	local countryDisambiguation = disambiguation:match("^(.*) season %d*") or disambiguation:match("^(.*) series %d*")
	local data = mw.loadData("Module:Country adjective")
	local valid_result = data.getCountryFromAdj[countryDisambiguation]
	-- Check if the country adjective is valid.
	if valid_result then
		-- Add 'TV series' suffix
		return string.format(disambiguationStyle, countryDisambiguation .. " TV series")
	end

	-- Not a known disambiguation style. Use whatever was used in the title or manually added.
	-- Note: might not be a valid style link.
	return string.format(disambiguationStyle, disambiguation)
end

--- Returns the show's name from the title.
--- @param title string The article's title.
--- @return string
local function getShowName(title)
	local name, _ = mw.ustring.gsub(title, "season %d*$", "")
	name, _ = mw.ustring.gsub(name, "series %d*$", "")
	name, _ = mw.ustring.gsub(name, "specials", "")
	name, _ = mw.ustring.gsub(name, "story arc %d*$", "")
	name = string.match(name, "^%s*(.-)%s*$") -- Trim spaces.
	return name
end

--- Returns "true" if the given link is valid; nil otherwise.
--- A link is valid in the following cases:
---	-- A season article exists.
---	-- A redirect exists to a season section.
---
--- A link is invalid in the following cases:
---	-- A season article or redirect do not exist.
---	-- A redirect exists, but it is a general redirect and not for any specific season section.
---
--- Note: Return values are not booleans as the returned value is used in template space.
--- @param title string The article's title.
--- @return string | nil
local function isLinkValid(title)
	local article = mw.title.new(title)

	-- Article or redirect do not exist; Not a valid link.
	if not article or not article.exists then
		return nil
	end

	local redirectTarget = article.redirectTarget

	-- Article exists and is not a redirect; Valid link.
	if not redirectTarget then
		return "true"
	end

	local fullLink = redirectTarget.fullText
	local isSection = fullLink:find("#")

	-- Article is a section redirect; Valid link.
	if isSection then
		return "true"
	end

	-- Article is a general redirect; Not a valid link.
	return nil
end

--- Returns a season article title and a piped link.
---
--- The following are the supported season naming styles:
---	--  Style: <showName> <seasonType> <seasonNumber>
---		Example: Lost season 2.
---		Example: Doctor Who series 2.
---	--  Style: <showName> (<country> TV series) <seasonType> <seasonNumber>
---		Example: The Office (American TV series) season 2.
---		Example: Teenage Mutant Ninja Turtles (1987 TV series) season 2
---		Example: X Factor (British TV series) series 2.
---		Example: Love Island (British TV series) series 2
---	--  Style: <showName> (<year> TV series) <seasonType> <seasonNumber>
---		Example: Love Island (2015 TV series) series 2
---	--  Style: <showName> (<country> <seasonType>)
---		Example: Big Brother 2 (American season).

--- @param title string The article's title.
--- @param seasonNumberDiff number The number difference between the current season and the other season.
--- @return string, string
local function getArticleTitleAndPipedLink(title, seasonNumberDiff)
	local seasonType = getSeasonType(title)
	local currentSeasonNumber = getSeasonNumber(title)
	if tonumber(currentSeasonNumber) == nil then
		return "", nil
	end
	local seasonNumber = currentSeasonNumber + seasonNumberDiff
	local modifiedTitle, numberOfReplacements = string.gsub(title, "%d+$", seasonNumber)
	local pipedLink = seasonType:gsub("^%l", string.upper) .. " " .. seasonNumber

	local disambiguation = getDisambiguation(title)
	-- Titles such as "Big Brother 2 (American season) and Teenage Mutant Ninja Turtles (1987 TV series) season 2".
	if disambiguation then
		local titleWithoutDisambiguation = string.gsub(title, disambiguation, "_DAB_")
		modifiedTitle, numberOfReplacements = string.gsub(titleWithoutDisambiguation, "%d+", seasonNumber)

		 -- Articles, such as "Hawaii Five-0 (2010 TV series) season 2", that have a number
		 -- as part of their title will need an additional fix in order for that number not to change.
		if numberOfReplacements > 1 then
			local titleFix = string.match(title, "%d+", 1)
			modifiedTitle = string.gsub(modifiedTitle, "%d+", titleFix, 1)
		end
	
		modifiedTitle = string.gsub(modifiedTitle, "_DAB_", disambiguation)
		return modifiedTitle, pipedLink

	-- Titles such as "Big Brother Brasil 2".
	elseif not string.find(title, seasonType) then
		return modifiedTitle, nil

	-- Invalid usages of TV series articles with the television season infobox.
	elseif disambiguation and string.find(disambiguation, "TV series") and not (string.find(disambiguation, ", season") or string.find(disambiguation, ", series"))  then
		return "", nil

	-- Standard titles such as "Lost season 1".
	else
		return modifiedTitle, pipedLink
	end
end

--- Returns the article's title either from args (usually from /testcases) or from the page itself.
--- @param frame table The frame invoking the module.
--- @return string
local function getTitle(frame)
	local getArgs = require("Module:Arguments").getArgs
	local args = getArgs(frame)
	if args.italic_title then
		return "no"
	end
	
	local title = args.title
	if not title then
		title = mw.title.getCurrentTitle().text
	end
	return title
end

--- Returns "true" if the given season link is valid; nil otherwise.
--- @param frame table The frame invoking the module.
--- @param seasonNumberDiff number The number difference between the current season and the other season.
--- @return string | nil
local function isSeasonLinkValid(frame, seasonNumberDiff)
	local title = getTitle(frame)
	local articleTitle, _ = getArticleTitleAndPipedLink(title, seasonNumberDiff)
	return isLinkValid(articleTitle)
end

--- Returns a season article link.
--- @param frame table The frame invoking the module.
--- @param seasonNumberDiff number The number difference between the current season and the other season.
--- @return string
local function getSeasonArticleLink(frame, seasonNumberDiff)
	local title = getTitle(frame)
	local articleTitle, pipedLink = getArticleTitleAndPipedLink(title, seasonNumberDiff)
	return getArticleLink(articleTitle, pipedLink)
end

--- Returns "true" if the season link for the next season is valid; nil otherwise.
--- @param frame table The frame invoking the module.
--- @return string | nil
function p.isNextSeasonLinkValid(frame)
	return isSeasonLinkValid(frame, 1)
end

--- Returns "true" if the season link for the previous season is valid; nil otherwise.
--- @param frame table The frame invoking the module.
--- @return string | nil
function p.isPrevSeasonLinkValid(frame)
	return isSeasonLinkValid(frame, -1)
end

--- Returns "true" if the season link for the previous or next season is valid; nil otherwise.
--- @param frame table The frame invoking the module.
--- @return string | nil
function p.isPrevOrNextSeasonLinkValid(frame)
	if p.isPrevSeasonLinkValid(frame) == "true" then
		return "true"
	end
	return p.isNextSeasonLinkValid(frame)
end

--- Returns the next season article title.
--- @param frame table The frame invoking the module.
--- @return string
function p.getNextSeasonArticle(frame)
	return getSeasonArticleLink(frame, 1)
end

--- Returns the previous season article title.
--- @param frame table The frame invoking the module.
--- @return string
function p.getPrevSeasonArticle(frame)
	return getSeasonArticleLink(frame, -1)
end

--- Returns the type of season word used - "season" or "series".
--- @param frame table The frame invoking the module.
--- @return string
function p.getSeasonWord(frame)
	local title = getTitle(frame)
	title = getTitleWithoutDisambiguation(title)
	local seasonType = getSeasonType(title)
	return seasonType
end

--- Returns an {{Italic title}} instance if title qualifies or a blank string.

--- @param frame table
--- @return string
function p.getItalicTitle(frame)
	local getArgs = require("Module:Arguments").getArgs
	local args = getArgs(frame)
	
	-- If italic_title is set then "no" is the only valid value.
	-- Don't set an italic title.
	if args.italic_title then
		return ""
	end

	local title = getTitle(frame)
	title = getShowName(getTitleWithoutDisambiguation(title))

	-- If the infobox is used on List of articles don't set an italic title.
	-- TODO: this can be fixed in the future but current usages use a manual display title.
	if string.find(title, "List of") then
		return ""
	end

	return frame:expandTemplate{title = "Italic title", args = {string = title}}
end

--- Returns the text used for the |above= field of the infobox.
---
--- @param frame table
--- @return string
function p.getAboveTitle(frame)
	local getArgs = require("Module:Arguments").getArgs
	local args = getArgs(frame)
	local title = getTitle(frame)
	title = getShowName(getTitleWithoutDisambiguation(title))
	return title
end

--- Returns the text used for the |subheader= field of the infobox.
---
--- The text is returned in the format of "Season #" or "Series #",
--- depending on either what the article disambiguation uses, or on the manually entered parameters of the infobox.
--- @param frame table The frame invoking the module.
--- @return string | nil
function p.getSubHeader(frame)
	local getArgs = require("Module:Arguments").getArgs
	local args = getArgs(frame)

	local seasonType
	local seasonNumber
	if args.season_number then
		seasonType = "Season"
		seasonNumber = args.season_number
	elseif args.series_number then
		seasonType = "Series"
		seasonNumber = args.series_number
	end

	if not seasonNumber then
		local title = getTitle(frame)
		local titleWithoutDisambiguation = getTitleWithoutDisambiguation(title)
		seasonNumber = getSeasonNumber(titleWithoutDisambiguation)
		seasonType = getSeasonType(titleWithoutDisambiguation)
		
		-- For pages like "Doctor Who specials (2008–2010)".
		if seasonType == "specials" then
			local disambiguation = getDisambiguation(title) or ""
			return disambiguation .. " " .. seasonType
		end
		seasonType = seasonType:sub(1, 1):upper() .. seasonType:sub(2)
	end

	if seasonNumber and seasonNumber ~= "" then
		return seasonType .. " " .. seasonNumber
	end

	return nil
end

--- Returns a formatted link to the list of episodes article.
---
--- The returned link is in the style of:
--- [List of <series name> <disambiguation, if present> episodes <range, if present>|List of episodes]
---
--- The link will only return if the page exists.
--- @param frame table The frame invoking the module.
--- @return string | nil
function p.getListOfEpisodes(frame)
	local getArgs = require("Module:Arguments").getArgs
	local args = getArgs(frame)

	if args.link then
		-- Parameter should be unformatted.
		if string.find(args.link, "%[") then
			local delink = require("Module:Delink")._delink
			args.link = delink({args.link, wikilinks = "target"})
		end

		return getListOfEpisodesLink(args.link)
	end

	local title = getTitle(frame)
	local showName = getShowName(getTitleWithoutDisambiguation(title))
	if showName then
		local disambiguation = getDisambiguation(title)
		if disambiguation then
			disambiguation = " (" .. disambiguation .. ")"
		end
		local listOfEpisodesArticle = string.format("List of %s%s episodes", showName, disambiguation or "")
		return getListOfEpisodesLink(listOfEpisodesArticle)
	end
end

return p