모듈:일간 신창섭 최근 목록
창팝위키
더 많은 작업
이 모듈에 대한 설명문서는 모듈:일간 신창섭 최근 목록/설명문서에서 만들 수 있습니다
local p = {}
local CONFIG = {
apiuntoSource = "일간신창섭최근목록", -- LocalSettings.php의 $wgApiuntoSources 키
templateName = "유튜브 영상 항목",
-- 시트의 열 순서(A~H)를 그대로 숫자 인덱스로 나열.
-- values[i][col.url] 식으로 참조하기 위한 상수.
col = {
url = 1, -- A: 원본 URL
videoId = 2, -- B: 추출된 영상 ID
title = 3, -- C: 제목
channel = 4, -- D: 채널명
channelId = 5, -- E: 채널 ID
views = 6, -- F: 조회수
published = 7, -- G: 게시일(UTC ISO 8601)
duration = 8, -- H: 길이(mm:ss, 이미 변환되어 있음)
},
}
-- ── 날짜/시간 유틸리티 (os 라이브러리 미사용) ──────────────────
local DAYS_IN_MONTH = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
local function isLeapYear(y)
return (y % 4 == 0 and y % 100 ~= 0) or (y % 400 == 0)
end
local function daysInMonth(y, m)
if m == 2 and isLeapYear(y) then return 29 end
return DAYS_IN_MONTH[m]
end
local function parseIso8601Utc(str)
local y, mo, d, h, mi, s = str:match(
"^(%d%d%d%d)%-(%d%d)%-(%d%d)T(%d%d):(%d%d):(%d%d)Z$"
)
if not y then return nil end
return {
year = tonumber(y), month = tonumber(mo), day = tonumber(d),
hour = tonumber(h), min = tonumber(mi), sec = tonumber(s),
}
end
local function utcToKst(t)
local hour = t.hour + 9
local day, month, year = t.day, t.month, t.year
if hour >= 24 then
hour = hour - 24
day = day + 1
if day > daysInMonth(year, month) then
day = 1
month = month + 1
if month > 12 then
month = 1
year = year + 1
end
end
end
return { year = year, month = month, day = day, hour = hour, min = t.min }
end
local function formatKstTime(kst)
local period = "오전"
local hour12 = kst.hour
if kst.hour == 0 then
hour12 = 12
elseif kst.hour == 12 then
period = "오후"
hour12 = 12
elseif kst.hour > 12 then
period = "오후"
hour12 = kst.hour - 12
end
return string.format("%s %d:%02d", period, hour12, kst.min)
end
local function formatDateHeading(kst)
return string.format("%d월 %d일", kst.month, kst.day)
end
local function abbreviateViews(n)
if not n then return "" end
local function trimUnit(value, unit)
local truncated = math.floor(value * 10) / 10
if truncated == math.floor(truncated) then
return string.format("%d%s", truncated, unit)
end
return string.format("%.1f%s", truncated, unit)
end
if n < 1000 then
return tostring(n)
elseif n < 10000 then
return trimUnit(n / 1000, "천")
elseif n < 100000000 then
return trimUnit(n / 10000, "만")
else
return trimUnit(n / 100000000, "억")
end
end
-- ============================================================
-- 메인 진입점: {{#invoke:YoutubeList|main}}
-- ============================================================
function p.main(frame)
local api = mw.ext.Apiunto
local raw = api.fetch(CONFIG.apiuntoSource, "")
if not raw or raw == "" or raw == "Could not retrieve API Data" then
return "Apiunto(" .. CONFIG.apiuntoSource .. ") 응답을 가져오지 못했습니다."
end
-- fetch()는 JSON을 파싱하지 않고 원문 문자열을 그대로 주므로, 여기서 직접 디코드해야 한다.
local ok, response = pcall(mw.text.jsonDecode, raw)
if not ok or type(response) ~= "table" then
return "Apiunto(" .. CONFIG.apiuntoSource .. ") 응답이 유효한 JSON이 아닙니다."
end
if not response.values then
return "Apiunto(" .. CONFIG.apiuntoSource .. ") 응답에서 values를 찾지 못했습니다."
end
local parts = {}
local currentDateKey = nil
local col = CONFIG.col
for _, row in ipairs(response.values) do
-- row[n]이 빈 셀 이후는 아예 배열에서 생략될 수 있으므로(구글 시트 API 특성),
-- 매번 or ""로 안전하게 기본값을 준다.
local published = row[col.published] or ""
local utc = parseIso8601Utc(published)
if utc then -- 업로드 시각이 없는(아직 조회 안 된) 행은 건너뜀
local kst = utcToKst(utc)
local dateKey = string.format("%04d-%02d-%02d", kst.year, kst.month, kst.day)
if dateKey ~= currentDateKey then
table.insert(parts, [[<p class="mw--card-row" style="
font-size: var(--font-size-large, 1.125rem);
font-weight: var(--font-weight-medium, 500);
margin: 0;
">]]
.. formatDateHeading(kst) .. "</p>")
currentDateKey = dateKey
end
local templateArgs = {
["영상Id"] = row[col.videoId] or "",
["제목"] = row[col.title] or "",
["채널이름"] = row[col.channel] or "",
["채널Id"] = row[col.channelId] or "",
["조회수"] = abbreviateViews(tonumber(row[col.views])),
["업로드시각"] = formatKstTime(kst),
["길이"] = row[col.duration] or "",
}
local rendered = frame:expandTemplate{
title = CONFIG.templateName,
args = templateArgs,
}
table.insert(parts, rendered)
end
end
return table.concat(parts, "\n")
end
return p