Модуль:Сезон сериала
Этот шаблон реализован на основе Lua:
|
Документацию смотри на странице шаблона {{Сезон сериала}}
См. также
правитьrequire('strict')
local listOfTitlesArticles = require('Модуль:Сезон сериала/БД списки эпизодов')
local wikidata = require('Модуль:Wikidata').formatProperty
local getArgs = require('Модуль:Arguments').getArgs
local yesno = require("Модуль:Yesno")
local format = mw.ustring.format
local match = mw.ustring.match
local find = mw.ustring.find
local gsub = mw.ustring.gsub
local sub = mw.ustring.sub
local p = {}
local cache = {}
--------------------------------------------------------------------------------
--- LOCALS
--------------------------------------------------------------------------------
--- Returns true if param has value (not nil and not empty string)
--- @param param string
--- @return boolean
local function hasValue(param)
if param and param:find('%S') then
return true
end
end
--- Returns true if page exist and not redirect
--- @param param string
--- @return boolean
local function hasPage(page)
if page and page.exists and page.redirectTarget ~= mw.title.getCurrentTitle() then
return true
end
return false
end
--- Returns a delinked string
--- @param link string
--- @return string
local function getPlainText(text)
local text = mw.text.trim(text, '%[%]%s'):gsub('<.->.-$', '')
if text:find('^{{нп')
or text:find('^%[%[нп')
or text:find('^{{')
then
text = mw.text.trim(text, '{}%[%]:%s')
text = text:gsub('^[^|]-|', '')
end
if text:find('^%[%[:') then
text = mw.text.trim(text, '{}%s')
text = text:gsub('^%[%[:[^:]-:', '')
end
text = text:gsub('%s*|.*$', '')
:gsub('%s*{.*$', '')
:gsub('<.->.-<.->', ' ')
:gsub('<.->', ' ')
:gsub('%s+', ' ')
text = mw.text.trim(text, '%s')
return text
end
--- 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 hasPage(listOfEpisodesPage) then
return format('[[%s|Список серий]]', 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)
local articleLink = mw.title.new(article, 0)
if hasPage(articleLink) then
if not hasValue(pipedLink) then
return '[[' .. article .. ']]'
end
return '[[' .. article .. '|' .. pipedLink .. ']]'
end
end
--- Returns the disambiguation without the '(year) TV series,' part.
--- @param disambiguation string The article's disambiguation.
--- @return string
local function getShortDisambiguation(disambiguation)
local shortDisambiguation = gsub(disambiguation, '^.+,%s*', '')
return shortDisambiguation
end
--- Returns the current season number from the disambiguation.
--- @param disambiguation string The article's disambiguation.
--- @return string
local function getCurrentSeasonNumberFromDisambiguation(disambiguation)
local commasText, shortDisambiguation, prefix, number, postfix
if match(disambiguation, '%d+[—%-]%d+') then
prefix, number, postfix = match(disambiguation, '^(%D*)(%d+%-?—?%d+)(%D*)$')
elseif disambiguation:find(', ') then
commasText = match(disambiguation, '^.+,%s*')
shortDisambiguation = getShortDisambiguation(disambiguation)
prefix, number, postfix = match(shortDisambiguation, '^(%D*)(%d+)(%D*)$')
else
prefix, number, postfix = match(disambiguation, '^(%D*)(%d+)(%D*)$')
end
postfix = postfix or ''
commasText = commasText or ''
prefix = commasText .. (prefix or '')
return number, prefix, postfix
end
--- Returns the type of word used for 'season' in the disambiguation.
--- @param disambiguation string The article's disambiguation.
--- @return string
local function getSeasonType(disambiguation)
local currentTitleText = mw.title.getCurrentTitle().text
local seasonTypes = {
'Мультсериал', 'Телесериал', 'Телепередача', 'Спецвыпуски', 'Телешоу',
'Шоу', 'Анимационный сериал', 'Аниме-сериал', 'Веб-сериал', 'Мини-сериал',
'Серии мультсериалов', 'Телевизионный сериал', 'Сюжетная арка', 'Выпуск',
'Сериал', 'Аниме', 'Серии', 'Сезоны', 'Сезона', 'Сезон', 'Серии с'
}
for _, seasonType in pairs(seasonTypes) do
if match(disambiguation, sub(seasonType, 3)) then
if find(currentTitleText, '^Список')
and not find(currentTitleText, '%d+[—%-]%d+')
then
if seasonType == 'Сезона' then
return 'Сезоны с'
elseif seasonType == 'Серии' then
return 'Серии с'
end
else
return seasonType
end
end
end
return 'Сезон'
end
--- Returns the disambiguation from the title.
--- @param title string The article's title.
--- @return string | nil, string | nil
local function getDisambiguation(title)
local disambiguationLast, disambiguationNext
local pattern = '%s*%(([^()]+)%)$'
disambiguationLast = match(title, pattern)
local title = gsub(title, pattern, '')
disambiguationNext = match(title, pattern)
if disambiguationLast ~= '' then
return disambiguationLast, disambiguationNext
end
end
--- Returns the show's name from the title.
--- @param title string The article's title.
--- @return string
local function getShowName(title)
while match(title, '%)%s*$') do
title = gsub(title, '%s+%b()%s*$', '')
end
return title
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.
--- @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 excludeList = {
'Американская история ужасов: Дом-убийца', 'Американская история ужасов: Психбольница',
'Американская история ужасов: Шабаш', 'Американская история ужасов: Фрик-шоу',
'Американская история ужасов: Отель', 'Американская история ужасов: Роанок',
'Американская история ужасов: Культ', 'Американская история ужасов: Апокалипсис',
'Американская история ужасов: 1984', 'Американская история ужасов: Двойной сеанс',
'Американская история ужасов: Нью-Йорк', 'Американская история ужасов: Нежность'
}
local iExcludeList = {
['Дом-убийца']=1, ['Психбольница']=2, ['Шабаш']=3, ['Фрик-шоу']=4,
['Отель']=5, ['Роанок']=6, ['Культ']=7, ['Апокалипсис']=8, ['1984']=9,
['Двойной сеанс']=10, ['Нью-Йорк']=11, ['Нежность']=12
}
local showName = getShowName(title)
local disambiguationLast, disambiguationNext = getDisambiguation(title)
if seasonNumberDiff == 0 and not hasValue(disambiguationLast) then
if title:find('мериканская история ужасов') then
return title, title:match(':%s*([^:]-)%s*$')
else
return title, nil
end
elseif not hasValue(disambiguationLast) then
if title:find('мериканская история ужасов') then
local index = iExcludeList[title:match(':%s*([^:]-)%s*$')]
local article = excludeList[index + seasonNumberDiff]
if article then
return article, article:match(':%s*([^:]-)%s*$')
else
return nil, nil
end
elseif not showName:find('%s+(%d+)$') then
return '', nil
end
end
if hasValue(disambiguationNext) then
disambiguationNext = ' (' .. disambiguationNext .. ')'
else
disambiguationNext = ''
end
local prefix, seasonType, seasonNumber, postfix
local shortDisambiguation, showNameModified
local pipedLink
if hasValue(disambiguationLast) then
seasonType = getSeasonType(disambiguationLast)
seasonNumber, prefix, postfix = getCurrentSeasonNumberFromDisambiguation(disambiguationLast)
pipedLink = seasonType
end
if not hasValue(seasonNumber) then
showNameModified, seasonNumber = match(showName, '(.+)%s+(%d+)$')
end
if tonumber(seasonNumber) then
seasonNumber = tonumber(seasonNumber) + seasonNumberDiff
end
seasonNumber = tostring(seasonNumber)
if hasValue(seasonNumber) and hasValue(pipedLink) then
pipedLink = pipedLink .. ' ' .. seasonNumber
elseif hasValue(seasonNumber) then
pipedLink = 'Сезон ' .. seasonNumber
end
-- Titles such as 'Big Brother 1 (American season)'.
if hasValue(showNameModified) and hasValue(disambiguationLast) then
return showNameModified .. ' ' .. seasonNumber .. ' (' .. disambiguationLast .. ')', pipedLink
-- Titles such as 'Big Brother Brasil 1'.
elseif hasValue(showNameModified) then
return showNameModified .. ' ' .. seasonNumber, pipedLink
else
return showName .. disambiguationNext .. ' (' .. prefix .. seasonNumber .. postfix .. ')', pipedLink
end
end
--- Returns the article's title either from args (usually from /testcases) or from the page itself.
--- @param args table The args invoking the module.
--- @return string
local function getTitle(title)
if not hasValue(title) then
title = mw.title.getCurrentTitle().text
end
return title
end
--- Returns 'true' if the given season link is valid; nil otherwise.
--- @param args table The args invoking the module.
--- @param seasonNumberDiff number The number difference between the current season and the other season.
--- @return string | nil
local function isSeasonLinkValid(args, seasonNumberDiff)
if yesno(args.link) == false then
return nil
end
if hasValue(args.link) and args.link:find('%[%[.*%]%]') then
return true
elseif hasValue(args.link) and isLinkValid(getPlainText(args.link)) then
return isLinkValid(getPlainText(args.link))
end
local title = getTitle(args.title)
local articleTitle = getArticleTitleAndPipedLink(title, seasonNumberDiff)
if hasValue(articleTitle) and articleTitle ~= mw.title.getCurrentTitle().fullText then
return isLinkValid(articleTitle)
end
end
--- Returns a season article link.
--- @param args table The args invoking the module.
--- @param seasonNumberDiff number The number difference between the current season and the other season.
--- @return string
local function getSeasonArticleLink(args, seasonNumberDiff)
if yesno(args.link) == false then
return nil
end
local title, articleTitle, pipedLink
if hasValue(args.link) and args.link:find('%[%[.*%]%]') then
return args.link
elseif hasValue(args.link) and isLinkValid(getPlainText(args.link)) then
articleTitle, pipedLink = getArticleTitleAndPipedLink(args.link, 0)
end
if not hasValue(articleTitle) then
title = getTitle(args.title)
articleTitle, pipedLink = getArticleTitleAndPipedLink(title, seasonNumberDiff)
end
if hasValue(articleTitle) and articleTitle ~= mw.title.getCurrentTitle().fullText then
return getArticleLink(articleTitle, pipedLink)
end
end
-- Декоратор для передачи аргуметнов в функцию
local function makeInvokeFunc(funcName)
return function (frame)
local args = getArgs(frame)
return p[funcName](args)
end
end
--------------------------------------------------------------------------------
--- MAIN CLASS
--------------------------------------------------------------------------------
-- Проверка Викидинных пока не реализована
-- Предыдущий сезон ### wikidata|P155
-- Следующий сезон ### wikidata|P156
-- ОБРАЗЕЦ: wikidata({args={{property='P1811', value='Список эпизодов телесериала «Во все тяжкие»', from='Q126004'}})
--- Returns 'true' if the season link for the next season is valid; nil otherwise.
--- @param args table The args invoking the module.
--- @return string | nil
p.isNextSeasonLinkValid = makeInvokeFunc('_isNextSeasonLinkValid')
function p._isNextSeasonLinkValid(args)
return isSeasonLinkValid(args, 1)
end
--- Returns 'true' if the season link for the previous season is valid; nil otherwise.
--- @param args table The args invoking the module.
--- @return string | nil
p.isPrevSeasonLinkValid = makeInvokeFunc('_isPrevSeasonLinkValid')
function p._isPrevSeasonLinkValid(args)
return isSeasonLinkValid(args, -1)
end
--- Returns the next season article title.
--- @param args table The args invoking the module.
--- @return string
p.getNextSeasonArticle = makeInvokeFunc('_getNextSeasonArticle')
function p._getNextSeasonArticle(args)
return getSeasonArticleLink(args, 1)
end
--- Returns the previous season article title.
--- @param args table The args invoking the module.
--- @return string
p.getPrevSeasonArticle = makeInvokeFunc('_getPrevSeasonArticle')
function p._getPrevSeasonArticle(args)
return getSeasonArticleLink(args, -1)
end
--- @param args table The args invoking the module.
--- @return string
p.getInfoboxHeader = makeInvokeFunc('_getInfoboxHeader')
function p._getInfoboxHeader(args)
local title = getTitle(args.title)
local header = getShowName(title)
return header
end
--- Returns the relevant text for the sub-header field.
--- @param args table The args invoking the module.
--- @return string | nil
p.getInfoboxSubHeader = makeInvokeFunc('_getInfoboxSubHeader')
function p._getInfoboxSubHeader(args)
local title = getTitle(args.title)
local disambiguation = getDisambiguation(title)
local seasonNumber = args.season_number or args.series_number
local seasonType, shortDisambiguation
if not hasValue(disambiguation) and not hasValue(seasonNumber) then
return nil
end
if not hasValue(seasonNumber) then
shortDisambiguation = getShortDisambiguation(disambiguation)
seasonNumber = getCurrentSeasonNumberFromDisambiguation(shortDisambiguation)
end
if hasValue(disambiguation) then
seasonType = getSeasonType(disambiguation)
end
if not hasValue(seasonType) and hasValue(seasonNumber) then
return 'Сезон ' .. seasonNumber
elseif hasValue(seasonNumber) then
return seasonType .. ' ' .. seasonNumber
end
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 args table The args invoking the module.
--- @return string | nil
p.getListOfEpisodes = makeInvokeFunc('_getListOfEpisodes')
function p._getListOfEpisodes(args)
--[=[== Схема-приоритет поиска рабочей ссылки типа [[Список эпизодов телесериала «Название»]] ==
args.link -> wikidata -> database -> zeronamespace -> nil
]=]
if find(mw.title.getCurrentTitle().text, '^Список')
or yesno(args.link) == false
then
return nil
end
-- Проверка args.link
if hasValue(args.link) and args.link:find('%[%[.*%]%]') then
return getListOfEpisodesLink(getPlainText(args.link))
elseif hasValue(args.link) and isLinkValid(getPlainText(args.link)) then
return getListOfEpisodesLink(args.link)
end
-- list of episodes (P1811)
-- ОБРАЗЕЦ: wikidata({args={{property='P1811', value='Список эпизодов телесериала «Во все тяжкие»', from='Q126004'}})
-- Проверка Викиданных
--[=[ ДОРАБОТАТЬ!!!!
local linkFromWikidata = wikidata({args={property='P1811', value='', from=args.from or '', title=args.title, link=args.link}})
if hasValue(linkFromWikidata) then
local wikidataLinkText = getPlainText(linkFromWikidata)
local wikidataLink = getListOfEpisodesLink(wikidataLinkText)
if hasValue(wikidataLink) then
return wikidataLink
end
end
]=]
-- Остальные проверки
local title = getTitle(args.title)
local showName = getShowName(title)
if not hasValue(showName) then return nil end
-- Проверка Базы данных
local showName2, shortShowName, shortShowName2 = '~', '~', '~'
if showName:find('[«"]') then
showName2 = showName:gsub('«', '„'):gsub('»', '“')
shortShowName = match(showName, '[«"](.-)["»]')
end
if showName:find('[:.]') then
shortShowName2 = showName:gsub('[:.].-$', '')
end
local findedName1, findedName2, findedName3, findedName4
local pattern, articleText, databaseLink
for _, searchName in ipairs({shortShowName2, showName2, shortShowName, showName}) do
pattern = format('{{([^{«]+[« ]%s[ »][^»}]*)}}', searchName)
articleText = match(listOfTitlesArticles, pattern)
if hasValue(articleText) then
databaseLink = getListOfEpisodesLink(articleText)
if hasValue(databaseLink) then
return databaseLink
end
end
end
-- Проверка основного пространства имён википедии
local listOfEpisodesArticle, listOfEpisodesLink
local listOfShowNames = {showName, showName2, shortShowName, shortShowName2}
--- ??? работает ли кэш ???
for _, showTitle in pairs(listOfShowNames) do
if cache[showTitle] then
return cache[showTitle]
end
end
local listOfAllTypes = {
'серий', 'эпизодов', 'выпусков',
'серий телесериала', 'эпизодов телесериала', 'серий телесериала', 'эпизодов сериала',
'серий мультсериала', 'эпизодов мультсериала', 'серий аниме', 'эпизодов аниме',
'эпизодов телепередачи', 'эпизодов шоу', 'выпусков телепередачи', 'выпусков телешоу'
-- не используются:
-- 'выпусков шоу', 'серий сериала', 'серий телепередачи', 'серий телешоу', 'серий шоу',
-- 'эпизодов анимационного сериала', 'эпизодов аниме-сериала', 'эпизодов веб-сериала', 'эпизодов мини-сериала'
}
for _, insertThis in pairs(listOfAllTypes) do
for _, showTitle in pairs(listOfShowNames) do
listOfEpisodesArticle = format('Список %s «%s»', insertThis, showTitle)
listOfEpisodesLink = getListOfEpisodesLink(listOfEpisodesArticle)
if listOfEpisodesLink then
--- ??? работает ли кэш ???
cache[showTitle] = listOfEpisodesLink
return listOfEpisodesLink
end
listOfEpisodesArticle = format('Список %s %s', insertThis, showTitle)
listOfEpisodesLink = getListOfEpisodesLink(listOfEpisodesArticle)
if listOfEpisodesLink then
--- ??? работает ли кэш ???
cache[showTitle] = listOfEpisodesLink
return listOfEpisodesLink
end
end
end
end
return p