refactored everything to plugins (todo: fix memoize tiles)
This commit is contained in:
parent
1014554be6
commit
d36dfa30b2
20 changed files with 241 additions and 229 deletions
2
run.sh
2
run.sh
|
|
@ -1,2 +1,4 @@
|
|||
#!/bin/sh
|
||||
source ./.env
|
||||
rebuild
|
||||
result/bin/xrforge.com server
|
||||
|
|
|
|||
|
|
@ -23,21 +23,40 @@ app = require("soakbean") {
|
|||
cmd={
|
||||
help = {file="cmd/help.lua", info="display all possible flags"},
|
||||
server = {file="cmd/server.lua", info="starts the webserver"},
|
||||
createplugin = {file="cmd/createplugin.lua", info="generates skeleton plugin"}
|
||||
createplugin = {file="cmd/createplugin.lua", info="generates skeleton plugin"},
|
||||
generate = {file="cmd/generate.lua", info="generate www-folder with XR experiences"}
|
||||
}
|
||||
}
|
||||
|
||||
-- api skeleton (implemented via soakbean's app.on(...))
|
||||
app.set = function(k,v) end
|
||||
app.init = function() end
|
||||
app.scan = require('scan').scan
|
||||
|
||||
-- load config
|
||||
app.opts = require('config')(app)
|
||||
|
||||
-- load plugins
|
||||
-- load system plugins
|
||||
app.plugin.moderation = require('plugin/moderation')
|
||||
app.plugin.diskscan = require('plugin/diskscan')
|
||||
app.plugin.manyfold = require('plugin/manyfold')
|
||||
app.plugin.janusxr = require('plugin/janusxr')
|
||||
|
||||
-- ensure plugin config-defaults
|
||||
foreach( app.plugin, function(name,plugin)
|
||||
foreach( plugin.opts, function(k,opt)
|
||||
local key = opt.key:gsub("app.opts.","")
|
||||
if not app.opts[ key ] then
|
||||
app.opts[ key ] = opt.default
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
-- set order preference (optional)
|
||||
app.plugin[1] = app.plugin.diskscan
|
||||
app.plugin[2] = app.plugin.moderation
|
||||
app.plugin[3] = app.plugin.janusxr
|
||||
app.plugin[4] = app.plugin.manyfold
|
||||
|
||||
app.runcmd(app) -- run clicmds
|
||||
|
||||
-- init URL router
|
||||
|
|
@ -68,8 +87,9 @@ app --
|
|||
|
||||
app.on('init', function()
|
||||
if assert(unix.fork()) == 0 then
|
||||
app.plugin.diskscan.scan()
|
||||
print_r(app.cache)
|
||||
--os.execute("ls ; sleep 5")
|
||||
app.scan()
|
||||
print("ok")
|
||||
--local ok, headers, body = Fetch('http://127.0.0.1:8080/test')
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,17 +5,10 @@ return function(app)
|
|||
local config = { -- default
|
||||
name = "XRForge",
|
||||
baseurl="/",
|
||||
title="My XRForge experiences",
|
||||
title="Your XR Forge",
|
||||
subtitle="Portable XR experiences for Phone, VRheadset & desktop.",
|
||||
admin_title = "XRForge Admin",
|
||||
admin_subtitle = "Manage your XR experiences here",
|
||||
disk_dir = ".",
|
||||
hide_keywords = "wip beta -v[0-9] customerX",
|
||||
manyfold_instance_1 = "https://xrforge.isvery.ninja",
|
||||
manyfold_instance_2 = "",
|
||||
manyfold_instance_3 = "",
|
||||
sync_interval = 30,
|
||||
sync_strategy = "recent"
|
||||
}
|
||||
|
||||
local configfile = "xrforge.lua"
|
||||
|
|
|
|||
|
|
@ -31,17 +31,16 @@ local dir = {}
|
|||
|
||||
dir.scan = function(path)
|
||||
local stat = unix.stat(path)
|
||||
if stat == nil then
|
||||
return ServeError(404,"does not exist")
|
||||
else
|
||||
if not unix.S_ISDIR( stat:mode() ) then return false end -- let redbean take care of serving static file
|
||||
end
|
||||
state = assert(unix.opendir(path))
|
||||
return stat, state
|
||||
if not stat or not unix.S_ISDIR( stat:mode() ) then
|
||||
return nil,nil, "not a dir"
|
||||
end -- let redbean take care of serving static file
|
||||
state,err = assert(unix.opendir(path))
|
||||
return stat, state, err
|
||||
end
|
||||
|
||||
dir.foreach = function(path,cb)
|
||||
local stat, state = dir.scan(path)
|
||||
local stat, state, err = dir.scan(path)
|
||||
if not err then
|
||||
for name, kind, ino, off in state do
|
||||
if name == "." then goto continue end
|
||||
attr,err = unix.stat(path..'/'..name, unix.AT_SYMLINK_NOFOLLOW)
|
||||
|
|
@ -49,7 +48,8 @@ dir.foreach = function(path,cb)
|
|||
cb(path,stat,state,name,kind,ino,off,attr, path .. "/" ..name)
|
||||
::continue::
|
||||
end
|
||||
return state
|
||||
end
|
||||
return state,err
|
||||
end
|
||||
|
||||
dir.serve = function(folder) -- raw redbean function (use dir.foreach in soakbean)
|
||||
|
|
@ -97,7 +97,11 @@ dir.serve = function(folder) -- raw redbean function (use dir.foreach in soakbea
|
|||
Write('<th class=hide r>ctim\r\n')
|
||||
Write('<tbody>\r\n')
|
||||
|
||||
local stat, state = dir.scan(path)
|
||||
local stat, state, err = dir.scan(path)
|
||||
if stat == nil then
|
||||
return ServeError(404,"does not exist")
|
||||
end
|
||||
|
||||
dir.foreach(path, function(path,stat,state,name,kind,ino,off,attr,fullpath)
|
||||
Write('<tr>\r\n')
|
||||
Write('<td>')
|
||||
|
|
|
|||
1
src/.lua/page
Symbolic link
1
src/.lua/page
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../page
|
||||
|
|
@ -3,7 +3,7 @@ return function(app,argv)
|
|||
|
||||
--
|
||||
-- 1. put the code below in a file ('xrforge.myplugin.lua' e.g.)
|
||||
-- 2. make sure to require it at the top of xrforge.lua (require('xrforge.myplugin') e.g.)
|
||||
-- 2. in xrforge.lua make sure to add (at the top): app.plugin.myplugin = require('xrforge.myplugin')
|
||||
-- 3. profit!
|
||||
--
|
||||
|
||||
|
|
@ -38,7 +38,10 @@ local plugin = {
|
|||
default="bar",
|
||||
values=""
|
||||
}
|
||||
}
|
||||
},
|
||||
myfunc = function()
|
||||
-- call me via app.plugin.myplugin.myfunc()
|
||||
end
|
||||
}
|
||||
|
||||
return plugin
|
||||
|
|
|
|||
4
src/cmd/generate.lua
Normal file
4
src/cmd/generate.lua
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
return function(app,argv)
|
||||
app.plugin.diskscan.scan()
|
||||
os.exit()
|
||||
end
|
||||
|
|
@ -184,14 +184,14 @@ ul{
|
|||
.menu{
|
||||
text-align: right;
|
||||
}
|
||||
.menu,
|
||||
.menu *{
|
||||
white-space: nowrap;
|
||||
}
|
||||
.menu a {
|
||||
padding-right:30px;
|
||||
}
|
||||
|
||||
.menu br {
|
||||
display:none
|
||||
}
|
||||
|
||||
.grid .tile{ border-radius:5px; }
|
||||
.grid .tile .text{ padding:3px 0px; }
|
||||
.grid .tile .img{
|
||||
|
|
|
|||
|
|
@ -33,9 +33,14 @@ body{
|
|||
form table tr > td:nth-child(3) {
|
||||
display:none;
|
||||
}
|
||||
.menu br {
|
||||
display:initial !important;
|
||||
.menu{
|
||||
position:absolute;
|
||||
right:20px;
|
||||
}
|
||||
.menu a{
|
||||
padding-right:20px !important;
|
||||
}
|
||||
.menu a.xl{ display:none; }
|
||||
}
|
||||
|
||||
.grid .tile .text{
|
||||
|
|
|
|||
|
|
@ -10,145 +10,6 @@ ${notification}
|
|||
|
||||
<form method="POST">
|
||||
|
||||
<div class="tab">
|
||||
<div class="label col2">
|
||||
Local content
|
||||
</div>
|
||||
</div>
|
||||
<div class="margin1">
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<th width="165"/>
|
||||
<th />
|
||||
<th />
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Directory
|
||||
</td>
|
||||
<td >
|
||||
<input type="text" value="${opts.disk_dir}"></input>
|
||||
</td>
|
||||
<td class="col3">
|
||||
Directory to scan for experiences (use '.' for current)
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="tab">
|
||||
<div class="label col2">
|
||||
Hide content
|
||||
</div>
|
||||
</div>
|
||||
<div class="margin1">
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<th width="165"/>
|
||||
<th />
|
||||
<th />
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Keywords
|
||||
</td>
|
||||
<td >
|
||||
<input type="text" name="opts.hide_keywords" value="${opts.hide_keywords}"></input>
|
||||
</td>
|
||||
<td class="col3">
|
||||
Space-separated, <a href="http://lua-users.org/wiki/PatternsTutorial" target="_blank">lua patterns</a> are allowed
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<div class="tab">
|
||||
<div class="label col2">
|
||||
Manyfold instances
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="margin1">
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<th width="165"/>
|
||||
<th />
|
||||
<th />
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Instance URL 1
|
||||
</td>
|
||||
<td >
|
||||
<input type="text" name="opts.manyfold_instance_1" value="${opts.manyfold_instance_1}"></input>
|
||||
</td>
|
||||
<td class="col3">
|
||||
<a href="https://manyfold.app/" target="_blank">Manyfold</a> URL goes here (https://xrforge.isvery.ninja e.g.)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Instance URL 2
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="opts.manyfold_instance_2" value="${opts.manyfold_instance_2}"></input>
|
||||
</td>
|
||||
<td class="col3">
|
||||
<a href="https://manyfold.app/" target="_blank">Manyfold</a> URL goes here (https://xrforge.isvery.ninja e.g.)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Instance URL 3
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="opts.manyfold_instance_3" value="${opts.manyfold_instance_3}"></input>
|
||||
</td>
|
||||
<td class="col3">
|
||||
<a href="https://manyfold.app/" target="_blank">Manyfold</a> URL goes here (https://xrforge.isvery.ninja e.g.)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Sync strategy
|
||||
</td>
|
||||
<td>
|
||||
<select value="${opts.manyfold_sync_strategy}">
|
||||
<option value="recent" default>only recent</option>
|
||||
<option value="all+recent">everything + recent</option>
|
||||
<option value="disabled">disabled</option>
|
||||
</select>
|
||||
</td>
|
||||
<td class="col3">
|
||||
Specify how manyfold instances should be synced.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Sync interval
|
||||
</td>
|
||||
<td>
|
||||
<select value="${opts.manyfold_sync_interval}">
|
||||
<option value="30">every 30 mins</option>
|
||||
<option value="15" selected>every 15 mins</option>
|
||||
<option value="5">every 5 minutes</option>
|
||||
</select>
|
||||
</td>
|
||||
<td class="col3">
|
||||
Specify how often manyfold instances should be checked for recent items.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
${plugins}
|
||||
|
||||
<div style="margin-left:187px">
|
||||
|
|
|
|||
|
|
@ -14,11 +14,13 @@ function pluginInput(opt)
|
|||
</td>
|
||||
<td>
|
||||
]]
|
||||
local value = app.opts[ opt.key:gsub("^app.opts.","") ]
|
||||
if type(opt.values) == 'table' then
|
||||
html = html .. util.template('<select name="${key}" value="${value}">\n', {
|
||||
key = opt.key,
|
||||
value = app.opts[key]
|
||||
value = value
|
||||
})
|
||||
print(opt.key:gsub("^app.opts.","") )
|
||||
foreach( opt.values, function(k,v)
|
||||
html = html .. util.template('<option value="${v}">${k}</option>\n',{
|
||||
k=k,
|
||||
|
|
@ -29,7 +31,7 @@ function pluginInput(opt)
|
|||
else
|
||||
html = html .. util.template('<input type="text" name="${key}" value="${value}"></input>',{
|
||||
key = opt.key,
|
||||
value = app.opts[key]
|
||||
value = value
|
||||
})
|
||||
end
|
||||
html = html .. util.template([[
|
||||
|
|
@ -41,14 +43,17 @@ function pluginInput(opt)
|
|||
return html
|
||||
end
|
||||
|
||||
function pluginUI(name,plugin)
|
||||
function pluginUI(seen)
|
||||
return function(name,plugin)
|
||||
if seen[ plugin.name ] then return end -- already processed
|
||||
seen[ plugin.name ] = true
|
||||
local plugindata = util.flatten(plugin,"plugin")
|
||||
plugindata.opts = ""
|
||||
foreach(plugin.opts, function(k,opt)
|
||||
plugindata.opts = plugindata.opts .. pluginInput(opt)
|
||||
end)
|
||||
print_r(plugindata)
|
||||
data.plugins = data.plugins .. util.template( LoadAsset('/page/admin/plugin.html'), plugindata)
|
||||
end
|
||||
end
|
||||
|
||||
function saveData()
|
||||
|
|
@ -70,7 +75,8 @@ function saveData()
|
|||
end
|
||||
end
|
||||
|
||||
foreach( app.plugin, pluginUI )
|
||||
local seen = {}
|
||||
foreach( app.plugin, pluginUI(seen) )
|
||||
saveData()
|
||||
local html = util.template( LoadAsset("page/admin/index.html"),data)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<div class="tab">
|
||||
<div class="label col2">${plugin.name} <b class="tag">plugin</b></div>
|
||||
<div class="label col2">${plugin.name}</div>
|
||||
</div>
|
||||
<div class="margin1">
|
||||
<table width="100%">
|
||||
|
|
|
|||
|
|
@ -7,24 +7,7 @@ ${header}
|
|||
<hr style="margin-top:0">
|
||||
|
||||
<div class="grid">
|
||||
<div class="tile">
|
||||
<div class="img" style="background-image:url(https://xrforge.isvery.ninja/models/dpjnj8pt1cjc/model_files/bzjvdm7l523l.png?derivative=preview);"></div>
|
||||
<div class="text">
|
||||
<img src="img/folder.svg" class="icon"/> Item 1
|
||||
</div>
|
||||
</div>
|
||||
<div class="tile">
|
||||
<div class="img" style="background-image:url(https://xrforge.isvery.ninja/models/dpjnj8pt1cjc/model_files/bzjvdm7l523l.png?derivative=preview);"></div>
|
||||
<div class="text">
|
||||
<img src="img/folder.svg" class="icon"/> Item 2
|
||||
</div>
|
||||
</div>
|
||||
<div class="tile">
|
||||
<div class="img" style="background-image:url(https://xrforge.isvery.ninja/models/dpjnj8pt1cjc/model_files/bzjvdm7l523l.png?derivative=preview);"></div>
|
||||
<div class="text">
|
||||
<img src="img/folder.svg" class="icon"/> Item 3
|
||||
</div>
|
||||
</div>
|
||||
${tiles}
|
||||
</div>
|
||||
|
||||
${footer}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,16 @@
|
|||
local util = require("util")
|
||||
local tile = require('page/partial/tile')
|
||||
|
||||
if not app.cache['experiences.html'] then
|
||||
|
||||
print("processing! " .. util.count(app.cache.items) .. " items")
|
||||
app.cache['experiences.html'] = util.memoize(
|
||||
function()
|
||||
print("processing!")
|
||||
local data = util.merge({foo='1'},{ opts = app.opts })
|
||||
local html = util.template( LoadAsset("page/experiences.html"),app)
|
||||
local data = util.merge({tiles=''},{ opts = app.opts })
|
||||
foreach(app.cache.items, function(k,v)
|
||||
data.tiles = data.tiles .. tile( util.flatten(v,"item") )
|
||||
end)
|
||||
local html = util.template( LoadAsset("page/experiences.html"),data)
|
||||
return html
|
||||
end,
|
||||
60*5 -- re-run every 5 mins (otherwise return cache)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<base href="${opts.baseurl}" />
|
||||
<title>XRForge - selfsovereign interoperable XR experiences</title>
|
||||
<link rel="stylesheet" href="css/xrforge.css"></link>
|
||||
|
|
@ -25,10 +25,8 @@
|
|||
</td>
|
||||
<td class="menu">
|
||||
<div class="margin1L">
|
||||
<a href="/experiences">Experiences</a><br/>
|
||||
<a href="/about">About</a><br/>
|
||||
<a href="/howto">Howto</a><br/>
|
||||
</div>
|
||||
<!-- important: no spaces between anchor tags for older browsers without flexbox -->
|
||||
<a href="/experiences">experiences</a><a href="/about">about</a><a class="xl" href="/howto">Howto</a></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
|||
12
src/page/partial/tile.lua
Normal file
12
src/page/partial/tile.lua
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
local util = require('util')
|
||||
|
||||
return function(opts)
|
||||
return util.template([[
|
||||
<div class="tile">
|
||||
<div class="img" style="background-image:url(https://xrforge.isvery.ninja/models/dpjnj8pt1cjc/model_files/bzjvdm7l523l.png?derivative=preview);"></div>
|
||||
<div class="text">
|
||||
<img src="img/folder.svg" class="icon"/> ${item.title}
|
||||
</div>
|
||||
</div>
|
||||
]],opts)
|
||||
end
|
||||
|
|
@ -1,8 +1,18 @@
|
|||
local dir = require "opendirectory"
|
||||
|
||||
local scan
|
||||
scan = {
|
||||
|
||||
-- this registers the plugin UI /funcs
|
||||
return {
|
||||
name = "Content (from disk)",
|
||||
info = 'XRForge can search in (unnested) folders for XR/image/video files.',
|
||||
opts = {
|
||||
{
|
||||
key='app.opts.plugin_diskscan_dir',
|
||||
title='Directory',
|
||||
info="Directory to scan for experiences (use '.' for current) ",
|
||||
default=".",
|
||||
values=''
|
||||
}
|
||||
},
|
||||
shouldHideFile = function(name)
|
||||
return name == ".."
|
||||
or name == "util" -- repository
|
||||
|
|
@ -12,12 +22,15 @@ scan = {
|
|||
end,
|
||||
|
||||
scan = function()
|
||||
local me = app.plugin.diskscan
|
||||
local folder = app.opts.plugin_diskscan_dir
|
||||
-- scan dirs
|
||||
local dref = dir.foreach( app.opts.disk_dir, function(path,stat,state,name,kind,ino,off,attr,fullpath)
|
||||
if kind == unix.DT_DIR and not scan.shouldHideFile(name) then
|
||||
local dref, derr= dir.foreach( folder, function(path,stat,state,name,kind,ino,off,attr,fullpath)
|
||||
if (kind == unix.DT_DIR or kind == unix.DT_LNK) and not me.shouldHideFile(name) then
|
||||
local experience = {
|
||||
path = fullpath,
|
||||
name = name,
|
||||
title = name,
|
||||
tag = {},
|
||||
file = {stat=stat,state=state,kind=kind,ino=ino,off=off,attr=attr,fullpath=fullpath,name=name,path=path}
|
||||
}
|
||||
|
|
@ -25,18 +38,18 @@ scan = {
|
|||
print("ℹ️ ".. fullpath)
|
||||
|
||||
-- scan files
|
||||
local fref = dir.foreach(fullpath, function(path,stat,state,name,kind,ino,off,attr, fullpath)
|
||||
if kind ~= unix.DT_DIR and not scan.shouldHideFile(name) then
|
||||
local fref, ferr = dir.foreach(fullpath, function(path,stat,state,name,kind,ino,off,attr, fullpath)
|
||||
if kind ~= unix.DT_DIR and not me.shouldHideFile(name) then
|
||||
experience.file = {stat=stat,state=state,kind=kind,ino=ino,off=off,attr=attr,fullpath=fullpath,name=name,path=path}
|
||||
app.pub("scan_experience_file", nil, experience)
|
||||
local size = attr:size()
|
||||
trace("ℹ️ ".. fullpath)
|
||||
end
|
||||
end)
|
||||
fref:close()
|
||||
if not ferr then fref:close() end
|
||||
end
|
||||
end)
|
||||
dref:close()
|
||||
if not derr then dref:close() end
|
||||
|
||||
foreach( app.cache.items, function(k,v)
|
||||
-- remove file attributes (which are closed already)
|
||||
|
|
@ -46,5 +59,3 @@ scan = {
|
|||
end)
|
||||
end
|
||||
}
|
||||
|
||||
return scan
|
||||
|
|
@ -11,12 +11,17 @@ app.on('scan_experience_file', function(exp)
|
|||
local size = exp.file.attr:size()
|
||||
if exp.file.name:match(".glb") and not util.contains(exp.tag,"xrfragment") then
|
||||
print("✅ └─ plugin/janusxr: generating janusxr.xml")
|
||||
table.insert(exp.tag, "janusxr")
|
||||
app.pub("scan_experience_janusxr", nil, {exp=exp, item=item}) -- be nice to other plugins
|
||||
table.insert( app.cache.items, exp)
|
||||
elseif size < 1000 then -- skip large binary files
|
||||
local data = util.readfile( exp.file.fullpath)
|
||||
if data:match(pattern_fireboxroom) then
|
||||
table.insert(exp.tag, "janusxr")
|
||||
local title = data:match(pattern_title)
|
||||
if title then exp.title = title:gsub("<.*","") end
|
||||
if title then
|
||||
exp.title = title:gsub("<.*","")
|
||||
end
|
||||
app.pub("scan_experience_janusxr", nil, {exp=exp, item=item}) -- be nice to other plugins
|
||||
table.insert( app.cache.items, exp)
|
||||
print("✅ └─ plugin/janusxr: " .. exp.file.name)
|
||||
|
|
@ -31,8 +36,15 @@ end)
|
|||
-- this registers the plugin UI
|
||||
local plugin = {
|
||||
name = "JanusXR",
|
||||
info = '<a href="https://coderofsalvation.github.io/janus-guide" target="_blank">janusxr</a> allows composing (interconnected) 3D experiences (via portals) via its JML markup language. It also supports AFRAME (geometry)markup.',
|
||||
info = '<a href="https://coderofsalvation.github.io/janus-guide" target="_blank">JanusXR</a> connects XR experiences via XML portals (+AFRAME (geometry)markup also supported).',
|
||||
opts = {
|
||||
{
|
||||
key='app.opts.plugin_janusxr_janusweb_endpoint',
|
||||
title='backend URL',
|
||||
info='Where janusweb (editor) can save its JML/assets while livecoding',
|
||||
default="/janusxr",
|
||||
values=''
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_janusxr_wrap_image',
|
||||
title='wrap images',
|
||||
|
|
|
|||
64
src/plugin/manyfold.lua
Normal file
64
src/plugin/manyfold.lua
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
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)
|
||||
print("content was updated")
|
||||
end)
|
||||
|
||||
-- this registers the plugin UI
|
||||
local plugin = {
|
||||
name = "Manyfold",
|
||||
info = '',
|
||||
opts = {
|
||||
{
|
||||
key='app.opts.plugin_manyfold_instance_1',
|
||||
title='Instance 1 URL',
|
||||
info='<a href="https://manyfold.app/" target="_blank">Manyfold</a> URL goes here (https://xrforge.isvery.ninja e.g.)',
|
||||
default="https://xrforge.isvery.ninja",
|
||||
values=''
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_manyfold_instance_2',
|
||||
title='Instance 2 URL',
|
||||
info='<a href="https://manyfold.app/" target="_blank">Manyfold</a> URL goes here (https://xrforge.isvery.ninja e.g.)',
|
||||
default="",
|
||||
values=''
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_manyfold_instance_3',
|
||||
title='Instance 3 URL',
|
||||
info='<a href="https://manyfold.app/" target="_blank">Manyfold</a> URL goes here (https://xrforge.isvery.ninja e.g.)',
|
||||
default="",
|
||||
values=''
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_manyfold_sync_strategy',
|
||||
title='Instance 3 URL',
|
||||
info="Specify how content from manyfold instances should be fetched",
|
||||
default="recent",
|
||||
values={recent='only recent',all_recent='everything + recent', disabled='disabled'}
|
||||
},
|
||||
--{
|
||||
-- key='app.opts.plugin_manyfold_sync_strategy',
|
||||
-- title='Instance 3 URL',
|
||||
-- info='Specify how content from manyfold instances should be fetched",
|
||||
-- default="recent",
|
||||
-- values={recent='only recent',all_recent='everything + recent', disabled='disabled'}
|
||||
--},
|
||||
--{
|
||||
-- key='app.opts.plugin_manyfold_sync_interval',
|
||||
-- title='Instance 3 URL',
|
||||
-- info='Specify how often xrforge should check for recent items #serveronly'
|
||||
-- default="recent",
|
||||
-- values={recent='only recent',all_recent='everything + recent', disabled='disabled'}
|
||||
--},
|
||||
}
|
||||
}
|
||||
|
||||
return plugin
|
||||
29
src/plugin/moderation.lua
Normal file
29
src/plugin/moderation.lua
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
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)
|
||||
print("content was updated")
|
||||
end)
|
||||
|
||||
-- this registers the plugin UI
|
||||
local plugin = {
|
||||
name = "Moderation",
|
||||
info = 'Hide certain experiences from the listing (client work e.g.)',
|
||||
opts = {
|
||||
{
|
||||
key='app.opts.plugin_moderation_mutekeywords',
|
||||
title='Mute keywords',
|
||||
info='Space-separated, <a href="http://lua-users.org/wiki/PatternsTutorial" target="_blank">lua patterns</a> are allowed',
|
||||
default = "wip beta -v[0-9] customerX",
|
||||
values=''
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return plugin
|
||||
Loading…
Add table
Reference in a new issue