xrforge-v2/src/plugin/diskscan.lua

179 lines
6 KiB
Lua
Raw Normal View History

local dir = require "opendirectory"
2026-07-28 08:50:24 +02:00
app.on('init', function()
print("scanning experiences (this make take a while..)")
app.opts.plugin_diskscan_dirname = app.opts.plugin_diskscan_dir:gsub("^[.]?[/]?","")
2026-08-18 15:30:10 +02:00
-- swap between internal / external version of diskscan_dir
if app.opts.plugin_diskscan_dir:match("^/zip/") then
if util.fileExist(app.opts.plugin_diskscan_dir) then
print("ℹ️ serving " .. app.opts.plugin_diskscan_dir .. " from local disk")
app.opts.plugin_diskscan_dir = app.opts.plugin_diskscan_dir:gsub("^/zip/","")
app.set('app.opts', app.opts)
end
else
if not util.fileExist(app.opts.plugin_diskscan_dir) then
print("ℹ️ serving " .. app.opts.plugin_diskscan_dir .. " from internal (executable)")
app.opts.plugin_diskscan_dir = '/zip/' .. util.stripPath(app.opts.plugin_diskscan_dir)
app.set('app.opts', app.opts)
end
end
2026-07-28 08:50:24 +02:00
app.plugin.diskscan.scan(app.opts.plugin_diskscan_dir)
end)
-- this registers the plugin UI /funcs
return {
name = "Files",
tab = "<img src='img/drive.svg' class='icon invert'/> Files",
info = '',
opts = {
{
key='app.opts.plugin_diskscan_dir',
title='Directory',
info="Directory to scan for experiences (use '.' for current) ",
default="./myverse",
values=''
}
},
shouldHideFile = function(name)
return name == ".." -- parent
or name == "util" -- repository
2026-08-24 13:29:35 +02:00
or name:match("^%.[a-zA-Z0-9_-]") -- hidden
or name == "src" -- repository
or name == "result" -- repository
end,
scan = function(scandir)
local me = app.plugin.diskscan
local seen = {symlinks={}}
-- ensure rootdir as experience
2026-08-24 13:29:35 +02:00
app.addExperience({
path = scandir,
url = "/" .. util.stripPath(scandir),
name = scandir:gsub(".*/",""),
2026-08-18 15:30:10 +02:00
thumbnail = "",
title = util.dehyphenate( scandir:gsub(".*/","") ),
file = { ino = scandir },
id = scandir
2026-08-24 13:29:35 +02:00
},scandir)
me.scanDir(scandir, nil, seen )
-- deal with (circular) symlinks
foreach( seen.symlinks, function(ino,experience)
if not me.shouldHideFile(experience.name) then
local refItem = seen[experience.id_target]
if refItem then
print("ℹ️ ".. experience.path )
print("✅ └─ plugin/diskscan: detected symlink..creating portal")
experience.file = refItem.file
experience.portal = refItem
2026-08-24 13:29:35 +02:00
app.pub("scan_experience" .. (experience.dir and '' or '_file') , nil, experience)
app.addExperience(experience,ino)
end
end
end)
-- cleanup file handles
foreach( app.cache.items, function(k,v)
-- remove file attributes (which are closed already)
2026-08-02 14:00:56 +02:00
if v.file then
v.file.stat = nil
v.file.attr = nil
v.file.state = nil
end
end)
2026-09-16 13:43:33 +02:00
-- sort & apply dirs to plugin options
table.sort( app.cache.dirs)
2026-09-16 13:43:33 +02:00
foreach( app.plugin, function(k,plugin)
foreach( plugin.opts, function(k,opt)
if opt.type == 'dir' then
opt.values = app.cache.dirs
end
end)
end)
end,
scanDir = function(scandir,parent,seen)
local me = app.plugin.diskscan
parent = parent or app.cache.items[scandir]
app.cache.dirs[ scandir ] = util.stripPath(scandir)
-- scan dirs
local scanFile = function(path,stat,state,name,kind,ino,off,attr,fullpath)
local experience = {
path = fullpath,
url = "/" .. util.stripPath(fullpath),
name = name,
title = util.dehyphenate( name ),
sidecarfile = {},
thumbnail = '',
tag = {},
id = ino,
file = {stat=stat,state=state,kind=kind,ino=ino,off=off,attr=attr,fullpath=fullpath,name=name,path=path}
}
experience.parent = parent
if (kind == unix.DT_LNK) then
2026-08-24 13:29:35 +02:00
experience.symlink = true
local stat, err = unix.stat(fullpath)
2026-08-02 14:00:56 +02:00
if stat then
2026-08-24 13:29:35 +02:00
experience.id_target = stat:ino() -- stat follows symlink by default
local realpath = unix.realpath(fullpath)
state,err = unix.opendir(realpath)
if not err then
experience.symlink = true
experience.dir = true
state:close()
end
2026-08-02 14:00:56 +02:00
seen.symlinks[ ino ] = experience
end
end
2026-08-24 13:29:35 +02:00
--local already_seen = seen[ino] and seen[ino].parent.file.ino == experience.parent.file.ino and true or false -- process once
--if already_seen and not experience.symlink then return end
-- found directory
2026-08-24 13:29:35 +02:00
if not me.shouldHideFile(name) and
( (kind == unix.DT_DIR and kind ~= unix.DT_LNK) or experience.dir )
then
print("✅ ".. fullpath )
2026-07-31 14:41:34 +02:00
experience.dir = true
experience.portal3D = true -- can be viewed as 3d portal
app.pub("scan_experience", nil, experience)
2026-08-24 13:29:35 +02:00
app.addExperience(experience,ino)
2026-08-02 14:00:56 +02:00
-- check for directory thumbnail sidecarfile
local thumbExt = {"png","jpg","webp"}
foreach( thumbExt, function(k,ext)
2026-08-03 19:19:07 +02:00
local files = { fullpath .. '.' .. ext, fullpath .. '/' .. name .. '.' .. ext }
foreach( files, function(kk,thumbnailFile)
if util.fileExist( thumbnailFile ) then
experience.thumbnail = "/" .. util.stripPath(thumbnailFile)
print("✅ └─ plugin/diskscan: detected .".. ext:lower() .. " thumbnail file: " .. thumbnailFile)
end
end)
2026-08-02 14:00:56 +02:00
end)
-- scan children
me.scanDir(fullpath,experience,seen,symlinks)
end
---- found file
2026-08-24 13:29:35 +02:00
if not me.shouldHideFile(name) and
( (kind ~= unix.DT_DIR and kind ~= unix.DT_LNK) or not experience.dir )
then
trace("ℹ️ ".. fullpath)
experience.tag.file = true
app.pub("scan_experience_file", nil, experience)
local size = attr:size()
end
2026-08-24 13:29:35 +02:00
-- remember file/parent relationship
seen[ino] = experience
end
local dref, derr;
dref, derr = dir.foreach( scandir, scanFile )
if not derr then dref:close() end
end
}