Модуль:FetchData: відмінності між версіями

1216 байтів вилучено ,  У неділю о 01:16
нема опису редагування
Немає опису редагування
Немає опису редагування
Рядок 2: Рядок 2:


-- ================================================
-- ================================================
-- КЕШУВАННЯ (найважливіша оптимізація)
-- КЕШУВАННЯ
-- ================================================
-- ================================================


Рядок 12: Рядок 12:
         return page_cache[page_name]
         return page_cache[page_name]
     end
     end
   
 
     local title = mw.title.new(page_name)
     local title = mw.title.new(page_name)
     if not title or not title.exists then
     if not title or not title.exists then
Рядок 18: Рядок 18:
         return nil
         return nil
     end
     end
   
 
     local content = title:getContent()
     local content = title:getContent()
     page_cache[page_name] = content
     page_cache[page_name] = content
Рядок 28: Рядок 28:
         return table_cache[page_name]
         return table_cache[page_name]
     end
     end
   
 
     local content = get_page_content(page_name)
     local content = get_page_content(page_name)
     if not content then  
     if not content then
         table_cache[page_name] = nil
         table_cache[page_name] = nil
         return nil  
         return nil
     end
     end
   
 
     local table_start = mw.ustring.find(content, "{|")
     local table_start = mw.ustring.find(content, "{|")
     local table_end = mw.ustring.find(content, "|}", table_start)
     local table_end = mw.ustring.find(content, "|}", table_start)
   
 
     if not table_start or not table_end then
     if not table_start or not table_end then
         table_cache[page_name] = nil
         table_cache[page_name] = nil
         return nil
         return nil
     end
     end
   
 
     local table_content = mw.ustring.sub(content, table_start, table_end + 1)
     local table_content = mw.ustring.sub(content, table_start, table_end + 1)
     table_cache[page_name] = table_content
     table_cache[page_name] = table_content
Рядок 49: Рядок 49:


-- ================================================
-- ================================================
-- УТИЛІТИ (спільні для всіх функцій)
-- УТИЛІТИ
-- ================================================
-- ================================================


local function error_output(context, error_details)
local function error_output(context, error_details)
     local safe_details = error_details or "N/A"
     local safe_details = error_details or "N/A"
     return string.format("<span style='color:red; font-weight:bold;'>[Error: %s. Details: %s]</span>",  
     return string.format("<span style='color:red; font-weight:bold;'>[Error: %s. Details: %s]</span>",
         context or "Unknown", safe_details)
         context or "Unknown", safe_details)
end
end


-- ШВИДКА ВЕРСІЯ: патерни тільки з ASCII-символів, тому string.gsub безпечний
local function clean_wikilinks(text)
local function clean_wikilinks(text)
     if not text then return nil end
     if not text then return nil end
     text = mw.ustring.gsub(text, "%[%[([^%]|]+)|([^%]]+)%]%]", "%2")
     text = string.gsub(text, "%[%[([^%]|]+)|([^%]]+)%]%]", "%2")
     text = mw.ustring.gsub(text, "%[%[([^%]]+)%]%]", "%1")
     text = string.gsub(text, "%[%[([^%]]+)%]%]", "%1")
     return mw.text.trim(text)
     return mw.text.trim(text)
end
end
Рядок 86: Рядок 87:
local function parse_row_cells(row)
local function parse_row_cells(row)
     local cells = {}
     local cells = {}
   
 
     for line in mw.ustring.gmatch(row, "[^\n]+") do
     for line in mw.ustring.gmatch(row, "[^\n]+") do
         line = mw.text.trim(line)
         line = mw.text.trim(line)
       
 
         if line ~= "|-" and line ~= "" then
         if line ~= "|-" and line ~= "" then
             line = mw.ustring.gsub(line, "^|%s*", "")
             line = mw.ustring.gsub(line, "^|%s*", "")
           
 
             if line ~= "" then
             if line ~= "" then
                 table.insert(cells, line)
                 table.insert(cells, line)
Рядок 98: Рядок 99:
         end
         end
     end
     end
   
 
     return cells
     return cells
end
end
Рядок 104: Рядок 105:
local function find_player_in_table(table_content, player_name, column_index)
local function find_player_in_table(table_content, player_name, column_index)
     if not table_content then return nil end
     if not table_content then return nil end
   
 
     local escaped = mw.ustring.gsub(player_name, "([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1")
     local escaped = mw.ustring.gsub(player_name, "([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1")
     local player_pattern = "%[%[" .. escaped .. "%]%]"
     local player_pattern = "%[%[" .. escaped .. "%]%]"
   
 
     local rows = parse_table_rows(table_content)
     local rows = parse_table_rows(table_content)
   
 
     for _, row in ipairs(rows) do
     for _, row in ipairs(rows) do
         if mw.ustring.find(row, player_pattern) then
         if mw.ustring.find(row, player_pattern) then
Рядок 119: Рядок 120:
         end
         end
     end
     end
   
 
     return nil
     return nil
end
end


-- ================================================
-- ================================================
-- FETCHDATA (season_result)
-- SEASON RESULT
-- ================================================
-- ================================================


Рядок 130: Рядок 131:
     local season = frame.args.season
     local season = frame.args.season
     local player = frame.args.player
     local player = frame.args.player
   
 
     local season_titles = {
     local season_titles = {
         "Перший сезон", "Другий сезон", "Третій сезон",
         "Перший сезон", "Другий сезон", "Третій сезон",
         "Четвертий сезон", "П'ятий сезон", "Шостий сезон",  
         "Четвертий сезон", "П'ятий сезон", "Шостий сезон",
         "Сьомий сезон", "Восьмий сезон", "Дев'ятий сезон"
         "Сьомий сезон", "Восьмий сезон", "Дев'ятий сезон"
     }
     }
   
 
     local season_title = season_titles[tonumber(season)]
     local season_title = season_titles[tonumber(season)]
     if not season_title then return "??" end
     if not season_title then return "??" end
   
 
     local content = get_page_content(season_title)
     local content = get_page_content(season_title)
     if not content then return "??" end
     if not content then return "??" end
   
 
     local rating_section = mw.ustring.match(content, "==%s*Рейтинг%s*==.-{|%s*class%s*=%s*\"wikitable sortable\"(.-)|}")
     local rating_section = mw.ustring.match(content, "==%s*Рейтинг%s*==.-{|%s*class%s*=%s*\"wikitable sortable\"(.-)|}")
     if not rating_section then return "--" end
     if not rating_section then return "--" end
   
 
     local pattern = "|%s*(%d+)%s*|%s*%[%[" .. mw.ustring.gsub(player, "([%(%)%.%-%+%[%]])", "%%%1") .. "%]%]"
     local pattern = "|%s*(%d+)%s*|%s*%[%[" .. mw.ustring.gsub(player, "([%(%)%.%-%+%[%]])", "%%%1") .. "%]%]"
     local direct_pattern = "|%s*(%d+)%s*|%s*" .. mw.ustring.gsub(player, "([%(%)%.%-%+%[%]])", "%%%1") .. "%s*"
     local direct_pattern = "|%s*(%d+)%s*|%s*" .. mw.ustring.gsub(player, "([%(%)%.%-%+%[%]])", "%%%1") .. "%s*"
   
 
     local rank = mw.ustring.match(rating_section, pattern) or mw.ustring.match(rating_section, direct_pattern)
     local rank = mw.ustring.match(rating_section, pattern) or mw.ustring.match(rating_section, direct_pattern)
   
 
     return rank or "--"
     return rank or "--"
end
end


-- ================================================
-- ================================================
-- FETCHDATA2 (базова статистика)
-- БАЗОВА СТАТИСТИКА
-- ================================================
-- ================================================


Рядок 161: Рядок 162:
     local player_name = frame.args.player
     local player_name = frame.args.player
     if not player_name or player_name == "" then return "0" end
     if not player_name or player_name == "" then return "0" end
   
 
     local result = find_player_in_table(get_table_from_page("Статистика"), player_name, 2)
     local result = find_player_in_table(get_table_from_page("Статистика"), player_name, 2)
     return result or "0"
     return result or "0"
Рядок 169: Рядок 170:
     local player_name = frame.args.player
     local player_name = frame.args.player
     if not player_name or player_name == "" then return "0" end
     if not player_name or player_name == "" then return "0" end
   
 
     local result = find_player_in_table(get_table_from_page("Статистика"), player_name, 3)
     local result = find_player_in_table(get_table_from_page("Статистика"), player_name, 3)
     return result or "0"
     return result or "0"
Рядок 177: Рядок 178:
     local player_name = frame.args.player
     local player_name = frame.args.player
     if not player_name or player_name == "" then return "0" end
     if not player_name or player_name == "" then return "0" end
   
 
     local result = find_player_in_table(get_table_from_page("Статистика"), player_name, 4)
     local result = find_player_in_table(get_table_from_page("Статистика"), player_name, 4)
     return result or "0"
     return result or "0"
Рядок 185: Рядок 186:
     local player_name = frame.args.player
     local player_name = frame.args.player
     if not player_name or player_name == "" then return "0%" end
     if not player_name or player_name == "" then return "0%" end
   
 
     local win_rate = find_player_in_table(get_table_from_page("Статистика"), player_name, 5)
     local win_rate = find_player_in_table(get_table_from_page("Статистика"), player_name, 5)
     if not win_rate then return "0%" end
     if not win_rate then return "0%" end
   
 
     local rate_num = tonumber(mw.ustring.match(win_rate, "([%d%.]+)"))
     local rate_num = tonumber(mw.ustring.match(win_rate, "([%d%.]+)"))
     if not rate_num then return win_rate end
     if not rate_num then return win_rate end
   
 
     local color = "#4caf50"
     local color = "#4caf50"
     if rate_num < 40 then
     if rate_num < 40 then
Рядок 198: Рядок 199:
         color = "orange"
         color = "orange"
     end
     end
   
 
     if not mw.ustring.find(win_rate, "%%") then
     if not mw.ustring.find(win_rate, "%%") then
         win_rate = win_rate .. "%"
         win_rate = win_rate .. "%"
     end
     end
   
 
     return string.format('<span style="color:%s;">%s</span>', color, win_rate)
     return string.format('<span style="color:%s;">%s</span>', color, win_rate)
end
end
Рядок 209: Рядок 210:
     local player_name = frame.args.player
     local player_name = frame.args.player
     if not player_name or player_name == "" then return "Не вказано" end
     if not player_name or player_name == "" then return "Не вказано" end
   
 
     local table_content = get_table_from_page("Гравці")
     local table_content = get_table_from_page("Гравці")
     if not table_content then return "Не вказано" end
     if not table_content then return "Не вказано" end
   
 
     local cells = find_player_in_table(table_content, player_name)
     local cells = find_player_in_table(table_content, player_name)
     if not cells or #cells < 2 then return "Не вказано" end
     if not cells or #cells < 2 then return "Не вказано" end
   
 
     local raw = mw.text.trim(cells[2])
     local raw = mw.text.trim(cells[2])
     if raw == "Відсутній" or raw == "-" or raw == "" then  
     if raw == "Відсутній" or raw == "-" or raw == "" then
         return "Не вказано"  
         return "Не вказано"
     end
     end
   
 
     return raw
     return raw
end
end
Рядок 227: Рядок 228:
     local player_name = frame.args.player
     local player_name = frame.args.player
     if not player_name or player_name == "" then return "Лише Бог знає" end
     if not player_name or player_name == "" then return "Лише Бог знає" end
   
 
     local raw = find_player_in_table(get_table_from_page("Гравці"), player_name, 3)
     local raw = find_player_in_table(get_table_from_page("Гравці"), player_name, 3)
   
 
     if not raw or raw == "" or raw == "-" or raw == "Відсутній" then
     if not raw or raw == "" or raw == "-" or raw == "Відсутній" then
         return "Лише Бог знає"
         return "Лише Бог знає"
     end
     end
   
 
     local day, month, year = mw.ustring.match(raw, "(%d+)%.(%d+)%.(%d+)")
     local day, month, year = mw.ustring.match(raw, "(%d+)%.(%d+)%.(%d+)")
   
 
     if day and month and year then
     if day and month and year then
         local end_date = os.time({year=2024, month=12, day=1})
         local end_date = os.time({year=2024, month=12, day=1})
         local start_date = os.time({year=tonumber(year), month=tonumber(month), day=tonumber(day)})
         local start_date = os.time({year=tonumber(year), month=tonumber(month), day=tonumber(day)})
         local days_diff = math.floor((end_date - start_date) / 86400)
         local days_diff = math.floor((end_date - start_date) / 86400)
       
 
         return string.format("%s (%d днів)", raw, days_diff)
         return string.format("%s (%d днів)", raw, days_diff)
     end
     end
   
 
     return "Лише Бог знає"
     return "Лише Бог знає"
end
end
Рядок 250: Рядок 251:
     local player_name = frame.args.player
     local player_name = frame.args.player
     if not player_name or player_name == "" then return "0₴" end
     if not player_name or player_name == "" then return "0₴" end
   
 
     local raw = find_player_in_table(get_table_from_page("Фундація"), player_name, 2)
     local raw = find_player_in_table(get_table_from_page("Фундація"), player_name, 2)
   
 
     if not raw or raw == "" or raw == "-" then return "0₴" end
     if not raw or raw == "" or raw == "-" then return "0₴" end
   
 
     raw = mw.ustring.gsub(raw, "[^%d%s]", "")
     raw = mw.ustring.gsub(raw, "[^%d%s]", "")
     raw = mw.text.trim(raw)
     raw = mw.text.trim(raw)
   
 
     return (raw or "0") .. " ₴"
     return (raw or "0") .. " ₴"
end
end
Рядок 264: Рядок 265:
     local player_name = frame.args.player
     local player_name = frame.args.player
     if not player_name or player_name == "" then return "0₴" end
     if not player_name or player_name == "" then return "0₴" end
   
 
     local raw = find_player_in_table(get_table_from_page("Призовий_фонд"), player_name, 2)
     local raw = find_player_in_table(get_table_from_page("Призовий_фонд"), player_name, 2)
   
 
     if not raw or raw == "" or raw == "-" then return "0₴" end
     if not raw or raw == "" or raw == "-" then return "0₴" end
   
 
     raw = mw.ustring.gsub(raw, "[^%d%s]", "")
     raw = mw.ustring.gsub(raw, "[^%d%s]", "")
     raw = mw.text.trim(raw)
     raw = mw.text.trim(raw)
   
 
     return (raw or "0") .. " ₴"
     return (raw or "0") .. " ₴"
end
end
Рядок 278: Рядок 279:
     local player_name = frame.args.player
     local player_name = frame.args.player
     if not player_name or player_name == "" then return "0/9" end
     if not player_name or player_name == "" then return "0/9" end
   
 
     local raw = find_player_in_table(get_table_from_page("Фіналіст"), player_name, 2)
     local raw = find_player_in_table(get_table_from_page("Фіналіст"), player_name, 2)
   
 
     if not raw or raw == "" or raw == "-" then return "0/9" end
     if not raw or raw == "" or raw == "-" then return "0/9" end
   
 
     local number_only = mw.ustring.gsub(raw, "[^%d]", "")
     local number_only = mw.ustring.gsub(raw, "[^%d]", "")
     local count = tonumber(number_only)
     local count = tonumber(number_only)
   
 
     if count then
     if count then
         return string.format("%d/9", count)
         return string.format("%d/9", count)
     end
     end
   
 
     return "0/9"
     return "0/9"
end
end
Рядок 296: Рядок 297:
     local player_name = frame.args.player
     local player_name = frame.args.player
     if not player_name or player_name == "" then return "—" end
     if not player_name or player_name == "" then return "—" end
   
 
     local content = get_page_content("Період")
     local content = get_page_content("Період")
     if not content then return "—" end
     if not content then return "—" end
   
 
     local foty_section = mw.ustring.match(content, "==+%s*Фінал Року%s*==+(.-)\n==")
     local foty_section = mw.ustring.match(content, "==+%s*Фінал Року%s*==+(.-)\n==")
     if not foty_section then
     if not foty_section then
         foty_section = mw.ustring.match(content, "==+%s*Фінал Року%s*==+(.*)")
         foty_section = mw.ustring.match(content, "==+%s*Фінал Року%s*==+(.*)")
     end
     end
   
 
     if not foty_section then return "—" end
     if not foty_section then return "—" end
   
 
     local table_start = mw.ustring.find(foty_section, "{|")
     local table_start = mw.ustring.find(foty_section, "{|")
     local table_end = mw.ustring.find(foty_section, "|}", table_start)
     local table_end = mw.ustring.find(foty_section, "|}", table_start)
   
 
     if not table_start or not table_end then return "—" end
     if not table_start or not table_end then return "—" end
   
 
     local table_content = mw.ustring.sub(foty_section, table_start, table_end + 1)
     local table_content = mw.ustring.sub(foty_section, table_start, table_end + 1)
     local cells = find_player_in_table(table_content, player_name)
     local cells = find_player_in_table(table_content, player_name)
   
 
     if not cells or #cells < 3 then return "—" end
     if not cells or #cells < 3 then return "—" end
   
 
     local place = strip_html_tags(cells[1]) or "—"
     local place = strip_html_tags(cells[1]) or "—"
     local rating = strip_html_tags(cells[3]) or "—"
     local rating = strip_html_tags(cells[3]) or "—"
   
 
     rating = mw.ustring.gsub(rating, "[^%d%-]", "")
     rating = mw.ustring.gsub(rating, "[^%d%-]", "")
     rating = mw.text.trim(rating)
     rating = mw.text.trim(rating)
   
 
     if rating and rating ~= "" then
     if rating and rating ~= "" then
         return rating .. " (" .. place .. " місце)"
         return rating .. " (" .. place .. " місце)"
     end
     end
   
 
     return "—"
     return "—"
end
end


-- ================================================
-- ================================================
-- FETCHDATA3 (титули та нагороди)
-- ТИТУЛИ ТА НАГОРОДИ
-- ================================================
-- ================================================


Рядок 379: Рядок 380:
     if not value or value == "" or value == " " then return nil end
     if not value or value == "" or value == " " then return nil end
     value = mw.text.trim(value)
     value = mw.text.trim(value)
   
 
     if value == "" then return nil
     if value == "" then return nil
     elseif value == "1" then return "[[Файл:Gold.png|20px|link=]]"
     elseif value == "1" then return "[[Файл:Gold.png|20px|link=]]"
Рядок 400: Рядок 401:
         season_num = mw.ustring.match(header_name, "([А-Яа-яЁёІіЇїЄєҐґ']+) сезон %(рейтинг%)")
         season_num = mw.ustring.match(header_name, "([А-Яа-яЁёІіЇїЄєҐґ']+) сезон %(рейтинг%)")
     end
     end
   
 
     if season_num then
     if season_num then
         local season_map = {
         local season_map = {
Рядок 407: Рядок 408:
             ["Сьомий"] = 7, ["Восьмий"] = 8, ["Дев'ятий"] = 9
             ["Сьомий"] = 7, ["Восьмий"] = 8, ["Дев'ятий"] = 9
         }
         }
       
 
         local season_number = season_map[season_num]
         local season_number = season_map[season_num]
         if season_number then
         if season_number then
Рядок 415: Рядок 416:
             clean_name = mw.ustring.gsub(clean_name, "%s*%(рейтинг%)%s*", "")
             clean_name = mw.ustring.gsub(clean_name, "%s*%(рейтинг%)%s*", "")
             clean_name = mw.text.trim(clean_name)
             clean_name = mw.text.trim(clean_name)
           
 
             return string.format("[[%s|%s сезон. %s]]", clean_name, roman, type_text)
             return string.format("[[%s|%s сезон. %s]]", clean_name, roman, type_text)
         end
         end
     end
     end
   
 
     return string.format("[[%s]]", header_name)
     return string.format("[[%s]]", header_name)
end
end
Рядок 426: Рядок 427:
     local table_content = get_table_from_page(page_title)
     local table_content = get_table_from_page(page_title)
     if not table_content then return nil end
     if not table_content then return nil end
   
 
     local first_row = mw.ustring.match(table_content, "{|[^\n]*\n!(.-)[\n]")
     local first_row = mw.ustring.match(table_content, "{|[^\n]*\n!(.-)[\n]")
     local headers = {}
     local headers = {}
   
 
     if first_row then
     if first_row then
         for header in mw.ustring.gmatch(first_row, "([^|]+)") do
         for header in mw.ustring.gmatch(first_row, "([^|]+)") do
Рядок 438: Рядок 439:
         end
         end
     end
     end
   
 
     if #headers == 0 then return nil end
     if #headers == 0 then return nil end
   
 
     local cells = find_player_in_table(table_content, player_name)
     local cells = find_player_in_table(table_content, player_name)
     if not cells then return nil end
     if not cells then return nil end
   
 
     return {headers = headers, cells = cells}
     return {headers = headers, cells = cells}
end
end
-- ================================================
-- PLAYER IMAGE (автовибір аватара)
-- ================================================


function p.player_image(frame)
function p.player_image(frame)
Рядок 455: Рядок 452:
     local player_file = "Player_" .. nickname .. ".png"
     local player_file = "Player_" .. nickname .. ".png"
     local placeholder = "MCC_Placeholder.png"
     local placeholder = "MCC_Placeholder.png"
   
 
     local title = mw.title.new("File:" .. player_file)
     local title = mw.title.new("File:" .. player_file)
   
 
     local file_to_use
     local file_to_use
     if title and title.exists then
     if title and title.exists then
Рядок 464: Рядок 461:
         file_to_use = placeholder
         file_to_use = placeholder
     end
     end
   
 
     return string.format("[[File:%s|none|alt=Фотографія гравця|center|360px]]", file_to_use)
     return string.format("[[File:%s|none|alt=Фотографія гравця|center|360px]]", file_to_use)
end
end
Рядок 471: Рядок 468:
     local name = frame.args.player
     local name = frame.args.player
     if not name or name == "" then return "''Відсутні''" end
     if not name or name == "" then return "''Відсутні''" end
   
 
     local titles_data = get_player_row("Титули", name)
     local titles_data = get_player_row("Титули", name)
     if not titles_data then return "''Відсутні''" end
     if not titles_data then return "''Відсутні''" end
   
 
     local prize_data = get_player_row("Призові", name)
     local prize_data = get_player_row("Призові", name)
     if not prize_data then return error_output("Prize Data Missing", name) end
     if not prize_data then return error_output("Prize Data Missing", name) end
   
 
     local results = {}
     local results = {}
   
 
     for i = 2, #titles_data.cells do
     for i = 2, #titles_data.cells do
         local cell_value = titles_data.cells[i]
         local cell_value = titles_data.cells[i]
         local header = titles_data.headers[i]
         local header = titles_data.headers[i]
         local prize_value = prize_data.cells[i]
         local prize_value = prize_data.cells[i]
       
 
         if cell_value and cell_value ~= "" and cell_value ~= "-" and header then
         if cell_value and cell_value ~= "" and cell_value ~= "-" and header then
             local medal = get_medal_icon(cell_value)
             local medal = get_medal_icon(cell_value)
           
 
             if medal then
             if medal then
                 local prize_amount = "0 ₴"
                 local prize_amount = "0 ₴"
               
 
                 if prize_value and prize_value ~= "" and prize_value ~= "-" then
                 if prize_value and prize_value ~= "" and prize_value ~= "-" then
                     prize_value = mw.ustring.gsub(prize_value, "₴", "")
                     prize_value = mw.ustring.gsub(prize_value, "₴", "")
Рядок 498: Рядок 495:
                     end
                     end
                 end
                 end
               
 
                 local date = tournament_dates[header] or "01.01.2023"
                 local date = tournament_dates[header] or "01.01.2023"
                 local tournament_link = get_tournament_link(header)
                 local tournament_link = get_tournament_link(header)
               
 
                 table.insert(results, {
                 table.insert(results, {
                     date = date,
                     date = date,
Рядок 511: Рядок 508:
         end
         end
     end
     end
   
 
     if #results == 0 then return "''Відсутні''" end
     if #results == 0 then return "''Відсутні''" end
   
 
     local table_html = {
     local table_html = {
         '{| class="wikitable sortable" style="font-size: 14.5px;"',
         '{| class="wikitable sortable" style="font-size: 14.5px;"',
Рядок 521: Рядок 518:
         '! style="text-align: left;" | Приз'
         '! style="text-align: left;" | Приз'
     }
     }
   
 
     for _, result in ipairs(results) do
     for _, result in ipairs(results) do
         table.insert(table_html, '|-')
         table.insert(table_html, '|-')
Рядок 529: Рядок 526:
         ))
         ))
     end
     end
   
 
     table.insert(table_html, '|}')
     table.insert(table_html, '|}')
     return table.concat(table_html, '\n')
     return table.concat(table_html, '\n')
Рядок 535: Рядок 532:


-- ================================================
-- ================================================
-- FETCHDATA4 (цікаві факти)
-- ЦІКАВІ ФАКТИ
-- ================================================
-- ================================================


Рядок 554: Рядок 551:
     local content = get_page_content(page_title)
     local content = get_page_content(page_title)
     if not content then return nil end
     if not content then return nil end
   
 
     local section_start = mw.ustring.find(content, "==%s*[Цц]ікаві%s*[Фф]акти%s*==")
     local section_start = mw.ustring.find(content, "==%s*[Цц]ікаві%s*[Фф]акти%s*==")
     if not section_start then return nil end
     if not section_start then return nil end
   
 
     local section_end = mw.ustring.find(content, "\n==[^=]", section_start + 1)
     local section_end = mw.ustring.find(content, "\n==[^=]", section_start + 1)
   
 
     local section_content
     local section_content
     if section_end then
     if section_end then
Рядок 566: Рядок 563:
         section_content = mw.ustring.sub(content, section_start)
         section_content = mw.ustring.sub(content, section_start)
     end
     end
   
 
     return section_content
     return section_content
end
end
Рядок 574: Рядок 571:
     local pattern1 = "%[%[" .. escaped_name .. "%]%]"
     local pattern1 = "%[%[" .. escaped_name .. "%]%]"
     local pattern2 = "%[%[" .. escaped_name .. "|[^%]]+%]%]"
     local pattern2 = "%[%[" .. escaped_name .. "|[^%]]+%]%]"
   
 
     return mw.ustring.find(fact, pattern1) or mw.ustring.find(fact, pattern2)
     return mw.ustring.find(fact, pattern1) or mw.ustring.find(fact, pattern2)
end
end
Рядок 588: Рядок 585:
function p.facts(frame)
function p.facts(frame)
     local player_name = frame.args.player or frame.args[1] or mw.title.getCurrentTitle().text
     local player_name = frame.args.player or frame.args[1] or mw.title.getCurrentTitle().text
   
 
     local result_parts = {}
     local result_parts = {}
   
 
     for _, page_title in ipairs(pages_to_search) do
     for _, page_title in ipairs(pages_to_search) do
         local section = get_facts_section(page_title)
         local section = get_facts_section(page_title)
       
 
         if section then
         if section then
             local facts = extract_facts(section)
             local facts = extract_facts(section)
             local player_facts = {}
             local player_facts = {}
           
 
             for _, fact in ipairs(facts) do
             for _, fact in ipairs(facts) do
                 if fact_contains_player(fact, player_name) then
                 if fact_contains_player(fact, player_name) then
Рядок 603: Рядок 600:
                 end
                 end
             end
             end
           
 
             if #player_facts > 0 then
             if #player_facts > 0 then
                 local block = string.format("==== %s ====\n", page_title)
                 local block = string.format("==== %s ====\n", page_title)
Рядок 613: Рядок 610:
         end
         end
     end
     end
   
 
     if #result_parts == 0 then return "" end
     if #result_parts == 0 then return "" end
   
 
     return table.concat(result_parts, "\n")
     return table.concat(result_parts, "\n")
end
end


-- ================================================
-- ================================================
-- FETCHDATA5 (записи ігор) - З РОЛЛЮ ГРАВЦЯ
-- ЗАПИСИ ІГОР
-- ================================================
-- ================================================


Рядок 627: Рядок 624:
         return "Невідомо"
         return "Невідомо"
     end
     end
   
 
     if short_name == "Фанова гра" then
     if short_name == "Фанова гра" then
         return "Фанова гра"
         return "Фанова гра"
     end
     end
   
 
     if full_name then
     if full_name then
         full_name = clean_wikilinks(full_name)
         full_name = clean_wikilinks(full_name)
     end
     end
   
 
     if full_name and full_name ~= "" and full_name ~= short_name then
     if full_name and full_name ~= "" and full_name ~= short_name then
         return "[[" .. full_name .. "|" .. short_name .. "]]"
         return "[[" .. full_name .. "|" .. short_name .. "]]"
Рядок 643: Рядок 640:
end
end


local function parse_games_table_rows(table_content)
local function parse_games_row_cells(row)
    local cells = {}
    row = string.gsub(row, "^%s*|%s*", "")
    for cell in string.gmatch(row .. "||", "(.-)%s*||%s*") do
        table.insert(cells, mw.text.trim(cell))
    end
    return cells
end
 
-- Кеш: таблиця розбирається ОДИН раз на сторінку
local games_rows_cache = nil
local player_games_cache = {}
 
local function get_games_rows()
    if games_rows_cache then return games_rows_cache end
 
    local table_content = get_table_from_page("Ігри")
    if not table_content then return nil end
 
     local rows = {}
     local rows = {}
   
     for row in string.gmatch(table_content, "|-\n([^\n]+)") do
     for row in mw.ustring.gmatch(table_content, "|-\n([^\n]+)") do
         if not string.match(row, "^%s*!") then
         if not mw.ustring.match(row, "^%s*!") then
             local cells = parse_games_row_cells(row)
             table.insert(rows, row)
            if #cells >= 17 then
                local names = {}
                for i = 6, 15 do
                    names[i] = clean_wikilinks(cells[i])
                end
                table.insert(rows, { cells = cells, names = names })
            end
         end
         end
     end
     end
      
 
     games_rows_cache = rows
     return rows
     return rows
end
local function parse_games_row_cells(row)
    local cells = {}
   
    row = mw.ustring.gsub(row, "^%s*|%s*", "")
   
    for cell in mw.ustring.gmatch(row .. "||", "(.-)%s*||%s*") do
        cell = mw.text.trim(cell)
        table.insert(cells, cell)
    end
   
    return cells
end
end


Рядок 671: Рядок 680:
     local res = cells[16]
     local res = cells[16]
     if not res or mw.text.trim(res) == "" then return true end
     if not res or mw.text.trim(res) == "" then return true end
     return mw.ustring.find(res, "?", 1, true) ~= nil
     return string.find(res, "?", 1, true) ~= nil
end
end


local function get_player_role(player_name, cells)
local function get_player_role(player_name, entry)
     if has_unknown_roles(cells) then return "—" end
     if has_unknown_roles(entry.cells) then return "—" end
     -- Колонки 6-11: мирні
 
     local names = entry.names
     for i = 6, 11 do
     for i = 6, 11 do
         if cells[i] and clean_wikilinks(cells[i]) == player_name then
         if names[i] == player_name then return "Мир" end
            return "Мир"
        end
     end
     end
   
     if names[12] == player_name then return "Шер" end
    -- Колонка 12: шериф
     if cells[12] and clean_wikilinks(cells[12]) == player_name then
        return "Шер"
    end
   
    -- Колонки 13-14: мафія
     for i = 13, 14 do
     for i = 13, 14 do
         if cells[i] and clean_wikilinks(cells[i]) == player_name then
         if names[i] == player_name then return "Маф" end
            return "Маф"
        end
     end
     end
   
     if names[15] == player_name then return "Дон" end
    -- Колонка 15: дон
 
     if cells[15] and clean_wikilinks(cells[15]) == player_name then
        return "Дон"
    end
   
     return "—"
     return "—"
end
end
Рядок 708: Рядок 704:
     game_result = mw.text.trim(game_result)
     game_result = mw.text.trim(game_result)


    -- Маркер невідомості: ролі не читаються, отже і результат гравця теж
     if string.find(game_result, "?", 1, true) then return "—" end
     if mw.ustring.find(game_result, "?", 1, true) then return "—" end


     if game_result == "Місто" or game_result == "Мирні" then
     if game_result == "Місто" or game_result == "Мирні" then
Рядок 723: Рядок 718:


local function get_player_games_list(player_name)
local function get_player_games_list(player_name)
     local table_content = get_table_from_page("Ігри")
    if player_games_cache[player_name] then
     if not table_content then return nil end
        return player_games_cache[player_name]
   
    end
    local rows = parse_games_table_rows(table_content)
 
     local rows = get_games_rows()
     if not rows then return nil end
 
     local games = {}
     local games = {}
   
 
     for _, row in ipairs(rows) do
     for _, entry in ipairs(rows) do
         local cells = parse_games_row_cells(row)
         local found = false
          
         for i = 6, 15 do
        if #cells >= 17 then
            if entry.names[i] == player_name then
            local player_in_game = false
                found = true
            for i = 6, 15 do
                break
                if cells[i] and clean_wikilinks(cells[i]) == player_name then
                    player_in_game = true
                    break
                end
             end
             end
           
        end
          if player_in_game then
 
                local role = get_player_role(player_name, cells)
        if found then
                local result = get_player_result(role, cells[16])
            local cells = entry.cells
               
            local role = get_player_role(player_name, entry)
                -- Конвертуємо час з "37 хв 26 с" в "37:26"
            local result = get_player_result(role, cells[16])
                local time_raw = cells[5] or ""
 
                local minutes, seconds = mw.ustring.match(time_raw, "(%d+)%s*хв%s*(%d+)%s*с")
            local time_raw = cells[5] or ""
                local time_formatted = time_raw
            local time_formatted = time_raw
                if minutes and seconds then
            local minutes, seconds = string.match(time_raw, "(%d+)%s*хв%s*(%d+)%s*с")
                    time_formatted = minutes .. ":" .. string.format("%02d", tonumber(seconds))
            if minutes and seconds then
                end
                time_formatted = minutes .. ":" .. string.format("%02d", tonumber(seconds))
               
                table.insert(games, {
                    short = cells[3] or "",
                    tournament = cells[4] or "",
                    time = time_formatted,
                    role = role,
                    result = result,
                    link = cells[17] or ""
                })
             end
             end
            table.insert(games, {
                short = cells[3] or "",
                tournament = cells[4] or "",
                time = time_formatted,
                role = role,
                result = result,
                link = cells[17] or ""
            })
         end
         end
     end
     end
      
 
     player_games_cache[player_name] = games
     return games
     return games
end
end
Рядок 773: Рядок 768:
         return error_output("No Player Name", "")
         return error_output("No Player Name", "")
     end
     end
   
 
     local games = get_player_games_list(player_name)
     local games = get_player_games_list(player_name)
     if not games then
     if not games then
         return error_output("Cannot Load Games", "Ігри")
         return error_output("Cannot Load Games", "Ігри")
     end
     end
   
 
     if #games == 0 then
     if #games == 0 then
         return "''Ігор не знайдено''"
         return "''Ігор не знайдено''"
     end
     end
   
 
     local htmlTable = mw.html.create('table')
     local htmlTable = mw.html.create('table')
         :addClass('wikitable sortable')
         :addClass('wikitable sortable')
         :css('width', '100%')
         :css('width', '100%')
         :css('font-size', '14.5px')
         :css('font-size', '14.5px')
   
 
     local headerRow = htmlTable:tag('tr')
     local headerRow = htmlTable:tag('tr')
     headerRow:tag('th'):wikitext('Подія')
     headerRow:tag('th'):wikitext('Подія')
Рядок 795: Рядок 790:
     headerRow:tag('th'):wikitext('Запис')
     headerRow:tag('th'):wikitext('Запис')


    -- Колір для ролей (білий)
    local role_color = "#fff"
   
     for _, game in ipairs(games) do
     for _, game in ipairs(games) do
         local row = htmlTable:tag('tr')
         local row = htmlTable:tag('tr')
          
         local unknown = (game.result == "—")
 
         -- Турнір
         -- Турнір
         row:tag('td')
         row:tag('td')
Рядок 806: Рядок 799:
             :css('padding', '8px')
             :css('padding', '8px')
             :wikitext(get_tournament_link_games(game.short, game.tournament))
             :wikitext(get_tournament_link_games(game.short, game.tournament))
       
 
      -- Роль (білий колір)
         -- Роль
         -- Роль
         local roleCell = row:tag('td')
         row:tag('td')
             :css('text-align', 'center')
             :css('text-align', 'center')
             :css('padding', '8px')
             :css('padding', '8px')
 
            :tag('span')
        roleCell:tag('span')
                :css('color', unknown and '#777' or '#fff')
            :css('color', game.role == "—" and '#777' or '#fff')
                :wikitext(game.role)
            :wikitext(game.role)


         -- Час
         -- Час
Рядок 837: Рядок 828:
                 :wikitext('П')
                 :wikitext('П')
         else
         else
             resultCell:tag('span'):css('color', '#777'):wikitext('—')
             resultCell:tag('span')
                :css('color', '#777')
                :wikitext('—')
         end
         end
       
 
         -- Кнопка перегляду
         -- Запис
         local linkCell = row:tag('td')
         local linkCell = row:tag('td')
             :css('text-align', 'center')
             :css('text-align', 'center')
             :css('padding', '8px')
             :css('padding', '8px')
       
 
         if game.link and game.link ~= "" then
         if game.link and game.link ~= "" then
             linkCell:wikitext('<span class="game-record-btn">[' .. game.link .. ' ▶︎]</span>')
             linkCell:wikitext('<span class="game-record-btn">[' .. game.link .. ' ▶︎]</span>')
         end
         end
     end
     end
   
 
     return tostring(htmlTable)
     return tostring(htmlTable)
end
end
Рядок 856: Рядок 849:
     local player_name = frame.args.player
     local player_name = frame.args.player
     if not player_name or player_name == "" then return "0" end
     if not player_name or player_name == "" then return "0" end
   
 
     local games = get_player_games_list(player_name)
     local games = get_player_games_list(player_name)
     return games and tostring(#games) or "0"
     return games and tostring(#games) or "0"
Рядок 862: Рядок 855:


-- ================================================
-- ================================================
-- FETCHDATA6 (досягнення в сезонах)
-- ДОСЯГНЕННЯ В СЕЗОНАХ
-- ================================================
-- ================================================


Рядок 871: Рядок 864:
         [7] = "Сьомий сезон", [8] = "Восьмий сезон", [9] = "Дев'ятий сезон"
         [7] = "Сьомий сезон", [8] = "Восьмий сезон", [9] = "Дев'ятий сезон"
     }
     }
   
 
     local season_name = season_names[season_number]
     local season_name = season_names[season_number]
     if not season_name then return nil end
     if not season_name then return nil end
   
 
     local content = get_page_content(season_name)
     local content = get_page_content(season_name)
     if not content then return nil end
     if not content then return nil end
   
 
     local rating_section = mw.ustring.match(content, "==+%s*Рейтинг%s*==+(.-)\n==")
     local rating_section = mw.ustring.match(content, "==+%s*Рейтинг%s*==+(.-)\n==")
     if not rating_section then
     if not rating_section then
Рядок 883: Рядок 876:
     end
     end
     if not rating_section then return nil end
     if not rating_section then return nil end
   
 
     local table_start = mw.ustring.find(rating_section, "{|")
     local table_start = mw.ustring.find(rating_section, "{|")
     local table_end = mw.ustring.find(rating_section, "|}", table_start)
     local table_end = mw.ustring.find(rating_section, "|}", table_start)
     if not table_start or not table_end then return nil end
     if not table_start or not table_end then return nil end
   
 
     local table_content = mw.ustring.sub(rating_section, table_start, table_end + 1)
     local table_content = mw.ustring.sub(rating_section, table_start, table_end + 1)
   
 
     local current_row = {}
     local current_row = {}
     local all_rows = {}
     local all_rows = {}
   
 
     for line in mw.ustring.gmatch(table_content .. "\n", "([^\n]*)\n") do
     for line in mw.ustring.gmatch(table_content .. "\n", "([^\n]*)\n") do
         line = mw.text.trim(line)
         line = mw.text.trim(line)
       
 
         if line == "|-" then
         if line == "|-" then
             if #current_row > 0 then
             if #current_row > 0 then
Рядок 906: Рядок 899:
         end
         end
     end
     end
   
 
     if #current_row > 0 then
     if #current_row > 0 then
         table.insert(all_rows, current_row)
         table.insert(all_rows, current_row)
     end
     end
   
 
     for _, row in ipairs(all_rows) do
     for _, row in ipairs(all_rows) do
         if #row >= 5 then
         if #row >= 5 then
             local player_cell = clean_wikilinks(row[2])
             local player_cell = clean_wikilinks(row[2])
           
 
             if player_cell == player_name then
             if player_cell == player_name then
                 return {
                 return {
Рядок 925: Рядок 918:
         end
         end
     end
     end
   
 
     return nil
     return nil
end
end
Рядок 934: Рядок 927:
         return "<span style='color:red;'>Ім'я гравця не вказано</span>"
         return "<span style='color:red;'>Ім'я гравця не вказано</span>"
     end
     end
   
 
     local htmlTable = mw.html.create('table')
     local htmlTable = mw.html.create('table')
         :addClass('wikitable sortable')
         :addClass('wikitable sortable')
         :css('width', '100%')
         :css('width', '100%')
         :css('font-size', '14.5px')
         :css('font-size', '14.5px')
   
 
     local headerRow = htmlTable:tag('tr')
     local headerRow = htmlTable:tag('tr')
     headerRow:tag('th'):wikitext('Сезон')
     headerRow:tag('th'):wikitext('Сезон')
Рядок 946: Рядок 939:
     headerRow:tag('th'):wikitext('% перемог')
     headerRow:tag('th'):wikitext('% перемог')
     headerRow:tag('th'):wikitext('Ігор')
     headerRow:tag('th'):wikitext('Ігор')
   
 
     local season_links = {
     local season_links = {
         [1] = "[[Перший сезон#Рейтинг|01 сезон]]",
         [1] = "[[Перший сезон#Рейтинг|01 сезон]]",
Рядок 958: Рядок 951:
         [9] = "[[Дев'ятий сезон#Рейтинг|09 сезон]]"
         [9] = "[[Дев'ятий сезон#Рейтинг|09 сезон]]"
     }
     }
   
 
     for season = 1, 9 do
     for season = 1, 9 do
         local data = get_season_data(season, player_name)
         local data = get_season_data(season, player_name)
         local row = htmlTable:tag('tr')
         local row = htmlTable:tag('tr')
       
 
         row:tag('td'):css('text-align', 'center'):css('padding', '8px'):wikitext(season_links[season])
         row:tag('td'):css('text-align', 'center'):css('padding', '8px'):wikitext(season_links[season])
       
 
         if data then
         if data then
             row:tag('td'):css('text-align', 'center'):css('padding', '8px'):wikitext(data.place)
             row:tag('td'):css('text-align', 'center'):css('padding', '8px'):wikitext(data.place)
Рядок 976: Рядок 969:
         end
         end
     end
     end
   
 
     return tostring(htmlTable)
     return tostring(htmlTable)
end
end


return p
return p