Module:XVideosRedList: Difference between revisions

From Porn Base Central
Jump to navigation Jump to search
Content deleted Content added
No edit summary
No edit summary
 
(2 intermediate revisions by the same user not shown)
Line 8: Line 8:
local BASE_URL = "https://www.xvideos.red/"
local BASE_URL = "https://www.xvideos.red/"
-- Suffix to append to all XVideos RED URLs
-- Suffix to append to all XVideos RED URLs
local URL_SUFFIX = "?sxcaf=TARTFSJC35#_tabRed"
local URL_SUFFIX = "?sxcaf=TARTFSJC35"
-- Tab suffix added after the main suffix
local TAB_SUFFIX = "#_tabRed"
-- Main header URL for title link
-- Main header URL for title link
local HEADER_URL = "https://www.xvideos.red/gay?sxcaf=TARTFSJC35"
local HEADER_URL = "https://www.xvideos.red/gay?sxcaf=TARTFSJC35"
Line 122: Line 124:
return result .. formattedGenres[#formattedGenres]
return result .. formattedGenres[#formattedGenres]
end
end
end

-- Function to format country flag using frame:expandTemplate
-- @param country string: The country code or name
-- @param frame table: The current frame object for template expansion
-- @return string: Formatted country flag or empty string if country is nil or empty
local function formatCountryFlag(country, frame)
if not country or country == "" then
return ""
end
-- Use frame:expandTemplate to process the flagicon template
local flagTemplate = frame:expandTemplate{
title = 'flagicon',
args = { country }
}
return flagTemplate .. ' '
end
end


Line 192: Line 212:
end
end
-- Handle channel URL
-- Handle channel URL and country flag
local channelUrl = ""
local channelUrl = ""
local channelDisplay = channel.name
local channelDisplay = channel.name
local countryFlag = formatCountryFlag(channel.country, frame)
if channel.channel and channel.channel ~= '' then
if channel.channel and channel.channel ~= '' then
channelUrl = BASE_URL .. channel.channel .. URL_SUFFIX
channelUrl = BASE_URL .. channel.channel .. URL_SUFFIX .. TAB_SUFFIX
channelDisplay = string.format('[%s %s]', channelUrl, channel.name)
channelDisplay = string.format('%s[%s %s]', countryFlag, channelUrl, channel.name)
end
end



Latest revision as of 00:48, 15 March 2025

Documentation for this module may be created at Module:XVideosRedList/doc

-- This module handles the display of XVideos RED channel information
local p = {}

-- Load the i18n submodule for text strings and error messages
local i18n = require('Module:XVideosRedList/i18n')

-- Base URL for XVideos RED
local BASE_URL = "https://www.xvideos.red/"
-- Suffix to append to all XVideos RED URLs
local URL_SUFFIX = "?sxcaf=TARTFSJC35"
-- Tab suffix added after the main suffix
local TAB_SUFFIX = "#_tabRed"
-- Main header URL for title link
local HEADER_URL = "https://www.xvideos.red/gay?sxcaf=TARTFSJC35"
-- Default category for all channels
local DEFAULT_CATEGORY = "XVideos RED models"

-- Genre categories mapping
local GENRE_CATEGORIES = {
    ["Gay"] = "XVideos RED (gay) models",
    ["Straight"] = "XVideos RED (heterosexual) models",
    ["Bisexual"] = "XVideos RED (bisexual) models",
    ["Transexual"] = "XVideos RED (transsexual) models"
}

-- Genre display order priority
local GENRE_PRIORITY = {
    ["Gay"] = 1,
    ["Straight"] = 2,
    ["Bisexual"] = 3,
    ["Transexual"] = 4
}

-- Helper function to check if a table contains a specific value
-- @param tbl table: The table to search
-- @param value any: The value to find
-- @return boolean: True if the value is found, false otherwise
function table.contains(tbl, value)
    for _, v in pairs(tbl) do
        if v == value then return true end
    end
    return false
end

-- Helper function to format error message in red bold text
-- @param error string: The error message
-- @return string: Formatted error message
local function formatError(error)
    return string.format('|-\n| colspan="5" style="text-align:center;vertical-align:middle;color:red;font-weight:bold;" | %s\n', error)
end

-- Table of genres with their aliases for normalization
-- Each key is a standard genre name, and the value is a list of aliases or abbreviations
local genres = {
    Straight = {"s", "str", "str8"},
    Gay = {"g", "homo", "h", "homosexual"},
    Transexual = {"t", "trans", "tra", "trs"},
    Bisexual = {"b", "bi", "bisex"}
}

-- Table of icons for standard genres
-- Maps standard genre names to their corresponding icon file names
local iconMap = {
    ["Straight"] = "StraightIconPNG.png",
    ["Gay"] = "GayIconPNG.png",
    ["Transexual"] = "TranssexualIconPNG.png",
    ["Bisexual"] = "BisexualIconPNG.png",
}

-- Function to normalize genre input to a standard genre name
-- @param input string: The genre input to normalize
-- @return string: The standard genre name if matched, otherwise the original input
-- @return boolean: True if the genre is valid, false otherwise
local function normalizeGenre(input)
    if not input or input == '' then
        return nil, false
    end
    
    local lowerInput = input:lower()  -- Convert input to lowercase for case-insensitive comparison
    for standard, aliases in pairs(genres) do
        if lowerInput == standard:lower() or table.contains(aliases, lowerInput) then
            return standard, true
        end
    end
    return input, false  -- Return original input if no match is found, plus flag indicating no match
end

-- Function to format multiple genres with proper icons and formatting
-- @param genreList table: List of normalized genre names
-- @return string: Formatted genres with icons and proper separators
local function formatGenres(genreList)
    if #genreList == 0 then
        return '<span style="color:red;font-weight:bold;">' .. i18n.errors.noGenreProvided .. '</span>'
    end
    
    -- Sort genres according to priority order
    table.sort(genreList, function(a, b) 
        return (GENRE_PRIORITY[a] or 99) < (GENRE_PRIORITY[b] or 99)
    end)
    
    local formattedGenres = {}
    for _, genre in ipairs(genreList) do
        if iconMap[genre] then
            table.insert(formattedGenres, string.format('[[File:%s|13px|link=]] %s', iconMap[genre], genre))
        else
            table.insert(formattedGenres, genre)
        end
    end
    
    -- Format with appropriate separators based on the number of genres
    if #formattedGenres == 1 then
        return formattedGenres[1]
    elseif #formattedGenres == 2 then
        return formattedGenres[1] .. ' & ' .. formattedGenres[2]
    else
        local result = ""
        for i = 1, #formattedGenres - 1 do
            if i == #formattedGenres - 1 then
                result = result .. formattedGenres[i] .. ' & '
            else
                result = result .. formattedGenres[i] .. ', '
            end
        end
        return result .. formattedGenres[#formattedGenres]
    end
end

-- Function to format country flag using frame:expandTemplate
-- @param country string: The country code or name
-- @param frame table: The current frame object for template expansion
-- @return string: Formatted country flag or empty string if country is nil or empty
local function formatCountryFlag(country, frame)
    if not country or country == "" then
        return ""
    end
    
    -- Use frame:expandTemplate to process the flagicon template
    local flagTemplate = frame:expandTemplate{
        title = 'flagicon',
        args = { country }
    }
    
    return flagTemplate .. ' '
end

-- Main function to handle channel information display
-- @param frame table: The frame object passed from the template
-- @return string: The formatted table row or an error message
function p.channel(frame)
    -- Get template arguments
    local args = require('Module:Arguments').getArgs(frame, {wrappers = 'Template:XVideosRedList'})
    
    -- Check if channel parameter is provided
    if not args.channel or args.channel == '' then
        return formatError(i18n.errors.channelIsEmpty)
    end

    -- Get channel data
    local channel, error = getChannel(args.channel)

    if error then
        return formatError(error)
    elseif channel then
        -- Format channel data, prioritizing template arguments over module data
        local alias = args.alias or channel.alias or 'N/A'
        
        -- Fix for empty notes field
        local notes = args.notes or channel.notes or 'N/A'
        if notes == "" then
            notes = 'N/A'
        end
        
        -- Process multiple genres
        local genreList = {}
        local invalidGenres = {}
        
        -- Process primary genre
        local primaryGenre = args.genre or channel.genre or ''
        local normalizedGenre, isValid = normalizeGenre(primaryGenre)
        if normalizedGenre then
            table.insert(genreList, normalizedGenre)
            if not isValid then
                table.insert(invalidGenres, primaryGenre)
            end
        end
        
        -- Process additional genres (genre2, genre3, genre4)
        for i = 2, 4 do
            local genreArg = args['genre'..i]
            if genreArg and genreArg ~= '' then
                local normalized, valid = normalizeGenre(genreArg)
                if normalized and not table.contains(genreList, normalized) then
                    table.insert(genreList, normalized)
                    if not valid then
                        table.insert(invalidGenres, genreArg)
                    end
                end
            end
        end
        
        -- Check if at least one valid genre was provided
        if #genreList == 0 then
            return formatError(i18n.errors.noGenreProvided)
        end
        
        -- Format genres with appropriate icons and separators
        local genreOutput = formatGenres(genreList)
        
        -- Log any invalid genres for debugging
        for _, invalidGenre in ipairs(invalidGenres) do
            mw.log(string.format(i18n.errors.invalidGenre, invalidGenre))
        end
        
        -- Handle channel URL and country flag
        local channelUrl = ""
        local channelDisplay = channel.name
        local countryFlag = formatCountryFlag(channel.country, frame)
        
        if channel.channel and channel.channel ~= '' then
            channelUrl = BASE_URL .. channel.channel .. URL_SUFFIX .. TAB_SUFFIX
            channelDisplay = string.format('%s[%s %s]', countryFlag, channelUrl, channel.name)
        end

        -- Format row with gathered data
        local result = string.format(
            '|-\n| style="text-align:center;vertical-align:middle;" | %s\n| style="text-align:center;vertical-align:middle;" | %s\n| style="text-align:center;vertical-align:middle;" | %s\n| style="text-align:center;vertical-align:middle;" | %s\n| style="display:none;" |\n',
            channelDisplay,
            genreOutput,
            alias,
            notes
        )

        -- Add categories based on namespace and genres
        local ns = mw.title.getCurrentTitle().namespace
        if ns == 0 then
            -- Add default category for all entries
            result = result .. '[[Category:' .. DEFAULT_CATEGORY .. ']]'
            
            -- Add genre-specific categories
            for _, genre in ipairs(genreList) do
                if GENRE_CATEGORIES[genre] then
                    result = result .. '[[Category:' .. GENRE_CATEGORIES[genre] .. ']]'
                end
            end
            
            -- Add tracking category for main namespace
            result = result .. '[[Category:Articles using XVideosRedList]]'
        elseif ns == 2 then
            result = result .. '[[Category:User pages using XVideosRedList]]'
        elseif ns == 118 then
            result = result .. '[[Category:Draft pages using XVideosRedList]]'
        end

        return result
    else
        return formatError(string.format(i18n.errors.channelNotFound, args.channel))
    end
end

-- Function to find and retrieve channel data from appropriate module
-- @param name string: The name of the channel to find
-- @return table|string: The channel data table or an error message
function getChannel(name)
    if not name then return nil, i18n.errors.channelIsEmpty end
    
    local modulesToTry = {}
    local firstLetter = name:sub(1, 1):upper()
    table.insert(modulesToTry, firstLetter)
    
    -- Handle "The" prefix
    local nameWithoutThe = name:lower():gsub("^the%s*", ""):gsub("%s*", "")
    if nameWithoutThe ~= name:lower() then
        local theFirstLetter = nameWithoutThe:sub(1, 1):upper()
        if theFirstLetter ~= firstLetter then
            table.insert(modulesToTry, theFirstLetter)
        end
    end

    for _, module in ipairs(modulesToTry) do
        local success, channelModule = pcall(require, 'Module:XVideosRedList/' .. module)
        
        if success then
            if type(channelModule) == "table" and type(channelModule.channels) == "table" then
                local matchedChannels = {}
                
                -- First try direct match or aliases
                for _, channel in pairs(channelModule.channels) do
                    if channel.name:lower() == name:lower() or 
                       (channel.aliases and table.contains(channel.aliases, name:lower())) then
                        table.insert(matchedChannels, channel)
                    end
                end
                
                -- If found matches, return results
                if #matchedChannels > 1 then
                    return nil, string.format(i18n.errors.duplicateChannels, name)
                elseif #matchedChannels == 1 then
                    return matchedChannels[1]
                end
                
                -- If no direct matches found, try redirects
                if channelModule.redirects and channelModule.redirects[name:lower()] then
                    return getChannel(channelModule.redirects[name:lower()])
                end
            else
                mw.log(string.format(i18n.errors.invalidModuleStructure, module))
                return nil, string.format(i18n.errors.invalidModuleStructure, module)
            end
        else
            mw.log(string.format(i18n.errors.moduleLoadError, module))
        end
    end
    
    return nil, string.format(i18n.errors.channelNotFound, name)
end

-- Function to generate the table header with XVideos RED logo link
-- @return string: The formatted table header
function p.tableHeader()
    local headerLink = string.format('[[File:Xvideosredlogo.svg|24px|link=]] [%s XVideos RED]', HEADER_URL)
    
    return string.format('! colspan="5" | %s\n|-\n!style="width: 30%%; text-align: center; background-color:#E7E7E7;" |Studio name\n!style="width: 20%%; text-align: center; background-color:#E7E7E7;" |Genre\n!style="width: 25%%; text-align: center; background-color:#E7E7E7;" |Alias\n!style="width: 25%%; text-align: center; background-color:#E7E7E7;" |Notes\n!style="display:none;" |\n', headerLink)
end

return p