local dir = require "opendirectory" app.on('init', function() print("scanning experiences (this make take a while..)") app.opts.plugin_diskscan_dirname = app.opts.plugin_diskscan_dir:gsub("^[.]?[/]?","") app.plugin.diskscan.scan(app.opts.plugin_diskscan_dir) end) -- this registers the plugin UI /funcs return { name = "Local Content", 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 or name:match("^%.") -- 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 app.cache.items[ scandir ] = { path = scandir, url = "/" .. util.stripPath(scandir), name = scandir:gsub(".*/",""), title = scandir:gsub(".*/",""), file = { ino = scandir }, id = 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 app.pub("scan_experience", nil, experience) app.cache.items[experience.id] = experience end end end) -- cleanup file handles foreach( app.cache.items, function(k,v) -- remove file attributes (which are closed already) v.file.stat = nil v.file.attr = nil v.file.state = nil end) end, scanDir = function(scandir,parent,seen) local me = app.plugin.diskscan parent = parent or app.cache.items[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 = 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 -- check for thumbnail local thumbExt = {"png","jpg","webp"} foreach( thumbExt, function(k,ext) local thumbnailFile = fullpath .. "/" .. name .. "." .. ext if util.fileExist( thumbnailFile ) then print("✅ └─ plugin/diskscan: detected .".. ext:lower() .. " thumbnail file") experience.thumbnail = "/" .. util.stripPath(thumbnailFile) end end) if seen[ino] then return end -- dont process dirs/files twice if (kind == unix.DT_LNK) then local stat, err = unix.stat(fullpath) experience.id_target = stat:ino() seen.symlinks[ ino ] = experience return end -- found directory if (kind == unix.DT_DIR and kind ~= unix.DT_LNK) and not me.shouldHideFile(name) then seen[ino] = experience -- prevent recursion with symlinks print("✅ ".. fullpath .. " " ..ino) experience.dir = true app.pub("scan_experience", nil, experience) app.cache.items[ino] = experience me.scanDir(fullpath,experience,seen,symlinks) end ---- found file if (kind ~= unix.DT_DIR and kind ~= unix.DT_LNK) and not me.shouldHideFile(name) then seen[ino] = experience.file -- prevent recursion with symlinks trace("ℹ️ ".. fullpath) experience.tag.file = true app.pub("scan_experience_file", nil, experience) local size = attr:size() end end local dref, derr; dref, derr = dir.foreach( scandir, scanFile ) if not derr then dref:close() end end }