Jump to content

Module:FileMedia

Википедиа — Чөлөөт нэвтэрхий толь
local FileMedia = { suite  = "FileMedia",
                    serial = "2023-01-01",
                    item   = 24765326 }
--[=[
FileMedia
]=]


local Failsafe = FileMedia
FileMedia.extension = { storage = "FileMediaExt.tab" }



FileMedia.getExtension = function ( ask )
    -- Retrieve "file name extension" from file name
    -- Precondition:
    --     ask  -- file name; string, or nil
    -- Postcondition:
    --     Returns string, or false
    local r = false
    local s = FileMedia.getTitle( ask )
    if s then
        s = ask:match( ".%.(%w+)%s*$" )
        if s then
            r = s:lower()
        end
    end
    return r
end -- FileMedia.getExtension()



FileMedia.getHeight = function ( ask )
    -- Retrieve image height
    -- Precondition:
    --     ask  -- file name or title; string, or nil
    -- Postcondition:
    --     Returns number, or false or nil
    local r = false
    local s = FileMedia.getTitle( ask )
    if s then
        local d = mw.title.makeTitle( "File", s )
        if d and d.file then
            r = d.file.height
        end
    end
    return r
end -- FileMedia.getHeight()



FileMedia.getHeightWidth = function ( ask )
    -- Retrieve image height x width
    -- Precondition:
    --     ask  -- file name or title; string, or nil
    -- Postcondition:
    --     Returns string like "123x456px", or false or nil
    local r = false
    local s = FileMedia.getTitle( ask )
    if s then
        local d = mw.title.makeTitle( "File", s )
        if d and d.file then
            r = d.file.height
            if r then
                r = string.format("%dx%dpx", r, d.file.width)
            end
        end
    end
    return r
end -- FileMedia.getHeightWidth()



FileMedia.getMimeType = function ( ask )
    -- Retrieve file MimeType
    -- Precondition:
    --     ask  -- file name or title; string, or nil
    -- Postcondition:
    --     Returns string, or false or nil
    local r = false
    local s = FileMedia.getTitle( ask )
    if s then
        local d = mw.title.makeTitle( "File", s )
        if d and d.file then
            r = d.file.mimeType
        end
    end
    return r
end -- FileMedia.getMimeType()



FileMedia.getPageCount = function ( ask )
    -- Retrieve number of file pages (paged media fragments)
    -- Precondition:
    --     ask  -- file name or title; string, or nil
    -- Postcondition:
    --     Returns number (0 if not paged media), or false or nil
    local r = false
    local s = FileMedia.getTitle( ask )
    if s then
        local d = mw.title.makeTitle( "File", s )
        if d and d.file then
            r = d.file.pages
            if r then
                r = #r
            elseif d.file.size then
                r = 0
            end
        end
    end
    return r
end -- FileMedia.getPageCount()



FileMedia.getPages = function ( ask )
    -- Retrieve table of file page sizes (paged media fragments)
    -- Precondition:
    --     ask  -- file name or title; string, or nil
    -- Postcondition:
    --     Returns table, or false or nil
    local r = false
    local s = FileMedia.getTitle( ask )
    if s then
        local d = mw.title.makeTitle( "File", s )
        if d and d.file then
            r = d.file.pages
        end
    end
    return r
end -- FileMedia.getPages()



FileMedia.getSize = function ( ask )
    -- Retrieve file size
    -- Precondition:
    --     ask  -- file name or title; string, or nil
    -- Postcondition:
    --     Returns number, or false or nil
    local r = false
    local s = FileMedia.getTitle( ask )
    if s then
        local d = mw.title.makeTitle( "File", s )
        if d and d.file then
            r = d.file.size
        end
    end
    return r
end -- FileMedia.getSize()



FileMedia.getTitle = function ( ask )
    -- Retrieve file page title from page name
    -- Precondition:
    --     ask  -- file name; string, or nil
    -- Postcondition:
    --     Returns string, or false if not a valid file
    local r = false
    if FileMedia.isType( ask, "file" ) then
        local space, s = ask:match( "^([^:]+):(.+)$" )
        if space then
            if FileMedia.isSpacing( space ) then
                r = mw.text.trim( s )
            end
        else
            r = mw.text.trim( ask )
        end
    end
    return r
end -- FileMedia.getTitle()



FileMedia.getType = function ( ask )
    -- Retrieve supposed file type from "file name extension"
    -- Precondition:
    --     ask  -- file name; string, or nil
    -- Postcondition:
    --     Returns string, or false
    --             "audio"
    --             "data"
    --             "paged"
    --             "pixel"
    --             "program"
    --             "style"
    --             "vector"
    --             "video"
    local r = false
    if ask then
        local s = ask:match( ".%.(%w+)%s*$" )
        if s then
            if not FileMedia.extension.data then
                local lucky, data
                lucky, data = pcall( mw.ext.data.get,
                                     FileMedia.extension.storage )
                if type( data ) == "table" then
                    FileMedia.extension.data = data.data
                else
                    FileMedia.extension.data = true
                end
            end
            if type( FileMedia.extension.data ) == "table" then
                local e
                s = s:lower()
                for i = 1, #FileMedia.extension.data do
                    e = FileMedia.extension.data[ i ]
                    if type( e ) == "table"  and
                       e[ 1 ] == s then
                        r = e[ 2 ]
                        break   -- for i
                    end
                end   -- for i
            end
        end
    end
    return r
end -- FileMedia.getType()



FileMedia.getWidth = function ( ask )
    -- Retrieve image width
    -- Precondition:
    --     ask  -- file name or title; string, or nil
    -- Postcondition:
    --     Returns number, or false or nil
    local r = false
    local s = FileMedia.getTitle( ask )
    if s then
        local d = mw.title.makeTitle( "File", s )
        if d and d.file then
            r = d.file.width
        end
    end
    return r
end -- FileMedia.getWidth()



FileMedia.isFile = function ( ask )
    -- Is this a valid (existing) file title or file name?
    -- Precondition:
    --     ask  -- file title or file name; string, or nil
    -- Postcondition:
    --     Returns boolean
    -- Expensive function.
    local r
    local s = FileMedia.getTitle( ask )
    if s then
        r = mw.title.makeTitle( "File", s ).fileExists
    else
        r = false
    end
    return r
end -- FileMedia.isFile()



FileMedia.isSpacing = function ( ask )
    -- Is presumed space name not conflicting with files?
    -- Precondition:
    --     ask  -- possible space name; string, or nil
    -- Postcondition:
    --     Returns boolean; false: conflict
    local r = true
    if ask then
        local space = mw.site.namespaces[ mw.text.trim( ask ) ]
        if space then
            space = space.canonicalName
            r     = ( space == "Media"  or  space == "File" )
        end
    end
    return r
end -- FileMedia.isSpacing()



FileMedia.isType = function ( ask, against )
    -- Does file name match type expectation?
    -- Precondition:
    --     ask      -- file name; string, or nil
    --     against  -- expectation; generic or "file" or "image" or any
    -- Postcondition:
    --     Returns boolean
    local r = false
    local s = FileMedia.getType( ask )
    if s then
        local scope
        if against == "file" then
            scope = "audio paged pixel vector video"
        elseif against == "image" then
            scope = "paged pixel vector"
        end
        if scope then
            local suffix = ask:match( ".%.(%w+)%s*$" )
            if suffix  and  suffix:lower() ~= "doc" then
                r = scope:match( s )
            end
        else
            r = ( s == against )
        end
        if r then
            s = ask:match( "^%s*([^:]+)%s*:" )
            r = FileMedia.isSpacing( s )
        end
    end
    return r
end -- FileMedia.isType()



FileMedia.setParSize = function ( assign, atleast, ahead )
    -- Check or adapt transclusion parameter for size
    -- Precondition:
    --     assign   -- size parameter; string, or nil
    --     atleast  -- fallback value; string, or nil
    --     ahead    -- start with pipe, if not empty; boolean, or nil
    -- Postcondition:
    --     Returns px string, if valid or corrected, else false
    local r = false
    if type( assign ) == "string" then
        local s = mw.text.trim( assign )
        if s ~= "" then
            if s:match( "^[1-9]%d?%d?%d?$" ) then
                r = s .. "px"
            else
                s = s:lower()
                if s:match( "%d$" ) then
                    s = s .. "px"
                elseif not s:match( "%dpx$" ) then
                    s = false
                end
                if s then
                    if s:match( "^[1-9]%d?%d?%d?px$" )  or
                       s:match( "^[1-9]%d?%d?%d?x[1-9]%d?%d?%d?px$" )  or
                       s:match( "^x[1-9]%d?%d?%d?px$" ) then
                        r = s
                    end
                end
            end
        end
    end
    if not r and atleast then
        r = atleast
    end
    if r and ahead then
        r = "|" .. r
    end
    return r
end -- FileMedia.setParSize()



Failsafe.failsafe = function ( atleast )
    -- Retrieve versioning and check for compliance
    -- Precondition:
    --     atleast  -- string, with required version
    --                         or wikidata|item|~|@ or false
    -- Postcondition:
    --     Returns  string  -- with queried version/item, also if problem
    --              false   -- if appropriate
    -- 2020-08-17
    local since = atleast
    local last    = ( since == "~" )
    local linked  = ( since == "@" )
    local link    = ( since == "item" )
    local r
    if last  or  link  or  linked  or  since == "wikidata" then
        local item = Failsafe.item
        since = false
        if type( item ) == "number"  and  item > 0 then
            local suited = string.format( "Q%d", item )
            if link then
                r = suited
            else
                local entity = mw.wikibase.getEntity( suited )
                if type( entity ) == "table" then
                    local seek = Failsafe.serialProperty or "P348"
                    local vsn  = entity:formatPropertyValues( seek )
                    if type( vsn ) == "table"  and
                       type( vsn.value ) == "string"  and
                       vsn.value ~= "" then
                        if last  and  vsn.value == Failsafe.serial then
                            r = false
                        elseif linked then
                            if mw.title.getCurrentTitle().prefixedText
                               ==  mw.wikibase.getSitelink( suited ) then
                                r = false
                            else
                                r = suited
                            end
                        else
                            r = vsn.value
                        end
                    end
                end
            end
        end
    end
    if type( r ) == "nil" then
        if not since  or  since <= Failsafe.serial then
            r = Failsafe.serial
        else
            r = false
        end
    end
    return r
end -- Failsafe.failsafe()



-- Export
local p = { }



p.getExtension = function ( frame )
    -- Retrieve "file name extension" from page title or name
    --     1  -- file title or name
    local lucky, r = pcall( FileMedia.getExtension,
                            frame.args[ 1 ] )
    return r or ""
end -- p.getExtension



p.getHeight = function ( frame )
    -- Retrieve image height from page title or name
    --     1  -- file title or name
    local lucky, r = pcall( FileMedia.getHeight,
                            frame.args[ 1 ] )
    return r or ""
end -- p.getHeight



p.getHeightWidth = function ( frame )
    -- Retrieve image height x width from page title or name
    --     1  -- file title or name
    local lucky, r = pcall( FileMedia.getHeightWidth,
                            frame.args[ 1 ] )
    return r or ""
end -- p.getHeightWidth



p.getMimeType = function ( frame )
    -- Retrieve MIME type from page title or name
    --     1  -- file title or name
    local lucky, r = pcall( FileMedia.getMimeType,
                            frame.args[ 1 ] )
    return r or ""
end -- p.getMimeType



p.getPageCount = function ( frame )
    -- Retrieve number of file pages (paged media fragments) from page title or name
    --     1  -- file title or name
    local lucky, r = pcall( FileMedia.getPageCount,
                            frame.args[ 1 ] )
    return r or ""
end -- p.getPageCount



p.getSize = function ( frame )
    -- Retrieve file size from page title or name
    --     1  -- file title or name
    local lucky, r = pcall( FileMedia.getSize,
                            frame.args[ 1 ] )
    return r or ""
end -- p.getSize



p.getTitle = function ( frame )
    -- Retrieve file title from page title or name
    --     1  -- file title or name
    local lucky, r = pcall( FileMedia.getTitle,
                            frame.args[ 1 ] )
    return r or ""
end -- p.getTitle



p.getType = function ( frame )
    -- Retrieve supposed file type from "file name extension"
    --     1  -- file title or name
    local lucky, r = pcall( FileMedia.getType,
                            frame.args[ 1 ] )
    return r or ""
end -- p.getType



p.getWidth = function ( frame )
    -- Retrieve file width from page title or name
    --     1  -- file title or name
    local lucky, r = pcall( FileMedia.getWidth,
                            frame.args[ 1 ] )
    return r or ""
end -- p.getWidth



p.isFile = function ( frame )
    -- Is this a valid (existing) file title or file name?
    --     1  -- file name; with or without namespace
    -- Expensive function.
    local lucky, r = pcall( FileMedia.isFile,
                            frame.args[ 1 ] )
    return r and "1" or ""
end -- p.isFile



p.isType = function ( frame )
    -- Does file name match type expectation?
    --     1  -- file name
    --     2  -- expected
    local r        = false
    local supposed = frame.args[ 2 ]
    if supposed then
        supposed = supposed:match( "^%s*(%w+)%s*$" )
        if supposed then
            local lucky
            lucky, r = pcall( FileMedia.isType,
                              frame.args[ 1 ],
                              supposed:lower() )
        end
    end
    return r and "1" or ""
end -- p.isType



p.setParSize = function ( frame )
    -- Check or adapt transclusion parameter [ 1 ] for size
    -- Returns px string, if valid or corrected, else empty
    --         Fallback to parameter [ 2 ]
    local lead = frame.args.pipe
    local r
    if lead  and
       ( lead == ""  or  lead == "0" ) then
        lead = false
    end
    r = FileMedia.setParSize( frame.args[ 1 ],
                              frame.args[ 2 ],
                              lead )
    return  r or ""
end -- p.setParSize



p.failsafe = function ( frame )
    -- Versioning interface
    local s = type( frame )
    local since
    if s == "table" then
        since = frame.args[ 1 ]
    elseif s == "string" then
        since = frame
    end
    if since then
        since = mw.text.trim( since )
        if since == "" then
            since = false
        end
    end
    return Failsafe.failsafe( since )  or  ""
end -- p.failsafe()



p.FileMedia = function ()
    return FileMedia
end -- p.FileMedia



setmetatable( p,  { __call = function ( func, ... )
                                 setmetatable( p, nil )
                                 return Failsafe
                             end } )

return p