diff --git a/.env b/.env index f0395e0..8f0b117 100644 --- a/.env +++ b/.env @@ -1,6 +1,6 @@ # aliases -build(){ $(pwd)/src/util/xrforge.sh build; } -rebuild(){ $(pwd)/src/util/xrforge.sh rebuild; } +build(){ $(pwd)/src/util/build.sh build; } +rebuild(){ $(pwd)/src/util/build.sh rebuild; } # forgejo server hook #test "$GITEA_ROOT_URL" = "https://xrforge.isvery.ninja/" && { diff --git a/src/.init.lua b/src/.init.lua index 8ac293b..19a8029 100644 --- a/src/.init.lua +++ b/src/.init.lua @@ -54,6 +54,7 @@ app.opts = require('config')(app) -- load system plugins (in specific order for admin panel) app.plugin.global = app.addPlugin('plugin/global') +app.plugin.pubnix = app.addPlugin('plugin/pubnix') app.plugin.diskscan = app.addPlugin('plugin/diskscan') app.plugin.convert = app.addPlugin('plugin/convert') app.plugin.moderation = app.addPlugin('plugin/moderation') @@ -76,7 +77,7 @@ print = function(...) Log(kLogInfo, ... or "''") end -- nice redbean logging fro -- init URL router app.url['^/data'] = '/data.lua' -- setup custom file endpoint -app.get('^/$', app.plugin.global.middleware.homepage_2D_or_3D ) +app.use( app.plugin.global.middleware.homepage_2D_or_3D ) app.url['^/admin[/]?$'] = '/page/admin/index.lua' app.get('^/design[/]?$', util.pagerender('page/design.html')) diff --git a/src/.lua/util.lua b/src/.lua/util.lua index 4a41541..47b1735 100644 --- a/src/.lua/util.lua +++ b/src/.lua/util.lua @@ -327,7 +327,7 @@ end function util.stripPath(str) - return str:gsub("^./",""):gsub("^/",""):gsub("/$","") + return str:gsub("^/zip/",""):gsub("^./",""):gsub("^/",""):gsub("/$","") end -- WARNING: this is a destructive function which renders the redbean server inactive diff --git a/src/css/xrforge.css b/src/css/xrforge.css index e6e0e93..931686f 100644 --- a/src/css/xrforge.css +++ b/src/css/xrforge.css @@ -151,7 +151,7 @@ form > table > tbody > tr > td:nth-child(3) { .primary { color: #ff33Ff;} .secondary { color: #7070ff;} .btn a.primary{ background: #ff33Ff; color:#000} -.btn a.secondary{ background: #224; color: #83f; } +.btn a.secondary{ background: #000; color: #83f; } .pad1{ padding:20px; diff --git a/src/img/share.svg b/src/img/share.svg new file mode 100644 index 0000000..1e9e83d --- /dev/null +++ b/src/img/share.svg @@ -0,0 +1,12 @@ + + + \ No newline at end of file diff --git a/src/myverse/janusxr_tutorial/AFRAME.jpg b/src/myverse/janusxr_tutorial/AFRAME.jpg index 272b50c..9105c08 100644 Binary files a/src/myverse/janusxr_tutorial/AFRAME.jpg and b/src/myverse/janusxr_tutorial/AFRAME.jpg differ diff --git a/src/myverse/janusxr_tutorial/AFRAME/index.html b/src/myverse/janusxr_tutorial/AFRAME/index.html index f94228c..d80892b 100644 --- a/src/myverse/janusxr_tutorial/AFRAME/index.html +++ b/src/myverse/janusxr_tutorial/AFRAME/index.html @@ -1,3 +1,4 @@ + diff --git a/src/page/dir.html b/src/page/dir.html index 029b863..c9ec6f4 100644 --- a/src/page/dir.html +++ b/src/page/dir.html @@ -5,7 +5,7 @@ ${header}

${opts.title}


-
${opts.plugin_global_subtitle}
+
${opts.plugin_global_subtitle}

]]) @@ -21,20 +21,23 @@ end} {if items then for i=1,#items do local item = items[i] - local icon = 'list-tree' - local thumbnail = '' - if #item.thumbnail > 0 then thumbnail = 'style="background-image: url(' .. EscapeFragment( util.stripPath(item.thumbnail) ) .. ');"' end - if item.view3D or item.portal3D == false then icon = 'play' end - print([[ - - ]]) + local visible = item.view2D == nil or (item.view2D ~= nil and item.view2D ~= false) + if visible then + local icon = 'list-tree' + local thumbnail = '' + if #item.thumbnail > 0 then thumbnail = 'style="background-image: url(' .. EscapeFragment( util.stripPath(item.thumbnail) ) .. ');"' end + if item.view3D or item.portal3D == false then icon = 'play' end + print([[ + + ]]) + end end end} {if itemsremote then @@ -46,7 +49,7 @@ end} if item.view3D or item.portal3D == false then icon = 'play' end print([[
- +
 ]] .. item.title .. [[ diff --git a/src/page/dir.lua b/src/page/dir.lua index d777100..9442cdc 100644 --- a/src/page/dir.lua +++ b/src/page/dir.lua @@ -30,17 +30,13 @@ return { -- "parent = " .. util.stripPath(v.parent.path) .. " " .. -- "matchpath = " .. util.stripPath(matchpath) -- ) - if match(v.path, matchpath) then -- show parent folder if any - local parent = app.cache.items[ v.parent.id ] - if v.portal then - trace("-- portal redirect") - redirect = v.portal.url - end - if match(parent.path, app.opts.plugin_diskscan_dir) then -- add rootfolder if needed - local root = app.cache.items[ app.opts.plugin_diskscan_dir ] - --res.items[ root.id ] = root - end - end + --if match(v.path, matchpath) then -- add parent folder if any + --res.items[ v.parent.id ] = v.parent + -- if match(v.parent.path, app.opts.plugin_diskscan_dir) then -- add rootfolder if needed + -- local root = app.cache.items[ app.opts.plugin_diskscan_dir ] + -- res.items[ root.id ] = root + -- end + --end -- add items from dir if match(v.parent.path, matchpath) then @@ -49,6 +45,15 @@ return { res.items[ v.id ] = v res.parent = parent end + if not isroot then + res.items[ v.parent.id ] = { + view2D = false, + url = v.parent.url, + title = "parent world", + name = "parent world", + thumbnail = '', + } + end end end end @@ -57,7 +62,9 @@ return { local data = util.merge({ url = req.param.url, -- query hint to render janus.url in iframe (index.html) items = {}, - parent=res.parent + referrer = isroot and app.opts.plugin_federation_parent_url or util.getURL(), + parent=res.parent, + template=res.template },{ opts = app.opts }) local i = 0 foreach( res.items, function(k,v) @@ -70,10 +77,13 @@ return { end -- prioritize markup experience above binary 3D files as experience containers if not data.item or (isMarkupExperience(v) and not isMarkupExperience(data.item)) then + -- update referrer url + data.referrer = util.getURL( v.view3D and v.parent.parent.url or v.parent.url ) data.item = v data.title = data.item.title data.parent = v.parent data.url = app.opts.baseurl .. util.stripPath(v.url) -- because we are running in iframe + -- .. EscapeFragment( (v.url:match("#") and "&" or "#" ) .. 'janus.referrer=' .. EscapeFragment(v.referrer) ) if v.janusxr and (v.janusxr.jml or v.janusxr.aframe) then -- what to do here? no generated portals? data.janusxr = app.tpl( util.readfile(v.path), data ) diff --git a/src/page/footer.html b/src/page/footer.html index b3ad9c1..6c79cbc 100644 --- a/src/page/footer.html +++ b/src/page/footer.html @@ -17,7 +17,7 @@ NLNET
- View from XR Device
+ View from XR Device
Content overview
About
diff --git a/src/page/header.html b/src/page/header.html index be1e8ac..cfb4aba 100644 --- a/src/page/header.html +++ b/src/page/header.html @@ -37,6 +37,32 @@ {if true then print( app.opts.plugin_global_topmenu_html:gsub("\n"," ") ) end} + {if template == "page/dir.html" then + print([[ ]]) + end} + {if template == "page/index.html" then + local sharedata = { + title = (item and item.title or opts.plugin_global_title) + } + print([[ + + + + + ]]) + end} diff --git a/src/page/index.html b/src/page/index.html index f5fde5c..6a83bb8 100644 --- a/src/page/index.html +++ b/src/page/index.html @@ -3,7 +3,7 @@ ${header}
- + {if item and item.parent and item.parent.info then print([[ @@ -35,8 +35,9 @@ end} url = document.location.origin + document.location.pathname + '?url=' + url } }catch(e){} - const isFileWithExtension = url.replace( new RegExp('./','g'),"").match("\\.") - if( !isFileWithExtension ){ + const isFileWithExtension = url.replace( new RegExp('.*/','g'),"").match("\\.") ? true : false + //url = url.replace(/#.*/,'') + '#janus.referrer=' + encodeURIComponent(document.location.href) + if( !isFileWithExtension ){ window.history.replaceState( url, iframe.contentDocument.title, url ); } setTimeout( () => { diff --git a/src/page/janusxr.html b/src/page/janusxr.html index 2c7300c..ee22e7e 100644 --- a/src/page/janusxr.html +++ b/src/page/janusxr.html @@ -34,8 +34,8 @@ end} {if item then print([[ - - + + ]]) else local room = app.opts.plugin_janusxr_portalroom @@ -47,10 +47,14 @@ end} end} {if true then - function addPortal(id,x,v,url,i,z,thumb,rotation,scale) + function addPortal(id,x,v,url,i,z,thumb,rotation,scale,item) print('\t') print('\t ') print('\t ') + --TODO: fix janusweb paragraph for markdown urls + --if item.README ~= nil then + -- print('\t ') + --end print('\t') end end} @@ -66,7 +70,7 @@ end} end if v.dir then url = url .. "/" end if v.redirect then url = v.redirect end -- dont wrap standalone glb's in janusxr - addPortal('dir',center, v, url,i, -4, thumb, '0 0 0', '0.2 0.2 0.2') + addPortal('dir',center, v, url,i, -4, thumb, '0 0 0', '0.2 0.2 0.2', v) end end} {if not item and itemsremote and #itemsremote > 0 then @@ -80,7 +84,7 @@ end} end if v.dir then url = url .. "/" end if v.redirect then url = v.redirect end -- dont wrap standalone glb's in janusxr - addPortal('remote',center, v, url,i, 4, thumb, '0 180 0', '0.2 0.2 0.2') + addPortal('remote',center, v, url,i, 4, thumb, '0 180 0', '0.2 0.2 0.2',v) end print([[ @@ -88,6 +92,7 @@ end} end} + ${janusxr_jml_deco} ${opts.plugin_janusxr_jml} diff --git a/src/plugin/diskscan.lua b/src/plugin/diskscan.lua index f63d567..71b2795 100644 --- a/src/plugin/diskscan.lua +++ b/src/plugin/diskscan.lua @@ -3,6 +3,20 @@ 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("^[.]?[/]?","") + -- 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 app.plugin.diskscan.scan(app.opts.plugin_diskscan_dir) end) @@ -36,6 +50,7 @@ return { path = scandir, url = "/" .. util.stripPath(scandir), name = scandir:gsub(".*/",""), + thumbnail = "", title = scandir:gsub(".*/",""):gsub("-"," "), file = { ino = scandir }, id = scandir diff --git a/src/plugin/federation.lua b/src/plugin/federation.lua index 0705157..d2fe51c 100644 --- a/src/plugin/federation.lua +++ b/src/plugin/federation.lua @@ -24,7 +24,8 @@ app.on('dir', function(opts) table.insert(itemsremote, { title = url:gsub(".*//",""), thumbnail = thumburl, - url = '/janusweb/index.html#janus.url=' .. EscapeFragment(url) + url = '/janusweb/index.html#janus.url=' .. EscapeFragment(url) + .. '&janus.referrer=' .. EscapeFragment( util.getURL(opts.urlpath ) ) }) end end @@ -34,7 +35,7 @@ end) local plugin = { name = 'Federation', tab = " Federation", - info = 'Add links to other (janus)XR(forges), and have them show up as extra portals in portalrooms', + info = 'Add links to other (janus)XR(forges), and have them show up as extra portals in portalrooms.
NOTE: please leave at the Parent World URL non-empty, as it promotes interconnected ecosystems of experiences ♥', opts = { -- TODO populate this based on xrforge-federation.json { key='app.opts.plugin_federation_strategy', @@ -43,6 +44,14 @@ local plugin = { default="homepage", values={always='always',homepage='only homepage'} }, + { + key='app.opts.plugin_federation_parent_url', + title='Parent World URL', + info="3D portal (entrypoint) in homepage", + default="https://www.janusxr.org", + placeholder="https://www.janusxr.org", + values='' + }, { key='app.opts.plugin_federation_url_1', title='Federated URL 1', @@ -54,7 +63,7 @@ local plugin = { key='app.opts.plugin_federation_url_2', title='Federated URL 2', info="URL and/or Thumbnail URL (space separated)", - default="https://www.janusxr.org https://www.janusvr.com/images/logos/logotextoverlight.png", + default="https://aframe.io/aframe/examples/boilerplate/hello-world/ /myverse/janusxr_tutorial/AFRAME.jpg", values='' }, { diff --git a/src/plugin/global.lua b/src/plugin/global.lua index 0600680..9770bd1 100644 --- a/src/plugin/global.lua +++ b/src/plugin/global.lua @@ -113,7 +113,7 @@ local plugin = { }, middleware = { homepage_2D_or_3D = function(req,res,next) - if (app.opts.plugin_global_homepage == '3D') or (req.param.view == '3D') or (req.param.url) then + if (req.url == '/' or req.url == '/index.html' and app.opts.plugin_global_homepage == '3D') or (req.param.view == '3D') or (req.param.url) then res.template = 'page/index.html' else res.template = 'page/dir.html' diff --git a/src/plugin/janusxr.lua b/src/plugin/janusxr.lua index 83b9024..13d283c 100644 --- a/src/plugin/janusxr.lua +++ b/src/plugin/janusxr.lua @@ -8,6 +8,15 @@ app.on('scan_experience', function(exp) --print_r(exp) end) +app.on('dir', function(opts) + local hash = GetPath() + if #app.opts.plugin_janusxr_random_objects > 0 and + #app.opts.plugin_janusxr_random_colors > 0 then + opts.data.janusxr_jml_deco = app.plugin.janusxr.getRandomDeco(7,50,hash,0,30) .. + app.plugin.janusxr.getRandomDeco(7,50,hash .. hash,30,30) + end +end) + app.on('scan_experience_file', function(exp) local me = app.plugin.janusxr local size = exp.file.attr:size() @@ -56,8 +65,7 @@ app.on('scan_experience_file', function(exp) end end) -app.on('set', function(k,v) -end) +app.on('set', function(k,v) end) -- this registers the plugin UI local rooms = {random="random room",room_plane="wirefloor",room1="room1",room2="room2",room3="room3",room4="room4",room5="room5",room6="room6",room7="room7"} @@ -118,6 +126,22 @@ local plugin = { default="room_plane", values={random="random room",room_plane="wirefloor",room1="room1",room2="room2",room3="room3",room4="room4",room5="room5",room6="room6",room7="room7"} }, + { + key='app.opts.plugin_janusxr_random_objects', + title='Random objects', + info="Random object id's in portal rooms", + default="capsule cone cube cylinder pyramid sphere torus", + placeholder="capsule cone cube cylinder pipe pyramid sphere torus", + values="", + }, + { + key='app.opts.plugin_janusxr_random_colors', + title='Random colors', + info="Random object colors in portal rooms", + default="#ffffff #111122 #FF33FF #8833FF #7070FF #404070 #222244", + placeholder="#ffffff #111122 #FF33FF #8833FF #7070FF #404070 #222244", + values="", + }, { key='app.opts.plugin_janusxr_scraper', title='Scraper', @@ -141,6 +165,7 @@ local plugin = { values='' } }, + getRandomRoom = function() local me = app.plugin.janusxr local room= '' @@ -153,6 +178,52 @@ local plugin = { end end) return room + end, + + getRandomDeco = function(num_objects, radius, seed_string, y, scale) + num_objects = num_objects or 6 + y = y or 0 + radius = radius or 2 -- Configurable distance from (0, 0, 0) + seed_string = seed_string or 'xf2dxf2dxf3f23' -- Given hashstring + local JML = '' + local colors = util.split( app.opts.plugin_janusxr_random_colors, ' ') + local ids = util.split( app.opts.plugin_janusxr_random_objects, ' ') + + local function hash_string_to_number(str) + local hash = 5381 + for i = 1, #str do + local char = string.byte(str, i) + hash = (hash * 33 + char) % 2147483647 + end + return hash + end + local index = { + color= hash_string_to_number(seed_string) % #colors, + id = hash_string_to_number(seed_string) % #ids + } + + for i = 1, num_objects do + -- Calculate angle in radians to space objects evenly around a circle + local angle = (i - 1) * (2 * math.pi / num_objects) + -- Calculate X and Z positions along the circle radius + local x = radius * math.cos(angle) + local z = radius * math.sin(angle) + local y = y -- Height level + + local selected_id = ids[ index.id+1] + local selected_color = colors[ index.color+1 ] + + local pos_str = string.format("%.2f %g %.2f", x, y, z) + local xml_tag = string.format('', + selected_id, pos_str, selected_color, scale, scale, scale) + + JML = JML .. xml_tag .. "\n" + + -- increase indexes + index.id = (index.id + 1 ) % #ids + index.color = (index.color + 1 ) % #colors + end + return JML end } diff --git a/src/plugin/markdown.lua b/src/plugin/markdown.lua index 2a35ebf..5dcda60 100644 --- a/src/plugin/markdown.lua +++ b/src/plugin/markdown.lua @@ -12,6 +12,7 @@ app.on('scan_experience_file', function(exp) if exp.path:match(v) then print("✅ └─ plugin/markdown: detected " .. v) exp.parent.info = '
' .. markdown( util.readfile(exp.path) ) .. '
' + exp.parent.README = util.stripPath( exp.path ) end end) end) diff --git a/src/plugin/peertube.lua b/src/plugin/peertube.lua index 5d54ec2..30ccab7 100644 --- a/src/plugin/peertube.lua +++ b/src/plugin/peertube.lua @@ -25,6 +25,7 @@ app.on('dir', function(opts) title = url:gsub(".*//",""), thumbnail = thumburl, url = '/janusweb/index.html#janus.url=' .. EscapeFragment(url) + .. '&janus.referrer=' .. EscapeFragment( util.getURL(opts.urlpath ) ) }) end end diff --git a/src/plugin/pubnix.lua b/src/plugin/pubnix.lua new file mode 100644 index 0000000..2d9a5fe --- /dev/null +++ b/src/plugin/pubnix.lua @@ -0,0 +1,50 @@ +local util = require('util') + +app.on('scan_experience', function(exp) + --print_r(exp) +end) + +app.on('scan_experience_file', function(exp) +end) + +app.on('set', function(k,v) +end) + +-- this registers the plugin UI +local plugin = { + name = "PubNIX", + info = 'disabled Turn server into a pubnix: automatically scan userdirectories in /home/* for XR experiences, and add them as 3D portals.', + opts = { + { + key='app.opts.plugin_pubnix_enabled', + title='Add homedirs', + info='Scan for experiences in /home/*', + default = "enabled", + values={enabled="enabled",disabled="disabled"} + }, + { + key='app.opts.plugin_pubnix_folder', + title='Require folder', + info='Require specific folder (/home/john/xrforge e.g.)', + default = "./xrforge", + values='' + }, + { + key='app.opts.plugin_pubnix_thumbnail', + title='User thumbnail', + info='look for /home/john/xrforge/~john.jpg sidecarfile', + default = "enabled", + values={enabled="enabled",disabled="disabled"} + }, + { + key='app.opts.plugin_pubnix_exclude', + title='Exclude pattern', + info='Space-separated, lua patterns for directories', + default = "", + placeholder = "admin root", + values='' + }, + } +} + +return plugin diff --git a/src/plugin/rssatom.lua b/src/plugin/rssatom.lua index 9efc7f5..81284ae 100644 --- a/src/plugin/rssatom.lua +++ b/src/plugin/rssatom.lua @@ -25,6 +25,7 @@ app.on('dir', function(opts) title = url:gsub(".*//",""), thumbnail = thumburl, url = '/janusweb/index.html#janus.url=' .. EscapeFragment(url) + .. '&janus.referrer=' .. EscapeFragment( util.getURL(opts.urlpath ) ) }) end end diff --git a/src/plugin/xrfragments.lua b/src/plugin/xrfragments.lua index 5dcf2a3..28f5b7c 100644 --- a/src/plugin/xrfragments.lua +++ b/src/plugin/xrfragments.lua @@ -13,7 +13,7 @@ app.on('scan_experience_file', function(exp) local hasHref = false if ext == 'glb' then -- detect XR Fragment exp https://xrfragment.org/#%F0%9F%93%9C%20level0%3A%20File - local tree = me.extract_glb_json( util.stripPath(exp.path) ) + local tree = me.extract_glb_json( exp.path ) --util.stripPath(exp.path) ) hasHref = me.detectHrefInStruct(tree) end -- check sidecarfiles: https://xrfragment.org/#sidecar%20files diff --git a/src/util/xrforge.sh b/src/util/build.sh similarity index 95% rename from src/util/xrforge.sh rename to src/util/build.sh index 69f5afd..95d2602 100755 --- a/src/util/xrforge.sh +++ b/src/util/build.sh @@ -36,7 +36,7 @@ download(){ wget "https://github.com/coderofsalvation/janusweb/releases/download/v${version}-rc/janusweb-${version}.tar.gz" } test -d janusweb-${version} || tar -xvf janusweb-${version}.tar.gz - test -d src/janusweb || cp -r janusweb-${version} src/janusweb + test -d src/janusweb || cp -Lr janusweb-${version} src/janusweb } "$@"