Module:Biobox: Difference between revisions

From Porn Base Central
Jump to navigation Jump to search
Content deleted Content added
No edit summary
No edit summary
 
(One intermediate revision by the same user not shown)
Line 7: Line 7:
local BioboxPersonalPages = require('Module:BioboxPersonalPages')
local BioboxPersonalPages = require('Module:BioboxPersonalPages')
local BioboxDatabases = require('Module:BioboxDatabases')
local BioboxDatabases = require('Module:BioboxDatabases')
local BioboxSharing = require('Module:BioboxSharing')


local ALIAS_TO_PRIMARY = {}
local ALIAS_TO_PRIMARY = {}
Line 110: Line 109:


local function getPBDIBValue(propertyId, args, options)
local function getPBDIBValue(propertyId, args, options)
if not args.qid or args.qid == "" then
return PBDIB._getValue({
[1] = propertyId,
return nil
end
qid = args.qid,
format = options and options.format,
fpbd = "ALL"
local success, result = pcall(function()
return PBDIB._getValue({
})
[1] = propertyId,
qid = args.qid,
format = options and options.format,
fpbd = "ALL"
})
end)
if success then
return result
else
return nil
end
end
end


Line 375: Line 386:
args = normalizeKeys(args)
args = normalizeKeys(args)
if not args.qid or args.qid == "" then
if isEmpty(args.qid) then
args.qid = mw.wikibase.getEntityIdForCurrentPage()
local success, entityId = pcall(mw.wikibase.getEntityIdForCurrentPage)
if success and entityId then
args.qid = entityId
else
args.qid = nil
end
end
end
Line 382: Line 398:
local state = State:new()
local state = State:new()


local personalSection, rowIndex = BioboxPersonal.formatPersonalSection(state, args, title)
local personalSection, rowIndex
local success, result1, result2 = pcall(function()
local bodySection = BioboxBody.formatBodySection(state, args, rowIndex)
return BioboxPersonal.formatPersonalSection(state, args, title)
end)
if success then
local personalPagesSection, ppRowIndex = BioboxPersonalPages.formatPersonalPagesSection(state, args, rowIndex)
personalSection, rowIndex = result1, result2
local databasesSection, dbRowIndex = BioboxDatabases.formatDatabasesSection(state, args, ppRowIndex)
else
local sharingSection, shRowIndex = BioboxSharing.formatSharingSection(state, args, dbRowIndex)
personalSection = string.format('{| %s\n|-\n! colspan="2" %s | \'\'\'%s\'\'\'',
STYLES.INFOBOX,
STYLES.HEADER,
title)
rowIndex = 1
end
local bodySection = ""
success, result1 = pcall(function()
return BioboxBody.formatBodySection(state, args, rowIndex)
end)
if success then
bodySection = result1
end
local personalPagesSection, ppRowIndex = {}, rowIndex
success, result1, result2 = pcall(function()
return BioboxPersonalPages.formatPersonalPagesSection(state, args, rowIndex)
end)
if success then
personalPagesSection, ppRowIndex = result1, result2
end
local databasesSection, dbRowIndex = {}, ppRowIndex
success, result1, result2 = pcall(function()
return BioboxDatabases.formatDatabasesSection(state, args, ppRowIndex)
end)
if success then
databasesSection, dbRowIndex = result1, result2
end
if isEmpty(personalSection) or not string.find(personalSection, '{|%s+class="infoboxnew"') then
personalSection = string.format('{| %s\n|-\n! colspan="2" %s | \'\'\'%s\'\'\'',
STYLES.INFOBOX,
STYLES.HEADER,
title)
end
local result = personalSection .. '\n' .. bodySection
local result = personalSection .. '\n' .. bodySection
Line 397: Line 455:
if #databasesSection > 0 then
if #databasesSection > 0 then
result = result .. '\n' .. table.concat(databasesSection, '\n')
result = result .. '\n' .. table.concat(databasesSection, '\n')
end
if #sharingSection > 0 then
result = result .. '\n' .. table.concat(sharingSection, '\n')
end
end


if args.qid then
if not isEmpty(args.qid) then
local pbcLink = mw.wikibase.getSitelink(args.qid)
local success, pbcLink = pcall(mw.wikibase.getSitelink, args.qid)
if pbcLink then
if success and pbcLink then
result = result .. '\n|-class="stop-section-collapse"\n! colspan="2" style="background:#F0E68C;text-align:center;" | [[File:Pbd.svg | 45px | alt=' .. args.qid .. ' | link=pbd:' .. args.qid .. ']] [[:pbd:' .. args.qid .. '|' .. pbcLink .. ']] ([[:pbd:' .. args.qid .. '|' .. args.qid .. ']])'
result = result .. '\n|-class="stop-section-collapse"\n! colspan="2" style="background:#F0E68C;text-align:center;" | [[File:Pbd.svg | 45px | alt=' .. args.qid .. ' | link=pbd:' .. args.qid .. ']] [[:pbd:' .. args.qid .. '|' .. pbcLink .. ']] ([[:pbd:' .. args.qid .. '|' .. args.qid .. ']])'
end
end
Line 415: Line 469:
}
}
}
}
local imageRepoLink = PBDIB.getSiteLink(newFrame)
if imageRepoLink and imageRepoLink ~= '' then
local imageRepoLink
success, imageRepoLink = pcall(function()
return PBDIB.getSiteLink(newFrame)
end)
if success and imageRepoLink and imageRepoLink ~= '' then
result = result .. '\n|-class="stop-section-collapse"\n! colspan="2" style="background:#F0E68C;text-align:center;" | [[File:Image-icon.svg | 18px | link=:' .. imageRepoLink .. ']] [[:' .. imageRepoLink .. '| PBC Image Repository]]'
result = result .. '\n|-class="stop-section-collapse"\n! colspan="2" style="background:#F0E68C;text-align:center;" | [[File:Image-icon.svg | 18px | link=:' .. imageRepoLink .. ']] [[:' .. imageRepoLink .. '| PBC Image Repository]]'
end
end


newFrame.args.wiki = "pbcvideorepo"
newFrame.args.wiki = "pbcvideorepo"
local videoRepoLink = PBDIB.getSiteLink(newFrame)
local videoRepoLink
success, videoRepoLink = pcall(function()
return PBDIB.getSiteLink(newFrame)
end)
if videoRepoLink and videoRepoLink ~= '' then
if success and videoRepoLink and videoRepoLink ~= '' then
result = result .. '\n|-class="stop-section-collapse"\n! colspan="2" style="background:#F0E68C;text-align:center;" | [[File:Video-icon.svg | 18px | link=:' .. videoRepoLink .. ']] [[:' .. videoRepoLink .. '| PBC Video Repository]]'
result = result .. '\n|-class="stop-section-collapse"\n! colspan="2" style="background:#F0E68C;text-align:center;" | [[File:Video-icon.svg | 18px | link=:' .. videoRepoLink .. ']] [[:' .. videoRepoLink .. '| PBC Video Repository]]'
end
end
Line 431: Line 492:
result = result .. '\n|}'
result = result .. '\n|}'


local categories = BioboxPersonal.getPBDCategories(args)
local categories = {}
if not isEmpty(args.qid) then
success, categories = pcall(function()
return BioboxPersonal.getPBDCategories(args)
end)
if not success then
categories = {}
end
end
if #categories > 0 then
if #categories > 0 then
local categoryStrings = {}
local categoryStrings = {}

Latest revision as of 00:22, 19 March 2025

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

local p = {}

local PBDIB = require('Module:PornBaseDataIB')
local CategoryMapping = require('Module:BioboxCategoryMapping')
local BioboxPersonal = require('Module:BioboxPersonal')
local BioboxBody = require('Module:BioboxBody')
local BioboxPersonalPages = require('Module:BioboxPersonalPages')
local BioboxDatabases = require('Module:BioboxDatabases')

local ALIAS_TO_PRIMARY = {}
do
    for primary, aliases in pairs(CategoryMapping.PARAM_ALIASES) do
        for _, alias in ipairs(aliases) do
            ALIAS_TO_PRIMARY[alias] = primary
        end
        ALIAS_TO_PRIMARY[primary] = primary
    end
end

local STYLES = {
    INFOBOX = 'class="infoboxnew" align="left" cellspacing="1" cellpadding="1" style="text-align:center; font-size:88%; line-height:1.5em; white-space:normal;"',
    HEADER = 'style="color:white; text-align:center; border: 1px solid white; background:#657D91; font-size:112%;"',
    LABEL = 'width:40%; padding-left:0.1em; overflow-wrap: break-word; font-weight:normal; text-align:left;',
    SECTION_HEADER = 'style="color:white; text-align:center; border: 1px solid white; background:#657D91; font-size:100%;"',
    ODD_ROW = 'background-color:#F7F7F7;',
    EVEN_ROW = 'background-color:white;'
}

local function isEmpty(value)
    return value == nil or value == ''
end

local function isPositive(value)
    if isEmpty(value) then return false end
    value = tostring(value):lower()
    local positiveValues = {
        ['yes'] = true,
        ['y'] = true,
        ['ya'] = true,
        ['yep'] = true,
        ['true'] = true,
        ['1'] = true
    }
    return positiveValues[value] or false
end

local POSITIVE_ONLY_FIELDS = {
    ['tattoo'] = true
}

local function normalizeKeys(args)
    local normalized = {}
    local seenParams = {}
    local processedAliases = {}
    local firstOccurrence = {}
    
    for key, value in pairs(args) do
        local normalizedKey = tostring(key):gsub(" ", "_"):lower()
        local primaryKey = ALIAS_TO_PRIMARY[normalizedKey] or normalizedKey
        
        if not firstOccurrence[primaryKey] then
            firstOccurrence[primaryKey] = #seenParams + 1
        end
        
        table.insert(seenParams, {
            key = key,
            value = value,
            normalizedKey = normalizedKey,
            primaryKey = primaryKey,
            position = firstOccurrence[primaryKey]
        })
    end
    
    table.sort(seenParams, function(a, b) 
        return a.position < b.position
    end)
    
    for _, param in ipairs(seenParams) do
        local primaryKey = param.primaryKey
        
        if not processedAliases[primaryKey] then
            if not isEmpty(param.value) then
                normalized[primaryKey] = param.value
                processedAliases[primaryKey] = true
            elseif not normalized[primaryKey] then
                normalized[primaryKey] = param.value
            end
        end
    end
    
    return normalized
end

local function isNumeric(value)
    if type(value) == "number" then return true end
    if type(value) ~= "string" then return false end
    return tonumber(value) ~= nil
end

local function shouldDisplayField(fieldName, value)
    if not isEmpty(value) then
        if POSITIVE_ONLY_FIELDS[fieldName] then
            return isPositive(value)
        end
        return true
    end
    return false
end

local function getPBDIBValue(propertyId, args, options)
    if not args.qid or args.qid == "" then
        return nil
    end
    
    local success, result = pcall(function()
        return PBDIB._getValue({
            [1] = propertyId,
            qid = args.qid,
            format = options and options.format,
            fpbd = "ALL"
        })
    end)
    
    if success then
        return result
    else
        return nil
    end
end

local function extractNumber(str)
    if type(str) == 'number' then 
        return str 
    end

    if type(str) ~= 'string' or str == '' then 
        return nil 
    end

    local num = tonumber(str)
    if num then return num end
    
    num = str:match("^%s*(%d+%.?%d*)[%s%a]*$")
    if num then return tonumber(num) end
    
    num = str:match("^%s*(%d+%.?%d*)%a*$")
    if num then return tonumber(num) end
    
    num = str:match("^%s*(%d+,%d+)%s*$")
    if num then return tonumber(num:gsub(",", ".")) end
    
    return nil
end

local State = {}

function State:new()
    local state = {}
    setmetatable(state, self)
    self.__index = self
    state.STYLES = STYLES
    return state
end

function State:getRowStyle(index)
    return index % 2 == 1 and STYLES.ODD_ROW or STYLES.EVEN_ROW 
end

function State:splitByComma(str)
    if not str then return {} end
    local result = {}
    for value in str:gmatch("[^,]+") do
        table.insert(result, mw.text.trim(value))
    end
    return result
end

function State:formatCategoryLink(value, prefix, displayText)
    if isEmpty(value) then return nil end
    
    local normalized = mw.text.trim(value):gsub("^%l", string.upper)
    displayText = displayText or normalized
    
    local result = string.format("[[:Category:%s%s|%s]]",
        prefix,
        normalized,
        displayText
    )
    
    if mw.title.getCurrentTitle().namespace == 0 then
        result = result .. string.format("[[Category:%s%s]]",
            prefix,
            normalized
        )
    end
    
    return result
end

function State:collectNumberedParams(args, baseParam)
    local values = {}
    local numbered = {}
    
    if not isEmpty(args[baseParam]) then
        table.insert(values, {index = 0, value = args[baseParam]})
    end
    
    for param, value in pairs(args) do
        local index = param:match("^" .. baseParam .. "(%d+)$")
        if index and not isEmpty(value) then
            index = tonumber(index)
            if index and index > 0 and index < 100 then
                table.insert(values, {index = index, value = value})
            end
        end
    end
    
    table.sort(values, function(a, b) return a.index < b.index end)
    
    local result = {}
    for _, item in ipairs(values) do
        table.insert(result, item.value)
    end
    
    return result
end

function State:formatField(label, value, fieldName, index)
    if isEmpty(value) then
        return ''
    end
    
    if POSITIVE_ONLY_FIELDS[fieldName] and not isPositive(value) then
        return ''
    end
    
    local rowStyle = self:getRowStyle(index)
    
    return string.format('|-\n! style="%s %s" | \'\'\'%s\'\'\'\n| style="%s text-align:left;" | %s', 
        rowStyle,
        STYLES.LABEL,
        label,
        rowStyle,
        value)
end

function State:formatFeatureList(values, featureType)
    if not values or #values == 0 then return nil end
    
    local displayValues = {}
    local addedCategories = {}
    local isMainNamespace = mw.title.getCurrentTitle().namespace == 0
    
    if featureType == 'foreskin' then
        for _, value in ipairs(values) do
            if value then
                local feature = mw.text.trim(value):lower()
                local mapping = CategoryMapping.MAPPINGS[featureType][feature]
                
                if mapping then
                    local result = string.format("[[:Category:%s|%s]]",
                        mapping.category,
                        mapping.display
                    )
                    
                    if isMainNamespace then
                        result = result .. string.format("[[Category:%s]]",
                            mapping.category
                        )
                    end
                    
                    return result
                end
            end
        end
        return nil
    end
    
    if featureType == 'ass_type' then
        local foundMappings = {}
        local hasMainType = false
        
        for _, value in ipairs(values) do
            if value then
                local features = self:splitByComma(value)
                for _, feature in ipairs(features) do
                    feature = mw.text.trim(feature):lower()
                    
                    for _, mapping in ipairs(CategoryMapping.MAPPINGS[featureType]) do
                        for _, alias in ipairs(mapping.aliases) do
                            if feature == alias:lower() then
                                local isMainSize = mapping.priority >= 1 and mapping.priority <= 3

                                if (not isMainSize or not hasMainType) and not addedCategories[mapping.category] then
                                    table.insert(foundMappings, mapping)
                                    addedCategories[mapping.category] = true
                                    
                                    if isMainSize then
                                        hasMainType = true
                                    end
                                end
                            end
                        end
                    end
                end
            end
        end
        
        table.sort(foundMappings, function(a, b)
            return a.priority < b.priority
        end)
        
        for i, mapping in ipairs(foundMappings) do
            if i > 1 then
                table.insert(displayValues, ", ")
            end
            
            local result = string.format("[[:Category:%s|%s]]",
                mapping.category,
                mapping.display
            )
            
            if isMainNamespace then
                result = result .. string.format("[[Category:%s]]",
                    mapping.category
                )
            end
            
            table.insert(displayValues, result)
        end
        
    else
        for _, value in ipairs(values) do
            if value then
                local features = self:splitByComma(value)
                for _, feature in ipairs(features) do
                    feature = mw.text.trim(feature):lower()
                    
                    for _, mapping in ipairs(CategoryMapping.MAPPINGS[featureType]) do
                        local found = false
                        for _, alias in ipairs(mapping.aliases) do
                            if feature == alias:lower() then
                                found = true
                                if not addedCategories[mapping.category] then
                                    if #displayValues > 0 then
                                        table.insert(displayValues, ", ")
                                    end
                                    
                                    local result = string.format("[[:Category:%s|%s]]",
                                        mapping.category,
                                        mapping.display
                                    )
                                    
                                    if isMainNamespace then
                                        result = result .. string.format("[[Category:%s]]",
                                            mapping.category
                                        )
                                    end
                                    
                                    table.insert(displayValues, result)
                                    addedCategories[mapping.category] = true
                                end
                                break
                            end
                        end
                        if found then break end
                    end
                end
            end
        end
    end
    
    if #displayValues > 0 then
        return table.concat(displayValues)
    end
    
    return nil
end

function p.main(frame)
    local args = frame.args
    if not next(args) then
        args = frame:getParent().args
    end

    args = normalizeKeys(args)
    
    if isEmpty(args.qid) then
        local success, entityId = pcall(mw.wikibase.getEntityIdForCurrentPage)
        if success and entityId then
            args.qid = entityId
        else
            args.qid = nil
        end
    end
    
    local title = mw.title.getCurrentTitle().text
    local state = State:new()

    local personalSection, rowIndex
    local success, result1, result2 = pcall(function()
        return BioboxPersonal.formatPersonalSection(state, args, title)
    end)
    
    if success then
        personalSection, rowIndex = result1, result2
    else
        personalSection = string.format('{| %s\n|-\n! colspan="2" %s | \'\'\'%s\'\'\'', 
            STYLES.INFOBOX, 
            STYLES.HEADER, 
            title)
        rowIndex = 1
    end
    
    local bodySection = ""
    success, result1 = pcall(function()
        return BioboxBody.formatBodySection(state, args, rowIndex)
    end)
    
    if success then
        bodySection = result1
    end
    
    local personalPagesSection, ppRowIndex = {}, rowIndex
    success, result1, result2 = pcall(function()
        return BioboxPersonalPages.formatPersonalPagesSection(state, args, rowIndex)
    end)
    
    if success then
        personalPagesSection, ppRowIndex = result1, result2
    end
    
    local databasesSection, dbRowIndex = {}, ppRowIndex
    success, result1, result2 = pcall(function()
        return BioboxDatabases.formatDatabasesSection(state, args, ppRowIndex)
    end)
    
    if success then
        databasesSection, dbRowIndex = result1, result2
    end
    
    if isEmpty(personalSection) or not string.find(personalSection, '{|%s+class="infoboxnew"') then
        personalSection = string.format('{| %s\n|-\n! colspan="2" %s | \'\'\'%s\'\'\'', 
            STYLES.INFOBOX, 
            STYLES.HEADER, 
            title)
    end
    
    local result = personalSection .. '\n' .. bodySection
    
    if #personalPagesSection > 0 then
        result = result .. '\n' .. table.concat(personalPagesSection, '\n')
    end
    
    if #databasesSection > 0 then
        result = result .. '\n' .. table.concat(databasesSection, '\n')
    end

    if not isEmpty(args.qid) then
        local success, pbcLink = pcall(mw.wikibase.getSitelink, args.qid)
        if success and pbcLink then
            result = result .. '\n|-class="stop-section-collapse"\n! colspan="2" style="background:#F0E68C;text-align:center;" | [[File:Pbd.svg | 45px | alt=' .. args.qid .. ' | link=pbd:' .. args.qid .. ']]&nbsp;[[:pbd:' .. args.qid .. '|' .. pbcLink .. ']]&nbsp;([[:pbd:' .. args.qid .. '|' .. args.qid .. ']])'
        end

        local newFrame = {
            args = {
                qid = args.qid,
                wiki = "pbcimagerepo"
            }
        }
        
        local imageRepoLink
        success, imageRepoLink = pcall(function()
            return PBDIB.getSiteLink(newFrame)
        end)
        
        if success and imageRepoLink and imageRepoLink ~= '' then
            result = result .. '\n|-class="stop-section-collapse"\n! colspan="2" style="background:#F0E68C;text-align:center;" | [[File:Image-icon.svg | 18px | link=:' .. imageRepoLink .. ']]&nbsp;[[:' .. imageRepoLink .. '| PBC Image Repository]]'
        end

        newFrame.args.wiki = "pbcvideorepo"
        local videoRepoLink
        success, videoRepoLink = pcall(function()
            return PBDIB.getSiteLink(newFrame)
        end)
        
        if success and videoRepoLink and videoRepoLink ~= '' then
            result = result .. '\n|-class="stop-section-collapse"\n! colspan="2" style="background:#F0E68C;text-align:center;" | [[File:Video-icon.svg | 18px | link=:' .. videoRepoLink .. ']]&nbsp;[[:' .. videoRepoLink .. '| PBC Video Repository]]'
        end
    end

    result = result .. '\n|}'

    local categories = {}
    if not isEmpty(args.qid) then
        success, categories = pcall(function() 
            return BioboxPersonal.getPBDCategories(args)
        end)
        
        if not success then
            categories = {}
        end
    end
    
    if #categories > 0 then
        local categoryStrings = {}
        for _, category in ipairs(categories) do
            table.insert(categoryStrings, '[[Category:' .. category .. ']]')
        end
        result = result .. '\n' .. table.concat(categoryStrings, '\n')
    end

    return result
end

return p