Module:Television episode short description

-- This module requires the use of Module:ConvertNumeric. local convertNumeric = require('Module:ConvertNumeric')

-- Unique suffix list. local uniqueSuffix = { [1] = 'st', [2] = 'nd', [3] = 'rd', }

-- Common suffix. local commonSuffix = "th"

-- Tracking category list. local categoryList = { [1] = ,	[2] = ,	[3] = ,	[4] = ,	[5] = '', }

local p = {}

-- Local function which is used to return a relevant tracking category. local function createTrackingCategory(type) local namespace = mw.title.getCurrentTitle.nsText;													-- Get the invoking namespace. if (namespace == '' or namespace == 'Draft') then														-- Check if the invoking page is from the allowed namespace. return categoryList[type]																			-- Invoking page is from the allowed namespace; Retrieve the correct tracking category and return it. else return ''																							-- Invoking page is not from the allowed namespace; Return empty string. end end

-- Local function which is used to create a short description in the style of: "A television episode". -- Add article to the maintenance category:. local function getShortDescriptionNoValues return "A television episode", createTrackingCategory(1) end -- Local function which is used to create a short description in the style of: "An episode of Lost". -- Add article to the maintenance category:. local function getShortDescriptionNoEpisodeNoSeasonsValues(tvSeriesName) return "An episode of ''" .. tvSeriesName .. "''", createTrackingCategory(2) end

-- Local function which is used to create a short description in the style of: "An episode of the first season of Lost". -- Add article to the maintenance category:. local function getShortDescriptionNoEpisodeValue(seasonOrdinalNumber, tvSeriesName) return "An episode of the " .. seasonOrdinalNumber .. " season of ''" .. tvSeriesName .. "''", createTrackingCategory(3) end

-- Local function which is used to create a short description in the style of: "5th episode of the fourth season of Lost". -- Add article to the tracking category:. local function getShortDescriptionSingleEpisode(episodeOrdinalNumber, seasonOrdinalNumber, tvSeriesName) return episodeOrdinalNumber .. " episode of the " .. seasonOrdinalNumber .. " season of ''" .. tvSeriesName .. "''", createTrackingCategory(4) end

-- Local function which is used to create a short description for double episodes in the style of: "23rd and 24th episodes of the third season of Lost". -- Add article to the tracking category:. local function getShortDescriptionDoubleEpisode(episodeOrdinalNumber, secondEpisodeOrdinalNumber, seasonOrdinalNumber, tvSeriesName) return episodeOrdinalNumber .. " and " .. secondEpisodeOrdinalNumber .. " episodes of the " .. seasonOrdinalNumber .. " season of ''" .. tvSeriesName .. "''", createTrackingCategory(5) end

-- Local function which is used to retrieve the ordinal indicator for an integer between 0 and 100. local function getOrdinalIndicatorLessThan100(number) local suffix																							-- Variable to save the ordinal indicator suffix. while (suffix == nil) do																				-- Initiate a loop that goes on until a suffix has been found. if (number == 0) then																				-- Check if the number equals 0; This should never be a valid entry. suffix = ""																						-- Assign suffix as an empty string. elseif (number < 4) then																			-- Check if the number is less than 4; Numbers "1", "2" and "3" have unique suffixes. suffix = uniqueSuffix[number]																	-- It is; Get the unique suffix for that number and assign it. elseif (number < 20) then																			-- Check if the number is more than 4 AND less than 20; These numbers all have the same common suffix. suffix = commonSuffix																			-- It is; Assign suffix as the common suffix - "th". elseif (number % 10 == 0) then																		-- Check if the remainder after division of the number by 10 equals 0. suffix = commonSuffix																			-- It is; Assign suffix as the common suffix - "th". else																								-- Anything else - numbers that are above 20 and which their remainder doesn't equal 0 (such as 45). number = number % 10																			-- Save the new number to the remainder after division of the number by 100; -- So if the current number is 45, the new number be 5. end end return suffix																							-- Return the suffix. end

-- Local function which is used to retrieve the ordinal indicator for an integer between 0 and 1000. local function getOrdinalIndicatorLessThan1000(number) if (number < 100) then																					-- Check if the number is less than 100. -- The number is less than 100; return getOrdinalIndicatorLessThan100(number)														-- Call getOrdinalIndicatorLessThan100 to get the ordinal indicator and return it. elseif (number % 100 == 0) then																			-- Check if the remainder after division of the number by 100 equals 0. return commonSuffix																					-- It does; Return the common suffix - "th". else																									-- Anything else - numbers that are above 100 and which their remainder doesn't equal 0 (such as 345). return getOrdinalIndicatorLessThan100(number % 100)													-- Call getOrdinalIndicatorLessThan100 to get the ordinal indicator and return it; -- Pass the remainder after division of the number by 100 (So for 345, it would pass 45) as the parameter. end end

-- Local function which is used to create an ordinal number. local function getEpisodeOrdinalNumber(number) local ordinalIndicator = getOrdinalIndicatorLessThan1000(number)										-- Call getOrdinalIndicatorLessThan1000 to get the number's ordinal indicator. return number .. ordinalIndicator																		-- Create an ordinal number and return it. end

-- Local function which is used to validate if data was -- entered into a parameter of type number. local function validateNumberParam(number) if (tonumber(number) == nil) then																		-- Convert the string into a number and check if the value equals nil (conversion failed). return false																						-- Param is either empty or not a number; Return false. else																									-- Param is a number; return true																							-- Return true. end end

-- Local function which is used to return a clean version of the number. -- This is done to make sure that no malformed episode or 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"; -- "1 " -> "1" local function getCleanNumber(number) if (number ~= nil) then																					-- Check if the number is not null (some kind of value was entered). local cleanNumber = string.match(number, '%d+')														-- The value is not null; Clean the number, if needed. return cleanNumber																					-- Return the number. else return nil																							-- The number is nil; Return nil. end end

-- Local function which is used to create a short description -- by validating if a "multi_episodes" value was entered. local function createDescriptionValidateEpisodeValue(episodeNumberText, seasonOrdinalNumber, tvSeriesName, isDoubleEpisode) local episodeNumber = getCleanNumber(episodeNumberText)													-- Call getCleanNumber to return a cleaned version of the number. episodeNumber = tonumber(episodeNumber)																	-- Convert the value into a number. if (validateNumberParam(episodeNumber)) then															-- Call validateNumberParam to check if an episode number was entered. local episodeOrdinalNumber = getEpisodeOrdinalNumber(episodeNumber)									-- A number was entered; Call getEpisodeOrdinalNumber to get the episode ordinal number. if (isDoubleEpisode == nil) then																	-- Check if a multi_episodes value was entered. -- A multi_episodes value was not entered; return getShortDescriptionSingleEpisode(				episodeOrdinalNumber, seasonOrdinalNumber, tvSeriesName)									-- Call getShortDescriptionSingleEpisode to get the episode's short description and return it. else																								-- A multi_episodes value was entered; local secondEpisodeOrdinalNumber = getEpisodeOrdinalNumber(episodeNumber + 1)					-- Call getEpisodeOrdinalNumber and increment, to get the second episode ordinal number. return getShortDescriptionDoubleEpisode(				episodeOrdinalNumber, secondEpisodeOrdinalNumber, seasonOrdinalNumber, tvSeriesName)		-- Call getShortDescriptionDoubleEpisode to get the double episode's short description and return it. end else																									-- A an episode number was not entered; return getShortDescriptionNoEpisodeValue(seasonOrdinalNumber, tvSeriesName)							-- Call getShortDescriptionNoEpisodeValue to get the short description and return it. end end

-- Local function which is to validate that the value is a number and not a -- string with a number with a number in it (such as a ref with a URL). local function validateNumberParam(number) if (tonumber(number) == nil) then																		-- Check if the number value is an actual number return nil																							-- The value is not a number; Return nil. else return number																						-- The value is a number; Return the number. end end -- Local function which is to retrieve the season number, since it can be entered in -- either the "season" or "series_no" params. local function getSeasonNumber(seasonNumber, seasonNumberUK) seasonNumber = getCleanNumber(seasonNumber)																-- Call getCleanNumber to return a cleaned version of the number. seasonNumberUK = getCleanNumber(seasonNumberUK)															-- Call getCleanNumber to return a cleaned version of the number. seasonNumber = validateNumberParam(seasonNumber)														-- Call validateNumberParam to return the number or nil. seasonNumberUK = validateNumberParam(seasonNumberUK)													-- Call validateNumberParam to return the number or nil.

if (tonumber(seasonNumber) ~= nil) then																	-- Check if the value in the "|season_num" ("season") param is a number. return seasonNumber																					-- It is; Return value. elseif (tonumber(seasonNumberUK) ~= nil) then															-- Check if the value in the "|season_num_uk" ("series_no") param is a number. return seasonNumberUK																				-- It is; Return value. else																									-- Anything else - value not entered. return ""																							-- Return empty string. end end

-- Local function which is used to create a short description -- by validating if a season number was entered. local function createDescriptionValidateSeasonValue(episodeNumberText, seasonNumber, seasonNumberUK, tvSeriesName, isDoubleEpisode) seasonNumber = getSeasonNumber(seasonNumber, seasonNumberUK)											-- Call getSeasonNumber to get the season number, as it can be in one of two fields.

if (validateNumberParam(seasonNumber)) then																-- Call validateNumberParam to check if a season number was entered. -- A season number was entered; local seasonOrdinalNumber = convertNumeric.spell_number(											-- Call spell_number from Module:ConvertNumeric to get the season ordinal number.			seasonNumber,																					-- Pass it the season number.			nil,																							-- Not used here.			nil,																							-- Not used here.			false,																							-- Not used here.			false,																							-- Not used here.			false,																							-- Not used here.			true,																							-- Get the season ordinal number from the season number.			false,																							-- Not used here.			nil,																							-- Not used here.			nil,																							-- Not used here.			nil,																							-- Not used here.			nil,																							-- Not used here.			false)																							-- Not used here. return createDescriptionValidateEpisodeValue(episodeNumberText, 									-- Call createDescriptionValidateEpisodeValue to continue validation process.				seasonOrdinalNumber, tvSeriesName, isDoubleEpisode) else																									-- A season number was not entered; return getShortDescriptionNoEpisodeNoSeasonsValues(tvSeriesName)									-- Call getShortDescriptionNoEpisodeNoSeasonsValues to get the short description and return it. end end

-- Local function which is used to create a short description. -- This creates a description by a process of validating which values where entered -- into the Infobox and has the following options: -- If no TV series name was entered, it calls getShortDescriptionNoValues. -- If only the TV series name and season number were entered, it calls getShortDescriptionNoEpisodeValue. -- If all information was entered and it is a single episode, it calls getShortDescriptionSingleEpisode. -- If all information was entered and it is a double episode, it calls getShortDescriptionDoubleEpisode. local function createDescription(episodeNumberText, seasonNumber, seasonNumberUK, tvSeriesName, isDoubleEpisode, notDisambiguated) if (tvSeriesName ~= nil) then																			-- Check if a TV series name was entered.

if (notDisambiguated == nil) then																	-- A TV series name was entered; Check if a not_dab value was entered. tvSeriesName = string.gsub(tvSeriesName, "%s+%b$", "", 1, false)								-- A not_dab value was not entered; Get the article title without the disambiguation. end return createDescriptionValidateSeasonValue(episodeNumberText,										-- Call createDescriptionValidateSeasonValue to continue validation process.							seasonNumber, seasonNumberUK, tvSeriesName, isDoubleEpisode) else																									-- A TV series name was not entered; return getShortDescriptionNoValues																-- Call getShortDescriptionNoValues to get the short description and return it. end end

-- Local function which is used to clean the values from unwanted characters. local function cleanValues(args) for _, v in ipairs({'episode_num', 'season_num', 'season_num_uk', 'series_name'}) do		if args[v] then args[v] = args[v]:gsub('\127[^\127]*UNIQ%-%-(%a+)%-%x+%-QINU[^\127]*\127', '')					-- Remove all strip-markers. args[v] = args[v]:gsub('', ' ')														-- Replace (and variants) with space character. args[v] = args[v]:gsub('%b<>[^<]+%b<>', '')														-- Remove html markup. args[v] = args[v]:gsub('%b<>', '')																-- Remove self-closed html tags. args[v] = args[v]:gsub('%[%([^%+)%]%]', '%1')											-- Remove wiki-link retain label. args[v] = args[v]:gsub('%[%[([^%]]+)%]%]', '%1')												-- Remove wiki-link retain article. args[v] = args[v]:gsub('%[%S+ +([^%]]-)%]', '%1')												-- Remove URLs retain label. args[v] = args[v]:gsub('%^%-%]', '')														-- Remove all remaining URLs. if (args[v] == '') then																			-- Check if the value is an empty string. args[v] = nil																				-- The value is an empty string; Set it to nil. end end end return args																								-- Return args. end

-- Local function which does the actual main process. local function _getShortDescription(frame, args) args = cleanValues(args)																				-- Call cleanValues to remove all unwanted characters. local episodeNumberText = args['episode_num']															-- Get the episode number in text. local seasonNumber = args['season_num']																	-- Get the season number from the param. local seasonNumberUK = args['season_num_uk']															-- Get the season number if it's written in the "series_no" param. local tvSeriesName = args['series_name']																-- Get the TV series name. local isDoubleEpisode = args['multi_episodes']															-- Get the value of "multi_episodes" (used for episode consisting of two episodes). local notDisambiguated = args['not_dab']																-- Get the value of "not_dab" (used if the TV series name has parentheses as part of its name).

local test = args['test']																				-- This param should only be used by tests runned through Module:Television episode short description/testcases. local shortDescription, trackingCat = createDescription(		episodeNumberText, seasonNumber, seasonNumberUK, tvSeriesName, isDoubleEpisode, notDisambiguated)	-- Call createDescription and return two values: the episode's short description and tracking category. if (test == nil) then																					-- Check if the invoking page is a the /testcases. local tableData = {shortDescription, 'noreplace'}													-- Invoking page isn't a test; Create a table for the short description parameter. return frame:expandTemplate({title = 'short description', args = tableData}) .. trackingCat			-- Return expanded short description with tracking category. else return shortDescription																				-- Invoking page is a test; Return only short description. 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. -- -- This module function takes six 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. -- |multi_episodes= — optional; Set if the episode is a double episode. -- |not_dab= — optional; Set if the TV series name has parentheses as part of its name. function p.getShortDescription(frame) local getArgs = require('Module:Arguments').getArgs;													-- Use Module:Arguments to access module arguments. local args = getArgs(frame);																			-- Get the arguments sent via the template. return _getShortDescription(frame, args)																-- Call _getShortDescription to peform the actual process. end

return p