improved rssatom/federation/peertube plugins + ttemplates
|
|
@ -1,7 +1,8 @@
|
|||
XRForge is a tiny, powerful tool to interconnect XR experiences via 3D portals...like a federated viverse.com<br>
|
||||
<br>
|
||||
An open, seamless XR web built from simple URLs and directories, without gatekeepers.<br>
|
||||
An open, seamless XR web built from simple URLs and directories, without gatekeepers, built upon Next Generation Internet (NGI) specs:<br>
|
||||
<br>
|
||||
<img src="https://codeberg.org/coderofsalvation/xrforge-v2/raw/branch/master/src/img/badges.png"/>
|
||||
<br>
|
||||
<a href="screenshot.jpg" target="_blank">
|
||||
<img src="screenshot.jpg"/>
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@ HidePath('/usr/share/ssl/')
|
|||
|
||||
-- create
|
||||
app = require("soakbean") {
|
||||
bin = "./xrforge.com",
|
||||
bindir = arg[-1]:gsub("/[a-zA-Z0-9-_ ]+.com$","/"),
|
||||
cache = { items = {}, url = {} },
|
||||
plugin = {},
|
||||
opts = {},
|
||||
|
|
@ -62,11 +60,13 @@ app.plugin.moderation = app.addPlugin('plugin/moderation')
|
|||
app.plugin.xrfragments = app.addPlugin('plugin/xrfragments')
|
||||
app.plugin.janusxr = app.addPlugin('plugin/janusxr')
|
||||
app.plugin.clouddrive = app.addPlugin('plugin/clouddrive')
|
||||
app.plugin.markdown = app.addPlugin('plugin/markdown')
|
||||
app.plugin.rssatom = app.addPlugin('plugin/rssatom')
|
||||
app.plugin.federation = app.addPlugin('plugin/federation')
|
||||
app.plugin.manyfold = app.addPlugin('plugin/manyfold')
|
||||
app.plugin.peertube = app.addPlugin('plugin/peertube')
|
||||
app.plugin.git = app.addPlugin('plugin/git')
|
||||
app.plugin.webhook = app.addPlugin('plugin/webhook')
|
||||
app.plugin.markdown = app.addPlugin('plugin/markdown')
|
||||
app.plugin.staticwebgen = app.addPlugin('plugin/staticwebgen') -- should always be last
|
||||
|
||||
app.runcmd(app) -- run clicmds
|
||||
|
|
@ -92,7 +92,11 @@ app.post('^/save', function(req,res,next) -- setup inline POST endpoint
|
|||
end)
|
||||
|
||||
app --
|
||||
.use( require("middleware/httpauth")() )
|
||||
.use( require("middleware/httpauth")({
|
||||
user = app.opts.admin_user,
|
||||
pass = app.opts.admin_pass,
|
||||
path = "^/admin"
|
||||
}))
|
||||
.use( require("json").middleware() ) -- try plug'n'play json API middleware
|
||||
.use( require('page/dir').middleware ) -- directory browser
|
||||
.use( app.router( app.url ) ) -- try url router
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ return function(app)
|
|||
baseurl="/",
|
||||
admin_title = "admin panel",
|
||||
admin_subtitle = "Manage your XR experiences here",
|
||||
admin_user = "admin",
|
||||
admin_pass = "admin"
|
||||
}
|
||||
|
||||
local configfile = "xrforge.lua"
|
||||
|
|
|
|||
|
|
@ -181,7 +181,8 @@ sb = {
|
|||
run = function(req)
|
||||
local next = function() end
|
||||
local k = 0
|
||||
local req = {
|
||||
local internal = req
|
||||
req = req or {
|
||||
param={},
|
||||
method=GetMethod(),
|
||||
host=GetHost(),
|
||||
|
|
@ -195,7 +196,7 @@ sb = {
|
|||
_header={},
|
||||
_body=""
|
||||
}
|
||||
local params = GetParams()
|
||||
local params = internal and {} or GetParams()
|
||||
if params ~= nil then
|
||||
for i,p in pairs(params) do req.param[ p[1] ] = p[2] end
|
||||
end
|
||||
|
|
@ -238,6 +239,7 @@ sb = {
|
|||
|
||||
response = function()
|
||||
return function(req,res,next)
|
||||
sb.pub('response', {req=req, res=res, next=next})
|
||||
if res._status ~= nil then
|
||||
SetStatus(res._status)
|
||||
for k,v in pairs(res._header) do
|
||||
|
|
@ -293,7 +295,7 @@ sb = {
|
|||
end
|
||||
print("\nUsage: " .. app.bin .. " <cmd> [opts]\n\n")
|
||||
for k,v in pairs(app.cmd) do
|
||||
print("\t" .. app.bin .. " " .. k .. "\t\t" .. v.info )
|
||||
print( string.format("\t%s %-15s %s", app.bin, k, v.info ) )
|
||||
end
|
||||
print("")
|
||||
os.exit()
|
||||
|
|
@ -304,6 +306,8 @@ sb = {
|
|||
return function(data)
|
||||
local app = {}
|
||||
setmetatable(app,sb)
|
||||
sb.bin = arg[-1]:gsub(".*/","")
|
||||
sb.bindir = arg[-1]:gsub("/[a-zA-Z0-9-_ ]+.com$","/")
|
||||
sb.app = app
|
||||
sb.data = data
|
||||
sb.data.url = {}
|
||||
|
|
|
|||
|
|
@ -96,6 +96,8 @@ util.template = function(content,data)
|
|||
mdata.url = mdata.url or util.getURL()
|
||||
mdata.title = mdata.title or app.opts.subtitle
|
||||
mdata.header_include = mdata.header_include or ''
|
||||
mdata.footerlinks = {}
|
||||
app.pub('util.template', nil, mdata)
|
||||
mdata.header = app.tpl( LoadAsset('page/header.html'), mdata )
|
||||
if not mdata.janusxr then
|
||||
mdata.janusxr = app.tpl( LoadAsset('page/janusxr.html'), mdata )
|
||||
|
|
@ -328,5 +330,21 @@ function util.stripPath(str)
|
|||
return str:gsub("^./",""):gsub("^/",""):gsub("/$","")
|
||||
end
|
||||
|
||||
-- WARNING: this is a destructive function which renders the redbean server inactive
|
||||
-- only to be used in tests or staticwebgen plugin
|
||||
util.queueServerRequest = function(method, path, params, host, headers, body, scheme, port)
|
||||
GetMethod = function() return method end
|
||||
GetPath = function() return path end
|
||||
GetParams = function() return params or {} end -- note: { {"key","value"} } format
|
||||
GetHost = function() return host or 'localhost' end
|
||||
GetHeaders = function() return headers or {} end
|
||||
GetScheme = function() return scheme or 'https' end
|
||||
GetBody = function() return body or '' end
|
||||
GetPort = function() return port or 80 end
|
||||
SetStatus = function() end
|
||||
Write = function() end
|
||||
SetHeader = function() end
|
||||
Route = function() end
|
||||
end
|
||||
|
||||
return util
|
||||
|
|
|
|||
|
|
@ -2,6 +2,4 @@ return function(app,argv)
|
|||
print('generating..')
|
||||
-- do nothing here, as this is handled by the src/plugin/staticwebgen.lua
|
||||
-- AFTER all plugins are loaded
|
||||
print('TODO: disabled for now..not stable')
|
||||
os.exit()
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ return function(app,argv)
|
|||
io.write("Flags:\n\n")
|
||||
foreach( app.opts, function(k,v)
|
||||
if not k:match("/") and not k:match("^help") and not k:match("updated") then
|
||||
io.write( " " .. k .. "='" .. v .. "'\n")
|
||||
io.write( " " .. k .. "='" .. v:gsub("\n","") .. "'\n")
|
||||
end
|
||||
end)
|
||||
io.write("\n> NOTE: flags override flags in xrforge.lua configfile]\n")
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ return function(app,argv)
|
|||
print("starting server")
|
||||
if not util.contains(arg,"--nobrowser") then
|
||||
if arg[1] == 'admin' then
|
||||
print("ℹ️ admin login/pass is " .. app.opts.admin_user .. "/" .. app.opts.admin_pass)
|
||||
LaunchBrowser('/admin')
|
||||
else
|
||||
LaunchBrowser('/')
|
||||
|
|
|
|||
|
|
@ -54,11 +54,15 @@ body{
|
|||
font-size:14px;
|
||||
}
|
||||
|
||||
img.icon.invert,
|
||||
img.icon.link,
|
||||
img.icon.play,
|
||||
img.icon.download,
|
||||
img.icon.list-tree{
|
||||
filter: invert(1);
|
||||
}
|
||||
img.icon.play{
|
||||
filter: invert(1);
|
||||
img.icon.download,
|
||||
img.icon.play,{
|
||||
transform: translate(0,-1px);
|
||||
}
|
||||
|
||||
|
|
|
|||
16
src/img/download.svg
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M11 5C11 4.44772 11.4477 4 12 4C12.5523 4 13 4.44772 13 5V12.1578L16.2428 8.91501L17.657 10.3292L12.0001 15.9861L6.34326 10.3292L7.75748 8.91501L11 12.1575V5Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M4 14H6V18H18V14H20V18C20 19.1046 19.1046 20 18 20H6C4.89543 20 4 19.1046 4 18V14Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 445 B |
22
src/img/drive.svg
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M19 11C18.4477 11 18 11.4477 18 12C18 12.5523 18.4477 13 19 13C19.5523 13 20 12.5523 20 12C20 11.4477 19.5523 11 19 11Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M14 12C14 11.4477 14.4477 11 15 11C15.5523 11 16 11.4477 16 12C16 12.5523 15.5523 13 15 13C14.4477 13 14 12.5523 14 12Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M2 8C0.895431 8 0 8.89543 0 10V14C0 15.1046 0.89543 16 2 16H22C23.1046 16 24 15.1046 24 14V10C24 8.89543 23.1046 8 22 8H2ZM22 10H2L2 14H22V10Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 679 B |
20
src/img/link.svg
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M14.8284 12L16.2426 13.4142L19.071 10.5858C20.6331 9.02365 20.6331 6.49099 19.071 4.9289C17.509 3.3668 14.9763 3.3668 13.4142 4.9289L10.5858 7.75732L12 9.17154L14.8284 6.34311C15.6095 5.56206 16.8758 5.56206 17.6568 6.34311C18.4379 7.12416 18.4379 8.39049 17.6568 9.17154L14.8284 12Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M12 14.8285L13.4142 16.2427L10.5858 19.0711C9.02372 20.6332 6.49106 20.6332 4.92896 19.0711C3.36686 17.509 3.36686 14.9764 4.92896 13.4143L7.75739 10.5858L9.1716 12L6.34317 14.8285C5.56212 15.6095 5.56212 16.8758 6.34317 17.6569C7.12422 18.4379 8.39055 18.4379 9.1716 17.6569L12 14.8285Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M14.8285 10.5857C15.219 10.1952 15.219 9.56199 14.8285 9.17147C14.4379 8.78094 13.8048 8.78094 13.4142 9.17147L9.1716 13.4141C8.78107 13.8046 8.78107 14.4378 9.1716 14.8283C9.56212 15.2188 10.1953 15.2188 10.5858 14.8283L14.8285 10.5857Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1 KiB |
|
|
@ -1,5 +0,0 @@
|
|||
<title>world 1 title</title>
|
||||
<fireboxroom>
|
||||
<room use_local_asset="room2">
|
||||
</room>
|
||||
</fireboxroom>
|
||||
|
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 147 KiB |
BIN
src/myverse/janusxr_tutorial/AFRAME.jpg
Normal file
|
After Width: | Height: | Size: 32 KiB |
6
src/myverse/janusxr_tutorial/AFRAME/README.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# AFRAME hello world
|
||||
|
||||
[XRForge's](https://xrforge.isvery.ninja/) [JanusXR](https://coderofsalvation.github.io/janus-guide/)-viewer ([janusweb](https://github.com/jbaicoianu/janusweb)) can detect [AFRAME](https://aframe.io) markup in HTML/XML/even binary files(!).
|
||||
This basically extends [the seamless JanusXR portalsystem](https://coderofsalvation.github.io/janus-guide/#/home/about) by <b>interconnecting</b> otherwise immersively-disjointed ecosystems like [AFRAME](https://aframe.io), by [reprojecting them in 3D](https://coderofsalvation.github.io/janus-guide/#/home/about).
|
||||
|
||||
Currently only geometry markup and models are supported.
|
||||
12
src/myverse/janusxr_tutorial/AFRAME/index.html
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<a-scene>
|
||||
<a-assets>
|
||||
<a-asset-item id="tree" src="tree2.glb"></a-asset-item>
|
||||
</a-assets>
|
||||
|
||||
<a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"></a-box>
|
||||
<a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere>
|
||||
<a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
|
||||
<a-plane position="0 0 -4" rotation="-90 0 0" width="7" height="7" color="#7BC8A4"></a-plane>
|
||||
<a-gltf-model src="#tree" position="-2 0.05 -5.5" scale="2 2 2"></a-gltf-model>
|
||||
|
||||
</a-scene>
|
||||
BIN
src/myverse/janusxr_tutorial/AFRAME/tree2.glb
Normal file
BIN
src/myverse/janusxr_tutorial/helloworld.jpg
Normal file
|
After Width: | Height: | Size: 21 KiB |
5
src/myverse/janusxr_tutorial/helloworld/README.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# JanusXR JML
|
||||
|
||||
[XRForge's](https://xrforge.isvery.ninja/) uses a [JanusXR](https://coderofsalvation.github.io/janus-guide/)-viewer called ([janusweb](https://github.com/jbaicoianu/janusweb)).
|
||||
|
||||
> JanusWeb supports various URLs, containing [JML](https://coderofsalvation.github.io/janus-guide/#/build/room), [XRFragments](https://xrfragment.org), RSS/Atom, HTML, and so on..basically an <b>in-browser VR browser</b>
|
||||
10
src/myverse/janusxr_tutorial/helloworld/janusxr.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<title>JanusXR hello world</title>
|
||||
<fireboxroom>
|
||||
<room use_local_asset="room4">
|
||||
|
||||
<object id="cube" pos="-5 1 0" scale="2 2 2"/>
|
||||
|
||||
<link js_id="aframescene" shader_id="defaultportal" draw_glow="false" url="../AFRAME/index.html" pos="2 0 0 "/>
|
||||
|
||||
</room>
|
||||
</fireboxroom>
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
# Tron World 1
|
||||
|
||||
This is a test
|
||||
This is a glTF world which is only 65 kilobytes in size.<br>
|
||||
Say what?<br>
|
||||
<br>
|
||||
> Fitting an entire virtual world into 65 KB is like trying to condense the whole Marvel Cinematic Universe into a single tweet. It’s the digital equivalent of trying to build a full-scale, functioning Disneyland inside a hollowed-out peanut shell.
|
||||
|
||||
> This is a blockquote
|
||||
|
||||
And [this](https://xrfragment.org) is an URL.
|
||||
Read more about [best practices at xrfragment.org](https://xrfragment.org/#Best%20practices)
|
||||
|
|
|
|||
|
|
@ -1,52 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.0//EN" "https://www.web3d.org/specifications/x3d-3.0.dtd">
|
||||
<X3D version="3.0" profile="Immersive" xmlns:xsd="http://www.w3.org/2001/XMLSchema-instance" xsd:noNamespaceSchemaLocation="https://www.web3d.org/specifications/x3d-3.0.xsd">
|
||||
<head>
|
||||
<meta name="filename" content="test_world.x3d" />
|
||||
<meta name="generator" content="Blender 2.78 (sub 0)" />
|
||||
</head>
|
||||
<Scene>
|
||||
<NavigationInfo headlight="true"
|
||||
visibilityLimit="0.0"
|
||||
type='"EXAMINE", "ANY"'
|
||||
avatarSize="0.25, 1.75, 0.75"
|
||||
/>
|
||||
<Background DEF="WO_World"
|
||||
groundColor="0.051 0.051 0.051"
|
||||
skyColor="0.051 0.051 0.051"
|
||||
/>
|
||||
<Transform DEF="Cube_TRANSFORM"
|
||||
translation="0.000000 1.000000 0.000000"
|
||||
scale="5.000000 5.000000 1.000000"
|
||||
rotation="0.000000 0.707107 0.707107 3.141593"
|
||||
>
|
||||
<Transform DEF="Cube_ifs_TRANSFORM"
|
||||
translation="0.000000 0.000000 0.000000"
|
||||
scale="1.000000 1.000000 1.000000"
|
||||
rotation="1.000000 0.000000 0.000000 0.000000"
|
||||
>
|
||||
<Group DEF="group_ME_Cube">
|
||||
<Shape>
|
||||
<Appearance>
|
||||
<Material DEF="MA_Material"
|
||||
diffuseColor="0.500 0.500 1.000"
|
||||
specularColor="0.401 0.401 0.401"
|
||||
emissiveColor="0.000 0.000 0.000"
|
||||
ambientIntensity="0.333"
|
||||
shininess="0.098"
|
||||
transparency="0.000"
|
||||
/>
|
||||
</Appearance>
|
||||
<IndexedFaceSet solid="true"
|
||||
coordIndex="0 3 2 1 -1 4 5 6 7 -1 0 1 5 4 -1 1 2 6 5 -1 2 3 7 6 -1 3 0 4 7 -1 "
|
||||
>
|
||||
<Coordinate DEF="coords_ME_Cube"
|
||||
point="1.000000 1.000000 -1.000000 1.000000 -1.000000 -1.000000 -1.000000 -1.000000 -1.000000 -1.000000 1.000000 -1.000000 1.000000 0.999999 4.000000 0.999999 -1.000001 4.000000 -1.000000 -1.000000 4.000000 -1.000000 1.000000 4.000000 "
|
||||
/>
|
||||
</IndexedFaceSet>
|
||||
</Shape>
|
||||
</Group>
|
||||
</Transform>
|
||||
</Transform>
|
||||
</Scene>
|
||||
</X3D>
|
||||
|
|
@ -6,7 +6,7 @@ header h2{
|
|||
font-weight: normal;
|
||||
}
|
||||
header{
|
||||
background-image: linear-gradient(0deg,#0000,#101,#0000), url(/myverse/tronverse/tron/tron.png);
|
||||
background-image: linear-gradient(0deg,#0000,#101,#0000), url(myverse/tronverse/tron/tron.png);
|
||||
background-position-x: 0%;
|
||||
background-position-y: 0%;
|
||||
background-repeat: repeat;
|
||||
|
|
@ -20,7 +20,7 @@ header{
|
|||
|
||||
div#hint{
|
||||
float:right;
|
||||
background: url(/img/blinkhint.svg);
|
||||
background: url(img/blinkhint.svg);
|
||||
height: 129px;
|
||||
background-size: cover;
|
||||
display:inline-block;
|
||||
|
|
@ -28,7 +28,7 @@ div#hint{
|
|||
}
|
||||
|
||||
div#badges{
|
||||
background: url(/img/badges.png);
|
||||
background: url(img/badges.png);
|
||||
height: 90px;
|
||||
background-repeat:no-repeat;
|
||||
background-size: contain;
|
||||
|
|
@ -39,7 +39,7 @@ div#badges{
|
|||
}
|
||||
|
||||
div#xrecosystem{
|
||||
background: #000 url(/img/xrecosystem.png);
|
||||
background: #000 url(img/xrecosystem.png);
|
||||
background-repeat: no-repeat;
|
||||
height: 200px;
|
||||
background-size: cover;
|
||||
|
|
@ -67,7 +67,7 @@ div#xrecosystem{
|
|||
<br/>
|
||||
<div class="btn">
|
||||
<a href="https://codeberg.org/coderofsalvation/xrforge" class="" style="text-align:left">
|
||||
<img src="/img/codeberg.svg" style="width:20px">
|
||||
<img src="img/codeberg.svg" style="width:20px">
|
||||
Check the sourcecode<br>
|
||||
<small>docker run codeforge.org/coderofsalvation/xrforge:latest</small>
|
||||
</a>
|
||||
|
|
@ -79,7 +79,7 @@ div#xrecosystem{
|
|||
</noscript>
|
||||
<div class="btn">
|
||||
<a href="https://chat.isvery.ninja" class="secondary" style="text-align:left">
|
||||
<img src="/img/obsidian.png" style="width:20px">
|
||||
<img src="img/obsidian.png" style="width:20px">
|
||||
chat with community <br>
|
||||
<small>irc.isvery.ninja port 443 via ObsidianIRC</small>
|
||||
</a>
|
||||
|
|
@ -347,7 +347,7 @@ div#xrecosystem{
|
|||
<h3>JanusXR: The deep spatial web (within the web)</h3>
|
||||
<div style="max-width:945px;">
|
||||
<a href="https://coderofsalvation.github.io/janus-guide/" target="_blank">
|
||||
<img src="/img/janusxr-xrf.png" style="width:100%"/>
|
||||
<img src="img/janusxr-xrf.png" style="width:100%"/>
|
||||
</a>
|
||||
<br>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ end)
|
|||
function pluginUI(seen,data)
|
||||
return function(name,plugin)
|
||||
if plugin.hide or seen[ plugin.name ] then return end -- already processed
|
||||
table.insert( data.tabs, plugin.name ) -- insert tabname
|
||||
table.insert( data.tabs, plugin.tab or plugin.name ) -- insert tabname
|
||||
seen[ plugin.name ] = true
|
||||
local plugindata = {plugin=plugin}
|
||||
plugindata.opts = ""
|
||||
|
|
@ -88,6 +88,7 @@ function saveData()
|
|||
end
|
||||
end)
|
||||
if saveconfig then
|
||||
app.set('app.opts', app.opts)
|
||||
data.notification = '<div class="notification">updated</div>'
|
||||
else
|
||||
data.notification = '<div class="notification">no changes detected</div>'
|
||||
|
|
|
|||
|
|
@ -23,42 +23,38 @@ end}
|
|||
local item = items[i]
|
||||
local icon = 'list-tree'
|
||||
local thumbnail = ''
|
||||
if #item.thumbnail > 0 then thumbnail = 'style="background-image: url(' .. EscapeFragment(item.thumbnail) .. ');"' end
|
||||
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([[
|
||||
<div class="tile">
|
||||
<a href="]] .. item.url .. [[">
|
||||
<div class="img" ]] .. thumbnail .. [[></div>
|
||||
<a href="]] .. util.stripPath(item.url) .. [[">
|
||||
<div class="img" ]] .. util.stripPath(thumbnail) .. [[></div>
|
||||
<div class="text">
|
||||
<img src="img/]] .. icon .. [[.svg" class="icon ]] .. icon .. [["/> <a href="]] .. item.url .. [[">]] .. item.title .. [[</a>
|
||||
<img src="img/]] .. icon .. [[.svg" class="icon ]] .. icon .. [["/> <a href="]] .. util.stripPath(item.url) .. [[">]] .. item.title .. [[</a>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
]])
|
||||
end
|
||||
end}
|
||||
{if parent.parent == nil then
|
||||
for i=1,5 do
|
||||
local urls = app.opts[ 'plugin_federation_url_' .. i]
|
||||
if #urls > 0 then
|
||||
local title = urls:gsub(' .*','')
|
||||
local fediurl = '/?url=' .. EscapeFragment(title)
|
||||
local thumburl = urls:gsub('.* ','')
|
||||
local icon = 'list-tree'
|
||||
{if itemsremote then
|
||||
for i=1,#itemsremote do
|
||||
local item = itemsremote[i]
|
||||
local icon = 'link'
|
||||
local thumbnail = ''
|
||||
if #thumburl > 0 then thumbnail = 'style="background-image: url(' .. EscapeFragment(thumburl) .. ');"' end
|
||||
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([[
|
||||
<div class="tile">
|
||||
<a href="]] .. fediurl .. [[">
|
||||
<div class="img" ]] .. thumbnail .. [[></div>
|
||||
<a href="]] .. util.stripPath(item.url) .. [[">
|
||||
<div class="img" ]] .. util.stripPath(thumbnail) .. [[></div>
|
||||
<div class="text">
|
||||
<img src="img/]] .. icon .. [[.svg" class="icon ]] .. icon .. [["/> <a href="]] .. fediurl .. [[">]] .. title .. [[</a>
|
||||
<img src="img/]] .. icon .. [[.svg" class="icon ]] .. icon .. [["/> <a href="]] .. util.stripPath(item.url) .. [[">]] .. item.title .. [[</a>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
]])
|
||||
end
|
||||
end
|
||||
end}
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ return {
|
|||
|
||||
middleware = function(req,res,next)
|
||||
local rootpath = "/" .. app.opts.plugin_diskscan_dirname
|
||||
local urlpath = GetPath()
|
||||
local urlpath = req.url
|
||||
local isroot = urlpath == "/" or urlpath:match("^"..rootpath.."[/]?$")
|
||||
res.items = {}
|
||||
res.template = res.template or 'page/dir.html'
|
||||
local isdir = urlpath:sub(-1) == "/"
|
||||
|
|
@ -14,9 +15,8 @@ return {
|
|||
local match = function(a,b) return util.stripPath(a) == util.stripPath(b) end
|
||||
local urlhash = urlpath .. util.dump( req.param )
|
||||
|
||||
if urlpath == "/"
|
||||
or urlpath:match("^"..rootpath)
|
||||
and not urlpath:gsub(".*/",""):match("%.")
|
||||
if (isroot or urlpath:match("^"..rootpath))
|
||||
and not urlpath:gsub(".*/",""):match("%.") -- no regular file with extension
|
||||
and not req.param.url then
|
||||
|
||||
local redirect = false
|
||||
|
|
@ -26,10 +26,10 @@ return {
|
|||
foreach( app.cache.items, function(k,v)
|
||||
if req.authenticated or app.plugin.moderation.isAllowed(v) then
|
||||
if v.parent then
|
||||
trace( "path = " .. util.stripPath(v.path) .. " " ..
|
||||
"parent = " .. util.stripPath(v.parent.path) .. " " ..
|
||||
"matchpath = " .. util.stripPath(matchpath)
|
||||
)
|
||||
-- trace( "path = " .. util.stripPath(v.path) .. " " ..
|
||||
-- "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
|
||||
|
|
@ -45,7 +45,6 @@ return {
|
|||
-- add items from dir
|
||||
if match(v.parent.path, matchpath) then
|
||||
if v.dir or v.view3D then
|
||||
trace("-- dir item: " .. v.path )
|
||||
local parent = app.cache.items[ v.parent.id ]
|
||||
res.items[ v.id ] = v
|
||||
res.parent = parent
|
||||
|
|
@ -57,32 +56,35 @@ return {
|
|||
|
||||
local data = util.merge({
|
||||
url = req.param.url, -- query hint to render janus.url in iframe (index.html)
|
||||
html_items='',
|
||||
items = {},
|
||||
parent=res.parent
|
||||
},{ opts = app.opts })
|
||||
local i = 0
|
||||
foreach( res.items, function(k,v)
|
||||
-- position items for janusxr JML (dir.html)
|
||||
-- add extra metadata for janusxr JML (janusxr.html and dir.html)
|
||||
table.insert(data.items, util.merge({x = i*2, i = i},v) )
|
||||
i=i+1
|
||||
if v.view3D then
|
||||
local isMarkupExperience = function(v)
|
||||
return v.janusxr and (v.janusxr.jml or v.janusxr.aframe)
|
||||
end
|
||||
-- prioritize markup experience above binary 3D files as experience containers
|
||||
if not data.item or (isMarkupExperience(v) and not isMarkupExperience(data.item)) then
|
||||
data.item = v
|
||||
data.title = data.item.title
|
||||
data.parent = v.parent
|
||||
local port = ':' .. GetPort()
|
||||
if port == 80 then port = '' end
|
||||
data.url = GetScheme() .. '://' .. GetHost() .. port .. v.url
|
||||
if v.janusxr and v.janusxr.jml then
|
||||
data.url = app.opts.baseurl .. util.stripPath(v.url) -- because we are running in iframe
|
||||
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 )
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
if data.item then
|
||||
res.template = 'page/index.html'
|
||||
end
|
||||
app.pub("dir", nil, {res=res,data=data, urlpath=urlpath, isdir=isdir})
|
||||
app.pub("dir", nil, {res=res,data=data, urlpath=urlpath, isroot=isroot, isdir=isdir})
|
||||
if not redirect then
|
||||
app.cache.url[ urlhash ] = util.templateFile( res.template, data)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -17,13 +17,20 @@
|
|||
<a href="https://nlnet.nl">NLNET</a><br/>
|
||||
</td>
|
||||
<td class="col3">
|
||||
<a href="/?view=3D">View from XR Device</a><br/>
|
||||
<a href="/${opts.plugin_diskscan_dirname}">Content overview</a><br/>
|
||||
<a href="/about">About</a><br/>
|
||||
<a href="?view=3D">View from XR Device</a><br/>
|
||||
<a href="${opts.plugin_diskscan_dirname}">Content overview</a><br/>
|
||||
<a href="about">About</a><br/>
|
||||
</td>
|
||||
<td class="col3">
|
||||
<a href="https://codeberg.org/coderofsalvation/xrforge">Sourcecode</a> <br>
|
||||
<img src="/img/button-88x31.gif" style="display:inline-block"/>
|
||||
<img src="img/button-88x31.gif" style="display:inline-block"/><br/>
|
||||
<a href="https://codeberg.org/coderofsalvation/xrforge-v2">Sourcecode</a> <br>
|
||||
{if footerlinks then
|
||||
for i,v in pairs(footerlinks) do
|
||||
print([[
|
||||
<a href="]] .. v.url .. [[">]] .. v.title .. [[</a><br>
|
||||
]])
|
||||
end
|
||||
end}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<base href="${opts.baseurl}" />
|
||||
<title>${opts.plugin_global_title}</title>
|
||||
<link rel="stylesheet" href="/css/xrforge.css"></link>
|
||||
<link rel="stylesheet" href="css/xrforge.css"></link>
|
||||
${opts.plugin_global_headertags}
|
||||
<noscript>
|
||||
{if urlpath == '/' or urlpath == '/index.html' then
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
<td class="menu">
|
||||
<div class="margin1L">
|
||||
<!-- important: no spaces between anchor tags for older browsers without flexbox -->
|
||||
<a href="/${opts.plugin_diskscan_dirname}"><img class="icon" src="/img/list-tree.svg">${opts.plugin_global_topmenu_mapname}</a>
|
||||
<a href="${opts.plugin_diskscan_dirname}"><img class="icon" src="img/list-tree.svg">${opts.plugin_global_topmenu_mapname}</a>
|
||||
{if true then
|
||||
print( app.opts.plugin_global_topmenu_html:gsub("\n"," ") )
|
||||
end}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ ${header}
|
|||
<div></div>
|
||||
</div>
|
||||
|
||||
<iframe border="0" frameborder="0" src="/janusweb/index.html#janus.url=${url}" id="viewer"></iframe>
|
||||
<iframe border="0" frameborder="0" src="janusweb/index.html#janus.url=${url}" id="viewer"></iframe>
|
||||
|
||||
{if item and item.parent and item.parent.info then
|
||||
print([[
|
||||
|
|
@ -14,7 +14,7 @@ ${header}
|
|||
<noscript>
|
||||
<img src="${item.parent.thumbnail}" width="100%"/>
|
||||
</noscript>
|
||||
<img src="/img/close.svg" width="20" class="icon close" onclick="document.querySelector('#popup').style.display = 'none'"/>
|
||||
<img src="img/close.svg" width="20" class="icon close" onclick="document.querySelector('#popup').style.display = 'none'"/>
|
||||
]] .. item.parent.info .. [[
|
||||
</div>
|
||||
]])
|
||||
|
|
@ -31,9 +31,14 @@ end}
|
|||
if( url == document.location.href ) return
|
||||
try{ // handle external urls via ?url=
|
||||
let urlObj = new URL(url)
|
||||
if( document.location.origin != urlObj.origin ){
|
||||
url = document.location.origin + document.location.pathname + '?url=' + url
|
||||
}
|
||||
}catch(e){}
|
||||
const isFileWithExtension = url.replace( new RegExp('./','g'),"").match("\\.")
|
||||
if( !isFileWithExtension ){
|
||||
window.history.replaceState( url, iframe.contentDocument.title, url );
|
||||
}
|
||||
setTimeout( () => {
|
||||
document.title = iframe.contentDocument.title
|
||||
}, 1000 )
|
||||
|
|
|
|||
|
|
@ -14,6 +14,13 @@ end}
|
|||
end
|
||||
end
|
||||
end}
|
||||
{if itemsremote and #itemsremote > 0 then
|
||||
for i,v in pairs(itemsremote) do
|
||||
if #v.thumbnail > 0 then
|
||||
print('\t<assetimage src="' .. v.thumbnail .. '" id="imgremote' .. i .. '"/>')
|
||||
end
|
||||
end
|
||||
end}
|
||||
{if showfediportals then
|
||||
for i=1,5 do
|
||||
local urls = app.opts[ 'plugin_federation_url_' .. i]
|
||||
|
|
@ -49,9 +56,6 @@ end}
|
|||
end}
|
||||
<text js_id="location" pos="0 6 -5" billboard="y" col="#BBFFFF" scale="10 10 1" text="${url}" emissive="0 0 0" roughness="0.3" metalness="0" />
|
||||
{if not item and items and #items > 0 then
|
||||
local portals = {}
|
||||
for i,v in pairs(items) do table.insert(portals, v) end
|
||||
if parent then table.insert(portals, p) end
|
||||
for i,v in pairs(items) do
|
||||
local width = 3.2
|
||||
local center = -((#items*width)/1.3) + (i*width)
|
||||
|
|
@ -65,27 +69,24 @@ end}
|
|||
addPortal('dir',center, v, url,i, -4, thumb, '0 0 0', '0.2 0.2 0.2')
|
||||
end
|
||||
end}
|
||||
{if showfediportals and not item then
|
||||
local portals = {}
|
||||
for i=1,5 do
|
||||
local urls = app.opts[ 'plugin_federation_url_' .. i]
|
||||
if #urls > 0 then
|
||||
local fediurl = urls:gsub(' .*','')
|
||||
table.insert(portals, fediurl )
|
||||
end
|
||||
end
|
||||
if #portals > 0 then
|
||||
print([[
|
||||
<text js_id="location" pos="0 6 5" billboard="y" col="#BBFFFF" scale="10 10 1" text="${opts.plugin_federation_title}" emissive="0 0 0" roughness="0.3" metalness="0" />
|
||||
]])
|
||||
end
|
||||
for i,fediurl in pairs(portals) do
|
||||
{if not item and itemsremote and #itemsremote > 0 then
|
||||
for i,v in pairs(itemsremote) do
|
||||
local width = 3.2
|
||||
local center = -((#portals*width)/1.3) + (i*width)
|
||||
local thumb = ' thumb_id="federated' .. i .. '"'
|
||||
addPortal('federated',center, {title=fediurl}, fediurl,i, 4, thumb, '0 180 0', '0.1 0.1 0.1')
|
||||
local center = -((#itemsremote*width)/1.3) + (i*width)
|
||||
local url = v.url
|
||||
local thumb = ' shader_id="defaultportal"'
|
||||
if #v.thumbnail > 0 then
|
||||
thumb = ' thumb_id="imgremote' .. i .. '" '
|
||||
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')
|
||||
end
|
||||
print([[
|
||||
<text js_id="locationremote" pos="0 6 5" billboard="y" col="#BBFFFF" scale="10 10 1" text="${opts.plugin_global_remote_title}" emissive="0 0 0" roughness="0.3" metalness="0" />
|
||||
]])
|
||||
end}
|
||||
|
||||
<object id="cube" rotation="0 0 0" position="0 0 0" scale="2 0.1 2"/> <!-- something to stand on -->
|
||||
${opts.plugin_janusxr_jml}
|
||||
</room>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ end)
|
|||
|
||||
-- this registers the plugin UI /funcs
|
||||
return {
|
||||
name = "Local Content",
|
||||
name = "Files",
|
||||
tab = "<img src='img/drive.svg' class='icon invert'/> Files",
|
||||
info = '',
|
||||
opts = {
|
||||
{
|
||||
|
|
|
|||
|
|
@ -11,70 +11,70 @@ app.on('set', function(k,v)
|
|||
end)
|
||||
|
||||
app.on('dir', function(opts)
|
||||
local me = app.plugin.federation
|
||||
if opts.urlpath == '/' then
|
||||
print_r(me.portals)
|
||||
--foreach( me.portals, function(k,portal)
|
||||
-- print("JAAA")
|
||||
-- table.insert( opts.data.items,{
|
||||
-- url = portal.url,
|
||||
-- name = portal.name,
|
||||
-- thumbnail = portal.thumbnail
|
||||
-- })
|
||||
--end)
|
||||
local showportals = app.opts.plugin_federation_strategy == 'always' or
|
||||
(app.opts.plugin_federation_strategy == 'homepage' and opts.isroot)
|
||||
if showportals then
|
||||
opts.data.itemsremote = opts.data.itemsremote or {}
|
||||
local itemsremote = opts.data.itemsremote
|
||||
for i=1,5 do
|
||||
local urls = app.opts[ 'plugin_federation_url_' .. i]
|
||||
if #urls > 0 then
|
||||
local url = urls:gsub(' .*','')
|
||||
local thumburl = urls:match(" ") and urls:gsub('.* ','') or nil
|
||||
table.insert(itemsremote, {
|
||||
title = url:gsub(".*//",""),
|
||||
thumbnail = thumburl,
|
||||
url = '/janusweb/index.html#janus.url=' .. EscapeFragment(url)
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local plugin = {
|
||||
name = 'Federation',
|
||||
tab = "<img src='img/link.svg' class='icon invert'/> Federation",
|
||||
info = 'Add links to other (janus)XR(forges), and have them show up as extra portals in portalrooms',
|
||||
opts = { -- TODO populate this based on xrforge-federation.json
|
||||
{
|
||||
key='app.opts.plugin_federation_title',
|
||||
title='Title',
|
||||
info="Displayed above federated portals",
|
||||
default="Federated neighbourhoods",
|
||||
values=''
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_federation_strategy',
|
||||
title='Display portals',
|
||||
info="When to show federated portals?",
|
||||
default="always",
|
||||
default="homepage",
|
||||
values={always='always',homepage='only homepage'}
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_federation_url_1',
|
||||
title='Federated URL 1',
|
||||
info="URL + Thumbnail URL (space separated)",
|
||||
info="URL and/or Thumbnail URL (space separated)",
|
||||
default="https://xrforge.isvery.ninja https://i.imgur.com/x7fzn9v.png",
|
||||
values=''
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_federation_url_2',
|
||||
title='Federated URL 2',
|
||||
info="URL + Thumbnail URL (space separated)",
|
||||
default="https://www.janusxr.org/new/ https://archive.org/download/janusxr-1/janusxr.png",
|
||||
info="URL and/or Thumbnail URL (space separated)",
|
||||
default="https://www.janusxr.org https://www.janusvr.com/images/logos/logotextoverlight.png",
|
||||
values=''
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_federation_url_3',
|
||||
title='Federated URL 3',
|
||||
info="URL + Thumbnail URL (space separated)",
|
||||
info="URL and/or Thumbnail URL (space separated)",
|
||||
default="",
|
||||
values=''
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_federation_url_4',
|
||||
title='Federated URL 4',
|
||||
info="URL + Thumbnail URL (space separated)",
|
||||
info="URL and/or Thumbnail URL (space separated)",
|
||||
default="",
|
||||
values=''
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_federation_url_5',
|
||||
title='Federated URL 5',
|
||||
info="URL + Thumbnail URL (space separated)",
|
||||
info="URL and/or Thumbnail URL (space separated)",
|
||||
default="",
|
||||
values=''
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@ end)
|
|||
-- this registers the plugin UI
|
||||
local plugin = {
|
||||
name = 'Git',
|
||||
info = '',
|
||||
info = 'Git repositories will be cloned before xrforge starts scanning for experiences',
|
||||
tab = "<img src='img/link.svg' class='icon invert'/> Git",
|
||||
opts = {
|
||||
{
|
||||
key='app.opts.plugin_git_repo_1',
|
||||
|
|
|
|||
|
|
@ -10,6 +10,38 @@ end)
|
|||
app.on('set', function(k,v)
|
||||
end)
|
||||
|
||||
app.on('init', function()
|
||||
if app.opts.plugin_global_credible_exit == 'platform' then
|
||||
if not util.fileExist( app.bin ) then -- check for binary in local filesystem
|
||||
os.execute("ln -fs " .. arg[-1] .. " .")
|
||||
os.execute("ln -fs " .. arg[-1] .. " " .. app.bin:gsub(".com",".zip"))
|
||||
end
|
||||
else
|
||||
if not util.fileExist( app.bin ) then
|
||||
os.execute("test -L " .. app.bin .. " && rm " .. app.bin ) -- delete symlink
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
app.on('util.template', function(data)
|
||||
if data.urlpath then
|
||||
local isAdminPath = data.urlpath:match("^/admin")
|
||||
if app.opts.plugin_global_credible_exit == 'platform' or
|
||||
(app.opts.plugin_global_credible_exit == 'platformadmin' and isAdminPath)
|
||||
then
|
||||
data.footerlinks = data.footerlinks or {}
|
||||
table.insert(data.footerlinks, {
|
||||
title="<img class='icon download' src='/img/download.svg'> Download data",
|
||||
url="/" .. app.bin:gsub(".com",".zip")
|
||||
})
|
||||
table.insert(data.footerlinks, {
|
||||
title="<img class='icon download' src='/img/download.svg'> Download data+platform",
|
||||
url="/" .. app.bin
|
||||
})
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- this registers the plugin UI
|
||||
local plugin = {
|
||||
name = "Global settings",
|
||||
|
|
@ -27,13 +59,13 @@ local plugin = {
|
|||
key='app.opts.plugin_global_subtitle',
|
||||
title='Subtitle',
|
||||
info='Slogan here',
|
||||
default = "Portable XR experiences for Phone, VRheadset & desktop.",
|
||||
default = "Interconnected XR experiences for Phone, VRheadset & desktop.",
|
||||
values=''
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_global_topmenu_mapname',
|
||||
title='Overview link',
|
||||
info='Top-right link <img class="icon list-tree" src="/img/list-tree.svg"> (overview page)',
|
||||
info='Top-right link <img class="icon list-tree" src="img/list-tree.svg"> (overview page)',
|
||||
default = "map",
|
||||
values=''
|
||||
},
|
||||
|
|
@ -41,14 +73,21 @@ local plugin = {
|
|||
key='app.opts.plugin_global_homepage',
|
||||
title='Homepage',
|
||||
info='Display 3D or 2D experiences on homepage',
|
||||
default = "2D",
|
||||
default = "3D",
|
||||
values={ ['3D'] = '3D', ['2D'] = '2D' },
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_global_credible_exit',
|
||||
title='Credible exit',
|
||||
info='How can users reproduce experiences locally?',
|
||||
default = "platform",
|
||||
values={ platform="download platform+data", platformadmin="download platform+data (admin only)" }
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_global_topmenu_html',
|
||||
title='Menu html',
|
||||
info='Add extra menu items here',
|
||||
default = '<a href="/about">about</a>',
|
||||
default = '<a href="about">about</a>',
|
||||
control='textarea',
|
||||
values=''
|
||||
},
|
||||
|
|
@ -64,6 +103,13 @@ local plugin = {
|
|||
control='textarea',
|
||||
values=''
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_global_remote_title',
|
||||
title='Title',
|
||||
info="Displayed above remote portals",
|
||||
default="Remote / Federated",
|
||||
values=''
|
||||
},
|
||||
},
|
||||
middleware = {
|
||||
homepage_2D_or_3D = function(req,res,next)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ local util = require('util')
|
|||
|
||||
local pattern_fireboxroom = "[Ff][Ii][Rr][Ee][Bb][Oo][Xx][Rr][Oo][Oo][Mm][ ]?.*>"
|
||||
local pattern_title = "<[Tt][Ii][Tt][Ll][Ee]>(.*)<"
|
||||
local pattern_aframe = "<a%-scene"
|
||||
|
||||
app.on('scan_experience', function(exp)
|
||||
--print_r(exp)
|
||||
|
|
@ -32,8 +33,8 @@ app.on('scan_experience_file', function(exp)
|
|||
if size < 100000 then -- skip large binary files > 100kb
|
||||
local data = util.readfile( exp.file.fullpath)
|
||||
if data then
|
||||
if data:match(pattern_fireboxroom) then
|
||||
table.insert(exp.tag, "janusxr")
|
||||
if data:match(pattern_fireboxroom) or
|
||||
data:match(pattern_aframe) then
|
||||
local title = data:match(pattern_title)
|
||||
if title then
|
||||
exp.title = title:gsub("<.*","")
|
||||
|
|
@ -41,8 +42,13 @@ app.on('scan_experience_file', function(exp)
|
|||
app.pub("scan_experience_janusxr", nil, {exp=exp, item=item}) -- be nice to other plugins
|
||||
app.cache.items[ exp.file.ino ] = exp
|
||||
exp.view3D = true
|
||||
exp.parent.redirect = exp.url -- mark parent to redirect to this standalone url instead (not glb assets e.g.)
|
||||
exp.janusxr = {}
|
||||
print("✅ └─ plugin/janusxr: " .. exp.file.name)
|
||||
if data:match(pattern_aframe) and app.opts.plugin_janusxr_wrap_aframe == 'enabled' then
|
||||
exp.janusxr.aframe = true
|
||||
print("✅ └─ plugin/janusxr: AFRAME markup detected")
|
||||
end
|
||||
end
|
||||
else
|
||||
-- symlink to directory
|
||||
|
|
@ -79,31 +85,31 @@ local plugin = {
|
|||
},
|
||||
{
|
||||
key='app.opts.plugin_janusxr_wrap_3dfile',
|
||||
title='wrap 3D file',
|
||||
title='VR wrap 3D file',
|
||||
info='render 3D files in <a href="https://coderofsalvation.github.io/janus-guide/#/build/room" target="_blank">janusxr.xml</a> room',
|
||||
default="room_plane",
|
||||
values=util.merge(rooms,{disabled="-- disabled --"})
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_janusxr_wrap_image',
|
||||
title='wrap images',
|
||||
title='VR wrap images',
|
||||
info='render images in <a href="https://coderofsalvation.github.io/janus-guide/#/build/room" target="_blank">janusxr.xml</a> room',
|
||||
default="room_plane",
|
||||
values=util.merge(rooms,{disabled="-- disabled --"})
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_janusxr_wrap_video',
|
||||
title='wrap videos',
|
||||
title='VR wrap videos',
|
||||
info='render videos in <a href="https://coderofsalvation.github.io/janus-guide/#/build/room" target="_blank">janusxr.xml</a> room',
|
||||
default="room_plane",
|
||||
values=util.merge(rooms,{disabled="-- disabled --"})
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_janusxr_wrap_aframe',
|
||||
title='wrap AFRAME',
|
||||
info='render AFRAME markup in <a href="https://coderofsalvation.github.io/janus-guide/#/build/room" target="_blank">janusxr.xml</a> room',
|
||||
default="room_plane",
|
||||
values=util.merge(rooms,{disabled="-- disabled --"})
|
||||
title='AFRAME support',
|
||||
info='render <a href="https://aframe.io">AFRAME</a> (geometry) markup when detected in URLs',
|
||||
default="enabled",
|
||||
values={enabled="enabled",disabled="disabled"}
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_janusxr_portalroom',
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ end)
|
|||
-- this registers the plugin UI
|
||||
local plugin = {
|
||||
name = "Manyfold",
|
||||
tab = "<img src='img/link.svg' class='icon invert'/> Manyfold",
|
||||
info = '',
|
||||
opts = {
|
||||
{
|
||||
|
|
|
|||
85
src/plugin/peertube.lua
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
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)
|
||||
|
||||
app.on('dir', function(opts)
|
||||
local showportals = app.opts.plugin_peertube_strategy == 'always' or
|
||||
(app.opts.plugin_peertube_strategy == 'homepage' and opts.isroot)
|
||||
if showportals then
|
||||
opts.data.itemsremote = opts.data.itemsremote or {}
|
||||
local itemsremote = opts.data.itemsremote
|
||||
for i=1,5 do
|
||||
local urls = app.opts[ 'plugin_peertube_url_' .. i]
|
||||
if #urls > 0 then
|
||||
local url = urls:gsub(' .*','')
|
||||
local thumburl = urls:match(" ") and urls:gsub('.* ','') or nil
|
||||
table.insert(itemsremote, {
|
||||
title = url:gsub(".*//",""),
|
||||
thumbnail = thumburl,
|
||||
url = '/janusweb/index.html#janus.url=' .. EscapeFragment(url)
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- this registers the plugin UI
|
||||
local plugin = {
|
||||
name = "Peertube",
|
||||
tab = "<img src='img/link.svg' class='icon invert'/> Peertube",
|
||||
info = "<b class='tag'>disabled</b> <a href='https://joinpeertube.org' target='_blank'>Peertube</a> videos/channels/livestreams can be rendered as rooms in <a href='https://coderofsalvation.github.io/janus-guide/#/build/peertube' target='_blank'>JanusWeb</a>",
|
||||
opts = {
|
||||
{
|
||||
key='app.opts.plugin_peertube_strategy',
|
||||
title='Display portals',
|
||||
info="When to show peertube portals?",
|
||||
default="homepage",
|
||||
values={always='always',homepage='only homepage'}
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_peertube_url_1',
|
||||
title='Peertube URL 1',
|
||||
info="URL and/or Thumbnail URL (space separated)",
|
||||
default="https://tilvids.com/c/arthurpizza https://oss.iqrator.org/wp-content/uploads/2026/01/00-16-510x510.png",
|
||||
values='https://tilvids.com/c/arthurpizza https://oss.iqrator.org/wp-content/uploads/2026/01/00-16-510x510.png'
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_peertube_url_2',
|
||||
title='Peertube URL 2',
|
||||
info="URL and/or Thumbnail URL (space separated)",
|
||||
default="",
|
||||
values=''
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_peertube_url_3',
|
||||
title='Peertube URL 3',
|
||||
info="URL and/or Thumbnail URL (space separated)",
|
||||
default="",
|
||||
values=''
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_peertube_url_4',
|
||||
title='Peertube URL 4',
|
||||
info="URL and/or Thumbnail URL (space separated)",
|
||||
default="",
|
||||
values=''
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_peertube_url_5',
|
||||
title='Peertube URL 5',
|
||||
info="URL and/or Thumbnail URL (space separated)",
|
||||
default="",
|
||||
values=''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return plugin
|
||||
85
src/plugin/rssatom.lua
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
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)
|
||||
|
||||
app.on('dir', function(opts)
|
||||
local showportals = app.opts.plugin_rssatom_strategy == 'always' or
|
||||
(app.opts.plugin_rssatom_strategy == 'homepage' and opts.isroot)
|
||||
if showportals then
|
||||
opts.data.itemsremote = opts.data.itemsremote or {}
|
||||
local itemsremote = opts.data.itemsremote
|
||||
for i=1,5 do
|
||||
local urls = app.opts[ 'plugin_rssatom_url_' .. i]
|
||||
if #urls > 0 then
|
||||
local url = urls:gsub(' .*','')
|
||||
local thumburl = urls:match(" ") and urls:gsub('.* ','') or nil
|
||||
table.insert(itemsremote, {
|
||||
title = url:gsub(".*//",""),
|
||||
thumbnail = thumburl,
|
||||
url = '/janusweb/index.html#janus.url=' .. EscapeFragment(url)
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- this registers the plugin UI
|
||||
local plugin = {
|
||||
name = "RSS Atom",
|
||||
tab = "<img src='img/link.svg' class='icon invert'/> RSS Atom",
|
||||
info = "<b class='tag'>disabled</b> RSS feeds can be rendered as rooms in <a href='https://coderofsalvation.github.io/janus-guide/#/build/feeds' target='_blank'>JanusWeb</a>",
|
||||
opts = {
|
||||
{
|
||||
key='app.opts.plugin_rssatom_strategy',
|
||||
title='Display portals',
|
||||
info="When to show rss portals?",
|
||||
default="homepage",
|
||||
values={always='always',homepage='only homepage'}
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_rssatom_url_1',
|
||||
title='RSS/Atom URL 1',
|
||||
info="URL and/or Thumbnail URL (space separated)",
|
||||
default="http://mastodon.online/@lvk.rss https://pbs.twimg.com/profile_images/1604566357206601730/dlRNo-V-_400x400.jpg",
|
||||
values='http://mastodon.online/@lvk.rss https://pbs.twimg.com/profile_images/1604566357206601730/dlRNo-V-_400x400.jpg'
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_rssatom_url_2',
|
||||
title='RSS/Atom URL 2',
|
||||
info="URL and/or Thumbnail URL (space separated)",
|
||||
default="https://nlnet.nl/feed.atom https://nlnet.nl/logo/history/logo-640x732-pre-2024.jpg",
|
||||
values='https://nlnet.nl/feed.atom https://nlnet.nl/logo/history/logo-640x732-pre-2024.jpg'
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_rssatom_url_3',
|
||||
title='RSS/Atom URL 3',
|
||||
info="URL and/or Thumbnail URL (space separated)",
|
||||
default="",
|
||||
values=''
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_rssatom_url_4',
|
||||
title='RSS/Atom URL 4',
|
||||
info="URL and/or Thumbnail URL (space separated)",
|
||||
default="",
|
||||
values=''
|
||||
},
|
||||
{
|
||||
key='app.opts.plugin_rssatom_url_5',
|
||||
title='RSS/Atom URL 5',
|
||||
info="URL and/or Thumbnail URL (space separated)",
|
||||
default="",
|
||||
values=''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return plugin
|
||||
|
|
@ -8,32 +8,10 @@ app.on('set', function(k,v)
|
|||
end)
|
||||
|
||||
app.on('init', function()
|
||||
local outdir = 'www'
|
||||
local url = {"/"}
|
||||
local me = app.plugin.staticwebgen
|
||||
if util.contains(argv, 'generate') then
|
||||
if util.fileExist(outdir) then
|
||||
print("[!] folder 'www' was already detected..please delete it")
|
||||
os.exit()
|
||||
me.generate()
|
||||
end
|
||||
local selfbinary = '../' .. argv[-1]
|
||||
os.execute("mkdir www")
|
||||
os.execute("cp -Lr " .. app.opts.plugin_diskscan_dir .. " " .. outdir .. "/.")
|
||||
os.execute("cd " .. outdir .. " && unzip " .. selfbinary .. " 'img/*' 'css/*' 'janusweb/*' 'shader/*'")
|
||||
foreach( app.cache.items, function(k,v)
|
||||
if v.dir then
|
||||
table.insert(url, v.url )
|
||||
end
|
||||
end)
|
||||
foreach( url, function(k,url)
|
||||
url = url:gsub("//","/")
|
||||
util.fetchServer( url, nil, function(req,res,next)
|
||||
print( outdir .. url .. '/index.html')
|
||||
util.writefile( outdir .. url .. '/index.html', res.body )
|
||||
end)
|
||||
end)
|
||||
end
|
||||
--print("files generated in 'www' folder")
|
||||
--os.exit()
|
||||
end)
|
||||
|
||||
-- this registers the plugin UI
|
||||
|
|
@ -77,7 +55,47 @@ local plugin = {
|
|||
default="",
|
||||
values=''
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
done = function()
|
||||
print("✅ finished generating 'www' folder")
|
||||
os.exit(0)
|
||||
end,
|
||||
|
||||
generate = function()
|
||||
local outdir = 'www'
|
||||
local root = app.opts.plugin_diskscan_dirname
|
||||
local urls = {"/","/about", "/" .. root }
|
||||
local urlLast = ''
|
||||
if util.fileExist(outdir) then
|
||||
print("[!] folder 'www' was already detected..please delete it")
|
||||
os.exit()
|
||||
end
|
||||
local selfbinary = '../' .. argv[-1]
|
||||
os.execute("mkdir www www/about")
|
||||
os.execute("cp -Lr " .. app.opts.plugin_diskscan_dir .. " " .. outdir .. "/.")
|
||||
os.execute("cd " .. outdir .. " && unzip " .. selfbinary .. " 'img/*' 'css/*' 'janusweb/*' 'shader/*'")
|
||||
foreach( app.cache.items, function(k,v)
|
||||
if v.dir then
|
||||
table.insert(urls, v.url )
|
||||
urlLast = v.url
|
||||
end
|
||||
end)
|
||||
|
||||
app.on('response', function(opts)
|
||||
local body = opts.res._body -- capture the output
|
||||
local url = opts.req.url:gsub("//","/")
|
||||
util.writefile( outdir .. url .. '/index.html', body )
|
||||
end)
|
||||
|
||||
foreach( urls, function(k,url)
|
||||
url = url:gsub("//","/")
|
||||
print("saving " .. url)
|
||||
util.queueServerRequest('GET', url, nil, nil, nil, nil, nil, 8080)
|
||||
app.run()
|
||||
end)
|
||||
app.plugin.staticwebgen.done()
|
||||
end
|
||||
}
|
||||
|
||||
return plugin
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ end)
|
|||
-- this registers the plugin UI
|
||||
local plugin = {
|
||||
name = 'Webhooks <b class="tag">disabled</b>',
|
||||
tab = "<img src='img/link.svg' class='icon invert'/> Webhooks",
|
||||
info = '',
|
||||
opts = {
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,17 +1,9 @@
|
|||
local lust = require 'test/lust'
|
||||
local util = require 'util'
|
||||
local describe, it, expect = lust.describe, lust.it, lust.expect
|
||||
-- usage: https://github.com/bjornbytes/lust
|
||||
|
||||
lust.queueServerRequest = function(method, path, params, host, headers, body, scheme, port)
|
||||
GetMethod = function() return method end
|
||||
GetPath = function() return path end
|
||||
GetParams = function() return params or {} end -- note: { {"key","value"} } format
|
||||
GetHost = function() return host or 'localhost' end
|
||||
GetHeaders = function() return headers or {} end
|
||||
GetScheme = function() return scheme or 'https' end
|
||||
GetBody = function() return body or '' end
|
||||
GetPort = function() return port or 80 end
|
||||
end
|
||||
lust.queueServerRequest = util.queueServerRequest
|
||||
|
||||
require('test/plugin_global')(lust)
|
||||
require('test/plugin_git')(lust)
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ build(){
|
|||
download janusweb
|
||||
cd src
|
||||
zip -yr ../result/bin/xrforge.com * .lua .init.lua .args
|
||||
test -n "$ARCH" && cp ../result/bin/xrforge.com ../result/bin/xrforge-$ARCH.com
|
||||
}
|
||||
|
||||
rebuild(){
|
||||
|
|
|
|||