Actions

Module

VideoGallery: Difference between revisions

From Dune Awakening DB

mNo edit summary
mNo edit summary
 
Line 1: Line 1:
-- Module:VideoGallery (no LuaSQLite required)
-- Module:VideoGallery
local p    = {}
-- Lua module for rendering video gallery sections
local json  = mw.text.jsonEncode
local ed    = mw.ext.externaldata


-----------------------------------------------------------------
local p = {}
-- collectRows()
 
--   Returns:  (rowsList , id→row  table)
-- Helper function to escape quotes
-----------------------------------------------------------------
local function escapeQuotes(str)
local function collectRows()
     if not str then return '' end
     local rows  = ed.getExternalData()
     return str:gsub('"', '"'):gsub("'", ''')
     local byId  = {}
    for _, r in ipairs( rows ) do
        byId[ r.id ] = r
    end
    return rows, byId
end
end


-----------------------------------------------------------------
-- Helper function to format duration
-- renderVideos( frame )
local function formatDuration(seconds)
--  Renders the cards for one category (passed as |category=...)
    if not seconds or seconds == 0 then return '' end
-----------------------------------------------------------------
     local minutes = math.floor(seconds / 60)
function p.renderVideos( frame )
     local secs = seconds % 60
     local category = ( frame.args.category or '' ):lower()
     return string.format("%d:%02d", minutes, secs)
     local rows     = ed.getExternalData()
end


     local out = { '<div class="video-grid">' }
-- Render videos for a specific category
    for _, v in ipairs( rows ) do
function p.renderCategoryVideos(frame)
        if ( v.category or '' ):lower() == category then
     local category = frame.args.category or 'Featured'
            out[#out+1] = string.format(
    local html = ''
                '<div class="video-card" data-video-id="%s">' ..
   
                  '<div class="video-thumbnail" style="background-image:url(%s)"></div>' ..
    -- Get unique purposes for this category
                  '<div class="video-info"><span class="video-title">%s</span></div>' ..
    local purposes = mw.ext.externalData.getExternalData{
                '</div>',
        source = 'externaldb',
                v.id,
        from = 'data_videos',
                mw.uri.encode( v.thumbnail_url or '', 'PATH' ),
        data = 'purpose=purpose',
                 mw.text.nowiki( v.title or '' )
        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
     end
     end
     out[#out+1] = '</div>'
      
     return table.concat( out )
     return html
end
end


-----------------------------------------------------------------
-- Render featured videos (shows videos from all categories)
-- getVideoData()
function p.renderFeaturedVideos(frame)
--   Emits one big JSON blob keyed by id → row  (for JS)
    local html = ''
-----------------------------------------------------------------
   
function p.getVideoData()
    -- Get unique purposes from all categories
    local _, byId = collectRows()
    local purposes = mw.ext.externalData.getExternalData{
     return json( byId )
        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
end


return p
return p

Latest revision as of 17:43, 2 June 2025

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('"', '&quot;'):gsub("'", '&#39;')
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