Module:VideoGallery
From Dune Awakening DB
Documentation for this module may be created at Module:VideoGallery/doc
-- Module:VideoGallery
-- Lua module for rendering video gallery sections
local p = {}
-- Helper function to escape quotes
local function escapeQuotes(str)
if not str then return '' end
return str:gsub('"', '"'):gsub("'", ''')
end
-- Helper function to format duration
local function formatDuration(seconds)
if not seconds or seconds == 0 then return '' end
local minutes = math.floor(seconds / 60)
local secs = seconds % 60
return string.format("%d:%02d", minutes, secs)
end
-- Render videos for a specific category
function p.renderCategoryVideos(frame)
local category = frame.args.category or 'Featured'
local html = ''
-- Get unique purposes for this category
local purposes = mw.ext.externalData.getExternalData{
source = 'externaldb',
from = 'data_videos',
data = 'purpose=purpose',
where = "primary_tag='" .. category .. "' AND visibility='public' AND purpose IS NOT NULL",
group_by = 'purpose',
order_by = 'purpose'
}
-- Loop through each purpose and create a section
if purposes and purposes.purpose then
for i, purpose in ipairs(purposes.purpose) do
html = html .. '<div class="video-section">\n'
html = html .. ' <div class="video-section-header">\n'
html = html .. ' <h3 class="section-title">' .. purpose .. '</h3>\n'
html = html .. ' </div>\n'
html = html .. ' <div class="video-grid">\n'
-- Get videos for this purpose
local videos = mw.ext.externalData.getExternalData{
source = 'externaldb',
from = 'data_videos',
data = 'video_id=video_id,youtube_id=youtube_id,title=title,channel_title=channel_title,channel_id=channel_id,author=author,published_at=published_at,duration_sec=duration_sec,purpose=purpose,primary_tag=primary_tag,secondary_tag=secondary_tag,description=description,video_notes=video_notes,video_internal_link=video_internal_link',
where = "primary_tag='" .. category .. "' AND purpose='" .. purpose .. "' AND visibility='public'",
order_by = 'published_at DESC'
}
-- Render each video card
if videos and videos.video_id then
for j, video_id in ipairs(videos.video_id) do
local duration = formatDuration(tonumber(videos.duration_sec[j] or 0))
html = html .. ' <div class="video-card" '
html = html .. 'data-video-id="' .. video_id .. '" '
html = html .. 'data-youtube-id="' .. (videos.youtube_id[j] or '') .. '" '
html = html .. 'data-title="' .. escapeQuotes(videos.title[j] or '') .. '" '
html = html .. 'data-channel="' .. escapeQuotes(videos.channel_title[j] or '') .. '" '
html = html .. 'data-channel-id="' .. (videos.channel_id[j] or '') .. '" '
html = html .. 'data-author="' .. escapeQuotes(videos.author[j] or '') .. '" '
html = html .. 'data-published="' .. (videos.published_at[j] or '') .. '" '
html = html .. 'data-duration="' .. (videos.duration_sec[j] or '') .. '" '
html = html .. 'data-purpose="' .. escapeQuotes(videos.purpose[j] or '') .. '" '
html = html .. 'data-primary-tag="' .. (videos.primary_tag[j] or '') .. '" '
html = html .. 'data-secondary-tag="' .. (videos.secondary_tag[j] or '') .. '" '
html = html .. 'data-description="' .. escapeQuotes(videos.description[j] or '') .. '" '
html = html .. 'data-notes="' .. escapeQuotes(videos.video_notes[j] or '') .. '" '
html = html .. 'data-internal-link="' .. escapeQuotes(videos.video_internal_link[j] or '') .. '">\n'
html = html .. ' <div class="video-thumbnail" style="background-image: url(\'https://img.youtube.com/vi/' .. (videos.youtube_id[j] or '') .. '/mqdefault.jpg\');">\n'
if duration ~= '' then
html = html .. ' <span class="video-duration">' .. duration .. '</span>\n'
end
html = html .. ' </div>\n'
html = html .. ' <div class="video-info">\n'
html = html .. ' <div class="video-title">' .. (videos.title[j] or '') .. '</div>\n'
html = html .. ' <div class="video-channel">' .. (videos.channel_title[j] or '') .. '</div>\n'
html = html .. ' </div>\n'
html = html .. ' </div>\n'
end
end
html = html .. ' </div>\n'
html = html .. '</div>\n'
end
end
return html
end
-- Render featured videos (shows videos from all categories)
function p.renderFeaturedVideos(frame)
local html = ''
-- Get unique purposes from all categories
local purposes = mw.ext.externalData.getExternalData{
source = 'externaldb',
from = 'data_videos',
data = 'purpose=purpose',
where = "visibility='public' AND purpose IS NOT NULL",
group_by = 'purpose',
order_by = 'purpose',
limit = 10 -- Limit featured to first 10 purposes
}
-- Loop through each purpose and create a section
if purposes and purposes.purpose then
for i, purpose in ipairs(purposes.purpose) do
html = html .. '<div class="video-section">\n'
html = html .. ' <div class="video-section-header">\n'
html = html .. ' <h3 class="section-title">' .. purpose .. '</h3>\n'
html = html .. ' </div>\n'
html = html .. ' <div class="video-grid">\n'
-- Get videos for this purpose
local videos = mw.ext.externalData.getExternalData{
source = 'externaldb',
from = 'data_videos',
data = 'video_id=video_id,youtube_id=youtube_id,title=title,channel_title=channel_title,channel_id=channel_id,author=author,published_at=published_at,duration_sec=duration_sec,purpose=purpose,primary_tag=primary_tag,secondary_tag=secondary_tag,description=description,video_notes=video_notes,video_internal_link=video_internal_link',
where = "purpose='" .. purpose .. "' AND visibility='public'",
order_by = 'published_at DESC',
limit = 4 -- Limit to 4 videos per purpose in featured
}
-- Render each video card
if videos and videos.video_id then
for j, video_id in ipairs(videos.video_id) do
local duration = formatDuration(tonumber(videos.duration_sec[j] or 0))
html = html .. ' <div class="video-card" '
html = html .. 'data-video-id="' .. video_id .. '" '
html = html .. 'data-youtube-id="' .. (videos.youtube_id[j] or '') .. '" '
html = html .. 'data-title="' .. escapeQuotes(videos.title[j] or '') .. '" '
html = html .. 'data-channel="' .. escapeQuotes(videos.channel_title[j] or '') .. '" '
html = html .. 'data-channel-id="' .. (videos.channel_id[j] or '') .. '" '
html = html .. 'data-author="' .. escapeQuotes(videos.author[j] or '') .. '" '
html = html .. 'data-published="' .. (videos.published_at[j] or '') .. '" '
html = html .. 'data-duration="' .. (videos.duration_sec[j] or '') .. '" '
html = html .. 'data-purpose="' .. escapeQuotes(videos.purpose[j] or '') .. '" '
html = html .. 'data-primary-tag="' .. (videos.primary_tag[j] or '') .. '" '
html = html .. 'data-secondary-tag="' .. (videos.secondary_tag[j] or '') .. '" '
html = html .. 'data-description="' .. escapeQuotes(videos.description[j] or '') .. '" '
html = html .. 'data-notes="' .. escapeQuotes(videos.video_notes[j] or '') .. '" '
html = html .. 'data-internal-link="' .. escapeQuotes(videos.video_internal_link[j] or '') .. '">\n'
html = html .. ' <div class="video-thumbnail" style="background-image: url(\'https://img.youtube.com/vi/' .. (videos.youtube_id[j] or '') .. '/mqdefault.jpg\');">\n'
if duration ~= '' then
html = html .. ' <span class="video-duration">' .. duration .. '</span>\n'
end
html = html .. ' </div>\n'
html = html .. ' <div class="video-info">\n'
html = html .. ' <div class="video-title">' .. (videos.title[j] or '') .. '</div>\n'
html = html .. ' <div class="video-channel">' .. (videos.channel_title[j] or '') .. '</div>\n'
html = html .. ' </div>\n'
html = html .. ' </div>\n'
end
end
html = html .. ' </div>\n'
html = html .. '</div>\n'
end
end
return html
end
return p
