Permanently protected module
From Wikipedia, the free encyclopedia


--- @module

local television = {}



-- Unique suffix list.

local uniqueSuffix = {

	1 = "st",

	2 = "nd",

	3 = "rd",

}



-- Common suffix.

local commonSuffix = "th"



-- Test validation.

local test = false



local descriptions = {

	no_series = {

		type = 1,

		text = "Television episode",

		category = "[[Category:Television episode articles with short description with no series name|%s]]",

	},

	only_series_name = {

		type = 2,

		text = "Episode of %s",

		category = "[[Category:Television episode articles with short description with no season number|%s]]",

	},

	season_and_series_name = {

		type = 3,

		text = "Episode of the %s %s of %s",

		category = "[[Category:Television episode articles with short description with no episode number|%s]]",

	},

	single_episode = {

		type = 4,

		text = "%s episode of the %s %s of %s",

		category = "[[Category:Television episode articles with short description for single episodes|%s]]",

	},

	multi_episodes = {

		type = 5,

		text = "%s episodes of the %s %s of %s",

		category = "[[Category:Television episode articles with short description for multi-part episodes|%s]]",

	},

	limited_series = {

		type = 6,

		text = {

			single_episode = "%s episode of %s",

			multi_episodes = "%s episodes of %s",

		},

		category = "", -- None

	},

	special_episode = {

		type = 7,

		text = "%s episode of %s",

		category = "", -- None

	},

}



-- Tracking category list.

local trackingCategories = {

	disambiguated = "[[Category:Television episode articles with short description and disambiguated page names|%s]]"

}



--- Returns a tracking category from a list by its name and adds a sort key.

--- @param typeName string The name of the category type.

--- @param useTrackingList boolean Whether to return a category from the trackingCategories list.

--- @param sortKey string The key by which to sort the page in the category.

local function getTrackingCategoryFromList(typeName, useTrackingList, sortKey)

	local category

	if useTrackingList then

		category = trackingCategoriestypeName

	else

		category = descriptionstypeName].category

	end

	return string.format(category, sortKey)

end



--- Returns true if the article name is disambiguated.

---

--- This is usually in the format of "Episode name (<TV series name>)" or "Episode name (<TV series name> episode)".

--- @param articleTitle string The name of the page.

--- @param tvSeriesName string The TV series name.

local function isDisambiguated(articleTitle, tvSeriesName)

	local disambiguation = string.match(tostring(articleTitle), "%s%((.-)%)")



	if not (disambiguation and tvSeriesName) then

		return false

	end



	-- Search for the TV series name in the article name disambiguation.

	if (string.find(disambiguation, tvSeriesName)) then

		return true

	end



	return false

end



--- Returns the sort key for the current page.

local function getSortKey()

	local sortTitleModule = require("Module:Sort title")

	return sortTitleModule._getSortKey()

end



--- Returns a tracking category depending on the type of short description created.

--- @param tvSeriesName string The TV series name.

--- @param descriptionName string

local function getTrackingCategory(tvSeriesName, descriptionName)

	local articleTitle = mw.title.getCurrentTitle()

	local namespace = articleTitle.nsText



	-- Check if the invoking page is from the allowed namespace.

	if (not (namespace == "" or namespace == "Draft" or test)) then

		return ""

	end



	local sortKey = getSortKey()

	if (isDisambiguated(articleTitle, tvSeriesName) == true) then

		local category1 = getTrackingCategoryFromList(descriptionName, false, sortKey)

		local category2 = getTrackingCategoryFromList("disambiguated", true, sortKey)

		return category1 .. category2

	end



	return getTrackingCategoryFromList(descriptionName, false, sortKey)

end





--- Returns a short description in the style of: "Television episode" and a maintenance category:

--- "Category:Television episode articles with short description with no series name".

local function getShortDescriptionNoSeries()

	local shortDescription = descriptions.no_series.text

	local category = getTrackingCategory(nil, "no_series")

	return shortDescription, category

end



--- Returns a short description in the style of: "Episode of Lost" and a maintenance category:

--- "Category:Television episode articles with short description with no season number".

--- @param tvSeriesName string The TV series name.

local function getShortDescriptionOnlySeriesName(tvSeriesName)

	local text = descriptions.only_series_name.text

	local shortDescription = string.format(text, tvSeriesName)

	local category = getTrackingCategory(tvSeriesName, "only_series_name")

	return shortDescription, category

end



--- Returns a short description in the style of: "Episode of the first season of Lost" and a maintenance category:

--- "Category:Television episode articles with short description with no episode number".

--- @param tvSeriesName string The TV series name.

--- @param seasonOrdinalNumber string The season's ordinal number.

--- @param seasonTextStyle string The text to use for seasons - either "season" or "series".

local function getShortDescriptionSeasonAndSeriesName(tvSeriesName, seasonOrdinalNumber, seasonTextStyle)

	local text = descriptions.season_and_series_name.text

	local shortDescription = string.format(text, seasonOrdinalNumber, seasonTextStyle, tvSeriesName)

	local category = getTrackingCategory(tvSeriesName, "season_and_series_name")

	return shortDescription, category

end



--- Returns a short description for a limited series in the style of: "1st episode of WandaVision" and a tracking category

--- based on the categoryKey value.

--- @param tvSeriesName string The TV series name.

--- @param episodeOrdinalNumber string The episode's ordinal number.

--- @param descriptionName string A key from the descriptions table.

local function getShortDescriptionLimitedSeries(tvSeriesName, episodeOrdinalNumber, descriptionName)

	local text = descriptions.limited_series.textdescriptionName

	local shortDescription = string.format(text, episodeOrdinalNumber, tvSeriesName)

	local category = getTrackingCategory(tvSeriesName, descriptionName)

	return shortDescription, category

end



--- Returns a short description in the style of: "5th episode of the fourth season of Lost" and a tracking category:

--- "Category:Television episode articles with short description for single episodes".

--- @param tvSeriesName string The TV series name.

--- @param seasonOrdinalNumber string The season's ordinal number.

--- @param seasonTextStyle string The text to use for seasons - either "season" or "series".

--- @param episodeOrdinalNumber string The episode's ordinal number.

--- @param limitedSeries boolean Whether the episode belongs to a limited series.

local function getShortDescriptionSingleEpisode(tvSeriesName, seasonOrdinalNumber, seasonTextStyle, episodeOrdinalNumber, limitedSeries)

	if (limitedSeries) then

		return getShortDescriptionLimitedSeries(tvSeriesName, episodeOrdinalNumber,"single_episode")

	end



	local text = descriptions.single_episode.text

	local shortDescription =  string.format(text, episodeOrdinalNumber, seasonOrdinalNumber, seasonTextStyle, tvSeriesName)

	local category = getTrackingCategory(tvSeriesName, "single_episode")

	return shortDescription, category

end



--- Returns a short description for a multi-part episode in the style of:

--- "23rd and 24th episodes of the third season of Lost" and a tracking category:

--- "Category:Television episode articles with short description for multi-part episodes".

--- @param tvSeriesName string The TV series name.

--- @param seasonOrdinalNumber string The season's ordinal number.

--- @param seasonTextStyle string The text to use for seasons - either "season" or "series".

--- @param episodeOrdinalNumbers table A list of episode ordinal numbers.

--- @param limitedSeries boolean Whether the episode belongs to a limited series.

local function getShortDescriptionMultiEpisode(tvSeriesName, seasonOrdinalNumber, seasonTextStyle, episodeOrdinalNumbers, limitedSeries)

	local episodeText = mw.text.listToText(episodeOrdinalNumbers)



	if (limitedSeries) then

		return getShortDescriptionLimitedSeries(tvSeriesName, episodeText, "multi_episodes")

	end



	local text = descriptions.multi_episodes.text

	local shortDescription = string.format(text, episodeText, seasonOrdinalNumber, seasonTextStyle, tvSeriesName)

	local category = getTrackingCategory(tvSeriesName, "multi_episodes")

	return shortDescription, category

end



--- Returns a short description for a special episode in the style of:

--- "Special episode of Lost" or "<value> episode of Lost" and a tracking category:

--- "Category:Television episode articles with short description for single episodes".

--- @param tvSeriesName string The TV series name.

--- @param special string The type of special episode. A "yes" value defaults to "Special".

local function getShortDescriptionSpecialEpisode(tvSeriesName, special)

	if (special == "yes" or special == "y") then

		special = "Special"

	end

	local text = descriptions.special_episode.text

	local shortDescription = string.format(text, special, tvSeriesName)

	local category = getTrackingCategory(tvSeriesName, "single_episode")

	return shortDescription, category

end



--- Returns a short description based on the description type passed.

--- @param descriptionType number A description type number.

--- @param tvSeriesName string The TV series name.

--- @param seasonOrdinalNumber string The season's ordinal number.

--- @param seasonTextStyle string The text to use for seasons - either "season" or "series".

--- @param episodeOrdinalNumbers table A list of episode ordinal numbers.

--- @param specialEpisode string The type of special episode.

--- @param limitedSeries boolean Whether the episode belongs to a limited series.

local function getShortDescriptionByType(

		descriptionType, tvSeriesName, seasonOrdinalNumber, seasonTextStyle, episodeOrdinalNumbers, specialEpisode, limitedSeries)

	if descriptionType == descriptions.no_series.type then

		return getShortDescriptionNoSeries()

	elseif descriptionType == descriptions.only_series_name.type then

		return getShortDescriptionOnlySeriesName(tvSeriesName)

	elseif descriptionType == descriptions.season_and_series_name.type then

		return getShortDescriptionSeasonAndSeriesName(tvSeriesName, seasonOrdinalNumber, seasonTextStyle)

	elseif descriptionType == descriptions.single_episode.type then

		return getShortDescriptionSingleEpisode(

                tvSeriesName, seasonOrdinalNumber, seasonTextStyle, episodeOrdinalNumbers1], limitedSeries)

	elseif descriptionType == descriptions.multi_episodes.type then

		return getShortDescriptionMultiEpisode(

				tvSeriesName, seasonOrdinalNumber, seasonTextStyle, episodeOrdinalNumbers, limitedSeries)

	elseif descriptionType == descriptions.special_episode.type then

		return getShortDescriptionSpecialEpisode(tvSeriesName, specialEpisode)

	else

		return ""

	end

end



--- Returns the type of the description to use.

--- @param tvSeriesName string The TV series name.

--- @param seasonOrdinalNumber string The season's ordinal number.

--- @param episodeOrdinalNumbers table A list of episode ordinal numbers.

--- @param specialEpisode string The type of special episode.

--- @param limitedSeries boolean Whether the episode belongs to a limited series.

local function getDescriptionType(tvSeriesName, seasonOrdinalNumber, episodeOrdinalNumbers, specialEpisode, limitedSeries)

	if (not tvSeriesName) then

		return descriptions.no_series.type

	end



	if (specialEpisode) then

		return descriptions.special_episode.type

	end



	if (not seasonOrdinalNumber and not limitedSeries) then

		return descriptions.only_series_name.type

	end



	if (#episodeOrdinalNumbers < 1) then

		return descriptions.season_and_series_name.type

	end



	if (#episodeOrdinalNumbers == 1) then

		return descriptions.single_episode.type

	end



	if (#episodeOrdinalNumbers > 1) then

		return descriptions.multi_episodes.type

	end

end



--- Returns true if the TV series is a limited series.

--- @param limitedSeries string Any value will be considered as true.

--- @param tvSeriesNameDab string The disambiguation used in the series name article title.

local function isLimitedSeries(limitedSeries, tvSeriesNameDab)

	if (limitedSeries) then

		return true

	end



	if tvSeriesNameDab and string.find(tvSeriesNameDab, "miniseries") then

		return true

	end



	return false

end



--- Returns the ordinal indicator for an integer between 0 and 100.

---

--- Numbers "1", "2" and "3" have unique suffixes.

--- Numbers between 4 and 20 have the same common suffix - "th".

--- Numbers ending with 0 have the same common suffix - "th".

--- @param number number A number value.

local function getOrdinalIndicatorLessThan100(number)

	local suffix

	while (not suffix) do

		-- Check if the number equals 0; This should never be a valid entry. Assign suffix as an empty string.

		if (number == 0) then

			suffix = ""

		-- Check if the number is less than 4; Numbers "1", "2" and "3" have unique suffixes.

		elseif (number < 4) then

			suffix = uniqueSuffixnumber

		-- Check if the number is more than 4 AND less than 20; These numbers all have the same common suffix.

		elseif (number < 20) then

			suffix = commonSuffix

		-- Check if the remainder after division of the number by 10 equals 0.

		elseif (number % 10 == 0) then

			suffix = commonSuffix

		else

			-- Numbers that are above 20 and which their remainder doesn't equal 0 (such as 45).

			-- Remainder after division of the number by 10; So if the current number is 45, the new number is 5.

			number = number % 10

		end

	end

	return suffix

end



--- Returns the ordinal indicator for an integer between 0 and 1000.

--- @param number number A number value.

local function getOrdinalIndicatorLessThan1000(number)

	if (number < 100) then

		return getOrdinalIndicatorLessThan100(number)

	elseif (number % 100 == 0) then

		return commonSuffix

	else

		-- Numbers that are above 100 and which their remainder doesn't equal 0 (such as 345).

		-- Pass the remainder after division of the number by 100 (So for 345, it would pass 45) as the parameter.

		return getOrdinalIndicatorLessThan100(number % 100)

	end

end



--- Returns a table of episode numbers.

---

--- Episode values may be of multipart episodes, in such situations, an episode may be seperated by one of the following:

--- ",", "/", "&", "-", "–", "and".

--- Decimal values and episode overall values sometimes erroneously used are removed.

--- @param number string A number value in string format.

local function cleanEpisodeNumber(number)

	if (not number) then

		return {}

	end



	number = string.gsub(number, "%(.*%)", " ")

	number = string.gsub(number, "%.%d+", " ")



	local numbers = {}

	for digits in string.gmatch(number, "%d+") do

		table.insert(numbers, tonumber(digits))

	end

	return numbers

end



--- Returns a table of episode ordinal numbers.

---

--- In most situations there will be only one episode, but this can support more.

--- @param episodeNumber number The episode's number.

local function getEpisodeOrdinalNumbers(episodeNumber)

	local episodeNumbers = cleanEpisodeNumber(episodeNumber)



	if (#episodeNumbers < 1) then

		return episodeNumbers

	end



	local episodeOrdinals = {}

	for _, cleanedEpisodeNumber in pairs(episodeNumbers) do

		local ordinalIndicator = getOrdinalIndicatorLessThan1000(cleanedEpisodeNumber)

		table.insert(episodeOrdinals, cleanedEpisodeNumber .. ordinalIndicator)

	end



	return episodeOrdinals

end



--- Returns true if the season number value is a number.

--- @param seasonNumber string The season number value in string format.

local function validateSeasonNumber(seasonNumber)

	if (tonumber(seasonNumber)) then

		return true

	else

		return false

	end

end



--- Returns the season's ordinal number, or nil if no season number was set.

--- @param seasonNumber string The season number.

local function getSeasonOrdinalNumber(seasonNumber)

	if (seasonNumber) then

		local convertOrdinal = require("Module:Ordinal")

		return convertOrdinal._ordinal(seasonNumber)

	end

	return nil

end



--- Returns a season number after removing from it unwanted characters.

---

--- This is done to make sure that no malformed season values have been entered.

--- The function will remove all text which is not part of the first number in the string.

---

--- The function converts entries such as:

--- "1.2" -> "1"

--- "12.2" -> "12"

--- @param seasonNumber string The season number value in string format.

local function cleanSeasonNumber(seasonNumber)

	if (seasonNumber) then

		return string.match(seasonNumber, "%d+")

	end

	return nil

end



--- Returns the season number after or cleaning it from unwanted values and validating value is a number.

--- Also returns the text style to use - either "season" or "series".

--- If no value was entered or if value was not a number, return nil.

--- @param seasonNumber string The season number.

--- @param seasonNumberUK string The season number, if UK style was used.

local function getSeasonNumberAndTextStyle(seasonNumber, seasonNumberUK)

    for _, v in ipairs({{seasonNumber, "season"}, {seasonNumberUK, "series"}}) do

        local cleanedSeasonNumber = cleanSeasonNumber(v1])

        if (validateSeasonNumber(cleanedSeasonNumber)) then

            return cleanedSeasonNumber, v2

        end

    end

	return nil

end



--- Returns the TV series title without disambiguation, and the disambiguation, or nil if no TV series name was set.

--- @param tvSeriesName string The TV series name.

--- @param notDab string If set, the parenthesis in the title is not disambiguation.

local function getTVSeriesName(tvSeriesName, notDab)

	if (tvSeriesName) then

		if (not notDab) then

			local title, disambiguation = string.match(tvSeriesName, "^(.+) %((.*)%)$")

			if not title then

				title = tvSeriesName

			end

			return title, disambiguation

		end

		return tvSeriesName, nil

	end

	return nil, nil

end



--- Returns the initial values after removing unwanted characters.

--- @param args table The values that should be processed.

local function cleanValues(args)

	for i, v in ipairs({"episode_num", "season_num", "season_num_uk", "series_name"}) do

		if (argsv]) then

			argsv = argsv]:gsub("\127[^\127]*UNIQ%-%-(%a+)%-%x+%-QINU[^\127]*\127", "")	-- Remove all strip-markers.

			argsv = argsv]:gsub("</? *br */?>", " ")					-- Replace <br /> (and variants) with space character.

			argsv = argsv]:gsub("%b<>[^<]+%b<>", "")					-- Remove html markup.

			argsv = argsv]:gsub("%b<>", "")							-- Remove self-closed html tags.

			if i ~= 4 then

				argsv = argsv]:gsub("%[%[[^|]+|([^%]]+)%]%]", "%1")	-- Remove wiki-link retain label.

			else

				argsv = argsv]:gsub("%[%[([^|]+)|.*%]%]", "%1")		-- Remove wiki-link retain article.

			end

			argsv = argsv]:gsub("%[%[([^%]]+)%]%]", "%1")			-- Remove wiki-link retain article.

			argsv = argsv]:gsub("%[%S+ +([^%]]-)%]", "%1")			-- Remove URLs retain label.

			argsv = argsv]:gsub("%[[^%]]-%]", "")					-- Remove all remaining URLs.



			if (argsv == "") then										-- Check if the value is an empty string.

				argsv = nil											-- The value is an empty string; Set it to nil.

			end

		end

	end

	return args

end



--- Public function - main process.

--- @param frame table The frame invoking the module.

--- @param args table The key-value parameters passed to the module.

function television._getShortDescription(frame, args)

	args = cleanValues(args)

	local tvSeriesName, tvSeriesNameDab = getTVSeriesName(args.series_name, args.not_dab)

    local seasonNumber, seasonTextStyle = getSeasonNumberAndTextStyle(args.season_num, args.season_num_uk)

	local seasonOrdinalNumber = getSeasonOrdinalNumber(seasonNumber)

	local episodeOrdinalNumbers = getEpisodeOrdinalNumbers(args.episode_num)

	local limitedSeries = isLimitedSeries(args.limited, tvSeriesNameDab)

	

	local descriptionType = getDescriptionType(

			tvSeriesName,

			seasonOrdinalNumber,

			episodeOrdinalNumbers,

			args.special,

			limitedSeries

	)



	local shortDescription, trackingCat = getShortDescriptionByType(

			descriptionType,

			tvSeriesName,

			seasonOrdinalNumber,

            seasonTextStyle,

			episodeOrdinalNumbers,

			args.special,

			limitedSeries

	)



	-- Check if the invoking page is from /testcases or /doc pages.

	if (args.test) then

		return shortDescription, trackingCat

	elseif (args.doc) then

		return shortDescription

	else

		local tableData = {shortDescription, "noreplace"}

		return frame:expandTemplate({title = "short description", args = tableData}) .. trackingCat

	end

end



--- Public function which is used to create a television episode's short description

--- from the data available in [Template:Infobox television episode].

--- A suitable description will be generated depending on the values of the various parameters.

--- See documentation for examples.

---

--- Parameters:

--- |episode_num=		— optional; The episode's number.

--- |season_num=		— optional; The season's number.

--- |season_num_uk=		— optional; The season's number if using the British "series" term.

--- |series_name=		— optional; The TV series name.

--- |not_dab=			— optional; Set if the TV series name has parentheses as part of its name.

--- |special=			— optional; Setting to "yes" will set the description as a "special episode".

---							Any other value will replace the word "special" with the one entered.

---							For example "special=recap" will create "recap episode".

---	|limited=			— optional; Set if the series is a single season series, such as miniseries or limited series

---							and does not need a season number as part of the description.

--- @param frame table The frame invoking the module.

function television.getShortDescription(frame)

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

	local args = getArgs(frame)

	return television._getShortDescription(frame, args)

end





--- Public function which is used for testing output only.

--- @param frame table The frame invoking the module.

function television.test(frame)

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

	local args = getArgs(frame)



	test = args.test

	local shortDescription, categories = television._getShortDescription(frame, args)



	if (test == "cat") then

		return categories

	else

		return shortDescription

	end

end



return television
Permanently protected module
From Wikipedia, the free encyclopedia


--- @module

local television = {}



-- Unique suffix list.

local uniqueSuffix = {

	1 = "st",

	2 = "nd",

	3 = "rd",

}



-- Common suffix.

local commonSuffix = "th"



-- Test validation.

local test = false



local descriptions = {

	no_series = {

		type = 1,

		text = "Television episode",

		category = "[[Category:Television episode articles with short description with no series name|%s]]",

	},

	only_series_name = {

		type = 2,

		text = "Episode of %s",

		category = "[[Category:Television episode articles with short description with no season number|%s]]",

	},

	season_and_series_name = {

		type = 3,

		text = "Episode of the %s %s of %s",

		category = "[[Category:Television episode articles with short description with no episode number|%s]]",

	},

	single_episode = {

		type = 4,

		text = "%s episode of the %s %s of %s",

		category = "[[Category:Television episode articles with short description for single episodes|%s]]",

	},

	multi_episodes = {

		type = 5,

		text = "%s episodes of the %s %s of %s",

		category = "[[Category:Television episode articles with short description for multi-part episodes|%s]]",

	},

	limited_series = {

		type = 6,

		text = {

			single_episode = "%s episode of %s",

			multi_episodes = "%s episodes of %s",

		},

		category = "", -- None

	},

	special_episode = {

		type = 7,

		text = "%s episode of %s",

		category = "", -- None

	},

}



-- Tracking category list.

local trackingCategories = {

	disambiguated = "[[Category:Television episode articles with short description and disambiguated page names|%s]]"

}



--- Returns a tracking category from a list by its name and adds a sort key.

--- @param typeName string The name of the category type.

--- @param useTrackingList boolean Whether to return a category from the trackingCategories list.

--- @param sortKey string The key by which to sort the page in the category.

local function getTrackingCategoryFromList(typeName, useTrackingList, sortKey)

	local category

	if useTrackingList then

		category = trackingCategoriestypeName

	else

		category = descriptionstypeName].category

	end

	return string.format(category, sortKey)

end



--- Returns true if the article name is disambiguated.

---

--- This is usually in the format of "Episode name (<TV series name>)" or "Episode name (<TV series name> episode)".

--- @param articleTitle string The name of the page.

--- @param tvSeriesName string The TV series name.

local function isDisambiguated(articleTitle, tvSeriesName)

	local disambiguation = string.match(tostring(articleTitle), "%s%((.-)%)")



	if not (disambiguation and tvSeriesName) then

		return false

	end



	-- Search for the TV series name in the article name disambiguation.

	if (string.find(disambiguation, tvSeriesName)) then

		return true

	end



	return false

end



--- Returns the sort key for the current page.

local function getSortKey()

	local sortTitleModule = require("Module:Sort title")

	return sortTitleModule._getSortKey()

end



--- Returns a tracking category depending on the type of short description created.

--- @param tvSeriesName string The TV series name.

--- @param descriptionName string

local function getTrackingCategory(tvSeriesName, descriptionName)

	local articleTitle = mw.title.getCurrentTitle()

	local namespace = articleTitle.nsText



	-- Check if the invoking page is from the allowed namespace.

	if (not (namespace == "" or namespace == "Draft" or test)) then

		return ""

	end



	local sortKey = getSortKey()

	if (isDisambiguated(articleTitle, tvSeriesName) == true) then

		local category1 = getTrackingCategoryFromList(descriptionName, false, sortKey)

		local category2 = getTrackingCategoryFromList("disambiguated", true, sortKey)

		return category1 .. category2

	end



	return getTrackingCategoryFromList(descriptionName, false, sortKey)

end





--- Returns a short description in the style of: "Television episode" and a maintenance category:

--- "Category:Television episode articles with short description with no series name".

local function getShortDescriptionNoSeries()

	local shortDescription = descriptions.no_series.text

	local category = getTrackingCategory(nil, "no_series")

	return shortDescription, category

end



--- Returns a short description in the style of: "Episode of Lost" and a maintenance category:

--- "Category:Television episode articles with short description with no season number".

--- @param tvSeriesName string The TV series name.

local function getShortDescriptionOnlySeriesName(tvSeriesName)

	local text = descriptions.only_series_name.text

	local shortDescription = string.format(text, tvSeriesName)

	local category = getTrackingCategory(tvSeriesName, "only_series_name")

	return shortDescription, category

end



--- Returns a short description in the style of: "Episode of the first season of Lost" and a maintenance category:

--- "Category:Television episode articles with short description with no episode number".

--- @param tvSeriesName string The TV series name.

--- @param seasonOrdinalNumber string The season's ordinal number.

--- @param seasonTextStyle string The text to use for seasons - either "season" or "series".

local function getShortDescriptionSeasonAndSeriesName(tvSeriesName, seasonOrdinalNumber, seasonTextStyle)

	local text = descriptions.season_and_series_name.text

	local shortDescription = string.format(text, seasonOrdinalNumber, seasonTextStyle, tvSeriesName)

	local category = getTrackingCategory(tvSeriesName, "season_and_series_name")

	return shortDescription, category

end



--- Returns a short description for a limited series in the style of: "1st episode of WandaVision" and a tracking category

--- based on the categoryKey value.

--- @param tvSeriesName string The TV series name.

--- @param episodeOrdinalNumber string The episode's ordinal number.

--- @param descriptionName string A key from the descriptions table.

local function getShortDescriptionLimitedSeries(tvSeriesName, episodeOrdinalNumber, descriptionName)

	local text = descriptions.limited_series.textdescriptionName

	local shortDescription = string.format(text, episodeOrdinalNumber, tvSeriesName)

	local category = getTrackingCategory(tvSeriesName, descriptionName)

	return shortDescription, category

end



--- Returns a short description in the style of: "5th episode of the fourth season of Lost" and a tracking category:

--- "Category:Television episode articles with short description for single episodes".

--- @param tvSeriesName string The TV series name.

--- @param seasonOrdinalNumber string The season's ordinal number.

--- @param seasonTextStyle string The text to use for seasons - either "season" or "series".

--- @param episodeOrdinalNumber string The episode's ordinal number.

--- @param limitedSeries boolean Whether the episode belongs to a limited series.

local function getShortDescriptionSingleEpisode(tvSeriesName, seasonOrdinalNumber, seasonTextStyle, episodeOrdinalNumber, limitedSeries)

	if (limitedSeries) then

		return getShortDescriptionLimitedSeries(tvSeriesName, episodeOrdinalNumber,"single_episode")

	end



	local text = descriptions.single_episode.text

	local shortDescription =  string.format(text, episodeOrdinalNumber, seasonOrdinalNumber, seasonTextStyle, tvSeriesName)

	local category = getTrackingCategory(tvSeriesName, "single_episode")

	return shortDescription, category

end



--- Returns a short description for a multi-part episode in the style of:

--- "23rd and 24th episodes of the third season of Lost" and a tracking category:

--- "Category:Television episode articles with short description for multi-part episodes".

--- @param tvSeriesName string The TV series name.

--- @param seasonOrdinalNumber string The season's ordinal number.

--- @param seasonTextStyle string The text to use for seasons - either "season" or "series".

--- @param episodeOrdinalNumbers table A list of episode ordinal numbers.

--- @param limitedSeries boolean Whether the episode belongs to a limited series.

local function getShortDescriptionMultiEpisode(tvSeriesName, seasonOrdinalNumber, seasonTextStyle, episodeOrdinalNumbers, limitedSeries)

	local episodeText = mw.text.listToText(episodeOrdinalNumbers)



	if (limitedSeries) then

		return getShortDescriptionLimitedSeries(tvSeriesName, episodeText, "multi_episodes")

	end



	local text = descriptions.multi_episodes.text

	local shortDescription = string.format(text, episodeText, seasonOrdinalNumber, seasonTextStyle, tvSeriesName)

	local category = getTrackingCategory(tvSeriesName, "multi_episodes")

	return shortDescription, category

end



--- Returns a short description for a special episode in the style of:

--- "Special episode of Lost" or "<value> episode of Lost" and a tracking category:

--- "Category:Television episode articles with short description for single episodes".

--- @param tvSeriesName string The TV series name.

--- @param special string The type of special episode. A "yes" value defaults to "Special".

local function getShortDescriptionSpecialEpisode(tvSeriesName, special)

	if (special == "yes" or special == "y") then

		special = "Special"

	end

	local text = descriptions.special_episode.text

	local shortDescription = string.format(text, special, tvSeriesName)

	local category = getTrackingCategory(tvSeriesName, "single_episode")

	return shortDescription, category

end



--- Returns a short description based on the description type passed.

--- @param descriptionType number A description type number.

--- @param tvSeriesName string The TV series name.

--- @param seasonOrdinalNumber string The season's ordinal number.

--- @param seasonTextStyle string The text to use for seasons - either "season" or "series".

--- @param episodeOrdinalNumbers table A list of episode ordinal numbers.

--- @param specialEpisode string The type of special episode.

--- @param limitedSeries boolean Whether the episode belongs to a limited series.

local function getShortDescriptionByType(

		descriptionType, tvSeriesName, seasonOrdinalNumber, seasonTextStyle, episodeOrdinalNumbers, specialEpisode, limitedSeries)

	if descriptionType == descriptions.no_series.type then

		return getShortDescriptionNoSeries()

	elseif descriptionType == descriptions.only_series_name.type then

		return getShortDescriptionOnlySeriesName(tvSeriesName)

	elseif descriptionType == descriptions.season_and_series_name.type then

		return getShortDescriptionSeasonAndSeriesName(tvSeriesName, seasonOrdinalNumber, seasonTextStyle)

	elseif descriptionType == descriptions.single_episode.type then

		return getShortDescriptionSingleEpisode(

                tvSeriesName, seasonOrdinalNumber, seasonTextStyle, episodeOrdinalNumbers1], limitedSeries)

	elseif descriptionType == descriptions.multi_episodes.type then

		return getShortDescriptionMultiEpisode(

				tvSeriesName, seasonOrdinalNumber, seasonTextStyle, episodeOrdinalNumbers, limitedSeries)

	elseif descriptionType == descriptions.special_episode.type then

		return getShortDescriptionSpecialEpisode(tvSeriesName, specialEpisode)

	else

		return ""

	end

end



--- Returns the type of the description to use.

--- @param tvSeriesName string The TV series name.

--- @param seasonOrdinalNumber string The season's ordinal number.

--- @param episodeOrdinalNumbers table A list of episode ordinal numbers.

--- @param specialEpisode string The type of special episode.

--- @param limitedSeries boolean Whether the episode belongs to a limited series.

local function getDescriptionType(tvSeriesName, seasonOrdinalNumber, episodeOrdinalNumbers, specialEpisode, limitedSeries)

	if (not tvSeriesName) then

		return descriptions.no_series.type

	end



	if (specialEpisode) then

		return descriptions.special_episode.type

	end



	if (not seasonOrdinalNumber and not limitedSeries) then

		return descriptions.only_series_name.type

	end



	if (#episodeOrdinalNumbers < 1) then

		return descriptions.season_and_series_name.type

	end



	if (#episodeOrdinalNumbers == 1) then

		return descriptions.single_episode.type

	end



	if (#episodeOrdinalNumbers > 1) then

		return descriptions.multi_episodes.type

	end

end



--- Returns true if the TV series is a limited series.

--- @param limitedSeries string Any value will be considered as true.

--- @param tvSeriesNameDab string The disambiguation used in the series name article title.

local function isLimitedSeries(limitedSeries, tvSeriesNameDab)

	if (limitedSeries) then

		return true

	end



	if tvSeriesNameDab and string.find(tvSeriesNameDab, "miniseries") then

		return true

	end



	return false

end



--- Returns the ordinal indicator for an integer between 0 and 100.

---

--- Numbers "1", "2" and "3" have unique suffixes.

--- Numbers between 4 and 20 have the same common suffix - "th".

--- Numbers ending with 0 have the same common suffix - "th".

--- @param number number A number value.

local function getOrdinalIndicatorLessThan100(number)

	local suffix

	while (not suffix) do

		-- Check if the number equals 0; This should never be a valid entry. Assign suffix as an empty string.

		if (number == 0) then

			suffix = ""

		-- Check if the number is less than 4; Numbers "1", "2" and "3" have unique suffixes.

		elseif (number < 4) then

			suffix = uniqueSuffixnumber

		-- Check if the number is more than 4 AND less than 20; These numbers all have the same common suffix.

		elseif (number < 20) then

			suffix = commonSuffix

		-- Check if the remainder after division of the number by 10 equals 0.

		elseif (number % 10 == 0) then

			suffix = commonSuffix

		else

			-- Numbers that are above 20 and which their remainder doesn't equal 0 (such as 45).

			-- Remainder after division of the number by 10; So if the current number is 45, the new number is 5.

			number = number % 10

		end

	end

	return suffix

end



--- Returns the ordinal indicator for an integer between 0 and 1000.

--- @param number number A number value.

local function getOrdinalIndicatorLessThan1000(number)

	if (number < 100) then

		return getOrdinalIndicatorLessThan100(number)

	elseif (number % 100 == 0) then

		return commonSuffix

	else

		-- Numbers that are above 100 and which their remainder doesn't equal 0 (such as 345).

		-- Pass the remainder after division of the number by 100 (So for 345, it would pass 45) as the parameter.

		return getOrdinalIndicatorLessThan100(number % 100)

	end

end



--- Returns a table of episode numbers.

---

--- Episode values may be of multipart episodes, in such situations, an episode may be seperated by one of the following:

--- ",", "/", "&", "-", "–", "and".

--- Decimal values and episode overall values sometimes erroneously used are removed.

--- @param number string A number value in string format.

local function cleanEpisodeNumber(number)

	if (not number) then

		return {}

	end



	number = string.gsub(number, "%(.*%)", " ")

	number = string.gsub(number, "%.%d+", " ")



	local numbers = {}

	for digits in string.gmatch(number, "%d+") do

		table.insert(numbers, tonumber(digits))

	end

	return numbers

end



--- Returns a table of episode ordinal numbers.

---

--- In most situations there will be only one episode, but this can support more.

--- @param episodeNumber number The episode's number.

local function getEpisodeOrdinalNumbers(episodeNumber)

	local episodeNumbers = cleanEpisodeNumber(episodeNumber)



	if (#episodeNumbers < 1) then

		return episodeNumbers

	end



	local episodeOrdinals = {}

	for _, cleanedEpisodeNumber in pairs(episodeNumbers) do

		local ordinalIndicator = getOrdinalIndicatorLessThan1000(cleanedEpisodeNumber)

		table.insert(episodeOrdinals, cleanedEpisodeNumber .. ordinalIndicator)

	end



	return episodeOrdinals

end



--- Returns true if the season number value is a number.

--- @param seasonNumber string The season number value in string format.

local function validateSeasonNumber(seasonNumber)

	if (tonumber(seasonNumber)) then

		return true

	else

		return false

	end

end



--- Returns the season's ordinal number, or nil if no season number was set.

--- @param seasonNumber string The season number.

local function getSeasonOrdinalNumber(seasonNumber)

	if (seasonNumber) then

		local convertOrdinal = require("Module:Ordinal")

		return convertOrdinal._ordinal(seasonNumber)

	end

	return nil

end



--- Returns a season number after removing from it unwanted characters.

---

--- This is done to make sure that no malformed season values have been entered.

--- The function will remove all text which is not part of the first number in the string.

---

--- The function converts entries such as:

--- "1.2" -> "1"

--- "12.2" -> "12"

--- @param seasonNumber string The season number value in string format.

local function cleanSeasonNumber(seasonNumber)

	if (seasonNumber) then

		return string.match(seasonNumber, "%d+")

	end

	return nil

end



--- Returns the season number after or cleaning it from unwanted values and validating value is a number.

--- Also returns the text style to use - either "season" or "series".

--- If no value was entered or if value was not a number, return nil.

--- @param seasonNumber string The season number.

--- @param seasonNumberUK string The season number, if UK style was used.

local function getSeasonNumberAndTextStyle(seasonNumber, seasonNumberUK)

    for _, v in ipairs({{seasonNumber, "season"}, {seasonNumberUK, "series"}}) do

        local cleanedSeasonNumber = cleanSeasonNumber(v1])

        if (validateSeasonNumber(cleanedSeasonNumber)) then

            return cleanedSeasonNumber, v2

        end

    end

	return nil

end



--- Returns the TV series title without disambiguation, and the disambiguation, or nil if no TV series name was set.

--- @param tvSeriesName string The TV series name.

--- @param notDab string If set, the parenthesis in the title is not disambiguation.

local function getTVSeriesName(tvSeriesName, notDab)

	if (tvSeriesName) then

		if (not notDab) then

			local title, disambiguation = string.match(tvSeriesName, "^(.+) %((.*)%)$")

			if not title then

				title = tvSeriesName

			end

			return title, disambiguation

		end

		return tvSeriesName, nil

	end

	return nil, nil

end



--- Returns the initial values after removing unwanted characters.

--- @param args table The values that should be processed.

local function cleanValues(args)

	for i, v in ipairs({"episode_num", "season_num", "season_num_uk", "series_name"}) do

		if (argsv]) then

			argsv = argsv]:gsub("\127[^\127]*UNIQ%-%-(%a+)%-%x+%-QINU[^\127]*\127", "")	-- Remove all strip-markers.

			argsv = argsv]:gsub("</? *br */?>", " ")					-- Replace <br /> (and variants) with space character.

			argsv = argsv]:gsub("%b<>[^<]+%b<>", "")					-- Remove html markup.

			argsv = argsv]:gsub("%b<>", "")							-- Remove self-closed html tags.

			if i ~= 4 then

				argsv = argsv]:gsub("%[%[[^|]+|([^%]]+)%]%]", "%1")	-- Remove wiki-link retain label.

			else

				argsv = argsv]:gsub("%[%[([^|]+)|.*%]%]", "%1")		-- Remove wiki-link retain article.

			end

			argsv = argsv]:gsub("%[%[([^%]]+)%]%]", "%1")			-- Remove wiki-link retain article.

			argsv = argsv]:gsub("%[%S+ +([^%]]-)%]", "%1")			-- Remove URLs retain label.

			argsv = argsv]:gsub("%[[^%]]-%]", "")					-- Remove all remaining URLs.



			if (argsv == "") then										-- Check if the value is an empty string.

				argsv = nil											-- The value is an empty string; Set it to nil.

			end

		end

	end

	return args

end



--- Public function - main process.

--- @param frame table The frame invoking the module.

--- @param args table The key-value parameters passed to the module.

function television._getShortDescription(frame, args)

	args = cleanValues(args)

	local tvSeriesName, tvSeriesNameDab = getTVSeriesName(args.series_name, args.not_dab)

    local seasonNumber, seasonTextStyle = getSeasonNumberAndTextStyle(args.season_num, args.season_num_uk)

	local seasonOrdinalNumber = getSeasonOrdinalNumber(seasonNumber)

	local episodeOrdinalNumbers = getEpisodeOrdinalNumbers(args.episode_num)

	local limitedSeries = isLimitedSeries(args.limited, tvSeriesNameDab)

	

	local descriptionType = getDescriptionType(

			tvSeriesName,

			seasonOrdinalNumber,

			episodeOrdinalNumbers,

			args.special,

			limitedSeries

	)



	local shortDescription, trackingCat = getShortDescriptionByType(

			descriptionType,

			tvSeriesName,

			seasonOrdinalNumber,

            seasonTextStyle,

			episodeOrdinalNumbers,

			args.special,

			limitedSeries

	)



	-- Check if the invoking page is from /testcases or /doc pages.

	if (args.test) then

		return shortDescription, trackingCat

	elseif (args.doc) then

		return shortDescription

	else

		local tableData = {shortDescription, "noreplace"}

		return frame:expandTemplate({title = "short description", args = tableData}) .. trackingCat

	end

end



--- Public function which is used to create a television episode's short description

--- from the data available in [Template:Infobox television episode].

--- A suitable description will be generated depending on the values of the various parameters.

--- See documentation for examples.

---

--- Parameters:

--- |episode_num=		— optional; The episode's number.

--- |season_num=		— optional; The season's number.

--- |season_num_uk=		— optional; The season's number if using the British "series" term.

--- |series_name=		— optional; The TV series name.

--- |not_dab=			— optional; Set if the TV series name has parentheses as part of its name.

--- |special=			— optional; Setting to "yes" will set the description as a "special episode".

---							Any other value will replace the word "special" with the one entered.

---							For example "special=recap" will create "recap episode".

---	|limited=			— optional; Set if the series is a single season series, such as miniseries or limited series

---							and does not need a season number as part of the description.

--- @param frame table The frame invoking the module.

function television.getShortDescription(frame)

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

	local args = getArgs(frame)

	return television._getShortDescription(frame, args)

end





--- Public function which is used for testing output only.

--- @param frame table The frame invoking the module.

function television.test(frame)

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

	local args = getArgs(frame)



	test = args.test

	local shortDescription, categories = television._getShortDescription(frame, args)



	if (test == "cat") then

		return categories

	else

		return shortDescription

	end

end



return television

Videos

Youtube | Vimeo | Bing

Websites

Google | Yahoo | Bing

Encyclopedia

Google | Yahoo | Bing

Facebook