xrforge/manyfold/root/hook.d/experience_updated/300-package_janusxr.rb

210 lines
8.3 KiB
Ruby
Executable file

#!/usr/bin/env ruby
require 'json'
require 'erb'
require_relative './../../xrforge.rb'
# Check if a filename is provided
if ARGV.length != 1
puts "Usage: #{$0} <path/to/experience/datapackage.json>"
exit 1
end
filename = ARGV[0]
JMLHeuristic = /<fireboxroom>.*?<\/fireboxroom>/im
metadataRegex= /(^<!--|<fireboxroom).*/im
templateDir = File.dirname(__FILE__)+"/../../templates/"
$links = []
def addLink(url)
$links.push(url)
return url
end
begin
# dont run for each file-update
if ! filename.end_with?("datapackage.json")
exit 0
end
# Change the directory
dir = File.dirname(filename)
dirPublic = dir.gsub("/mnt/","").gsub("#","%23")
Dir.chdir( File.dirname(filename) )
# Read and parse the JSON file
data = JSON.parse( File.read( "datapackage.json" ) )
#if data['keywords'].empty? || data['keywords'].include?('janusxr')
logfile = File.join( File.dirname(filename), ".xrforge/log.txt" )
XRForge.log("✅ starting build janusXR XR scene", logfile)
model_file = XRForge.getExperienceFile(data,dir,logfile)
# Check if a model file was found after the loop
if ! model_file
XRForge.log("❌ No suitable 3D file found for JanusXR-compatible experience", logfile)
end
# Get the value of the environment variable FEDERATE_DRIVE_HOST
federate_drive_host = ENV['FEDERATE_DRIVE_HOST']
autogenerate = true
janusweb_src = ENV['DEV'] ? "/janusweb/janusweb.js" : "/janusweb/janusweb.min.js"
if data['description'] && data['description'].match(JMLHeuristic)
if ! data['description'].match(/<room.* autogenerate.*>/i)
XRForge.log("✅ autogenerate attribute found in JML..keeping this JML",logfile)
autogenerate = false
jmlMatch = data['description'].match(JMLHeuristic)
jml = jmlMatch[0]
end
end
if autogenerate
assets = ""
objects = ""
startpos = ""
audiovisual = false
showavatar = "showavatar=\"false\""
data['keywords'] = data['keywords'] || []
data['description'] = data['description'] || ""
if data['description'].strip().length == 0
data['description'] = "Click the edit-button to change this description, or add the 'nodescription' tag to hide this."
end
# tags to JML rooms
use_local_asset = ""
use_local_asset = data['keywords'].include?('room1') ? "room1" : use_local_asset
use_local_asset = data['keywords'].include?('room2') ? "room2" : use_local_asset
use_local_asset = data['keywords'].include?('room3') ? "room3" : use_local_asset
use_local_asset = data['keywords'].include?('room4') ? "room4" : use_local_asset
use_local_asset = data['keywords'].include?('room5') ? "room5" : use_local_asset
use_local_asset = data['keywords'].include?('room6') ? "room5" : use_local_asset
use_local_asset = data['keywords'].include?('room1_pedestal') ? "room1_pedestal" : use_local_asset
use_local_asset = data['keywords'].include?('room2_pedestal') ? "room2_pedestal" : use_local_asset
use_local_asset = data['keywords'].include?('room2_narrow') ? "room3_narrow" : use_local_asset
# private room or not
if data['keywords'].include?('singleuser')
private = "private=\"true\""
data['keywords'] = data['keywords'] || []
showavatar = "showavatar=\"false\""
end
if data['keywords'].include?('showavatar')
showavatar = "showavatar=\"false\""
end
# detect audio track sidecarfile as per XR Fragment spec: https://xrfragment.org/#%F0%9F%93%9C%20level0%3A%20File
xrf_ext = model_file ? File.extname(model_file) : ""
xrf_base = model_file ? File.basename(model_file, xrf_ext) : ""
# remove the metadata from the description
description = data['description'].gsub(metadataRegex,"").strip()
data['resources'].each do |resource|
ext = File.extname(resource['path'])
if ext.match(/mp3/i)
audiovisual = model_file ? false : true
base = File.basename(resource['path'], ext)
soundtrackUrl = addLink("#{federate_drive_host}/#{dirPublic}/#{resource["path"]}")
assets += " <assetsound id=\"soundtrack\" src=\"#{soundtrack_url}\"/>\n"
objects += "<sound id=\"soundtrack\" loop=\"true\"/>\n"
end
if ext.match(/(png|jpg|jpeg|gif)/i)
imgbase = File.basename(resource['path'])
if File.basename( data['image'] || "") != imgbase && # ignore thumbnail
xrf_base != imgbase # ignore XR Fragments thumbnail
audiovisual = model_file ? false : true
base = File.basename(resource['path'], ext)
videoSrc = addLink("#{federate_drive_host}/#{dirPublic}/#{resource["path"]}")
assets += "<assetimage id=\"image\" src=\"#{videoSrc}\" loop=\"true\" auto_play=\"true\"/>\n"
objects += " <Object cull_face=\"none\" id=\"rplane\" js_id=\"image\" lighting=\"false\" pos=\"0 6.5 5.5\" scale=\"4 4 1\" image_id=\"image\"/>\n"
end
end
if ext.match(/mp4/i) || ext.match(/webm/i)
audiovisual = model_file ? false : true
base = File.basename(resource['path'], ext)
videoSrc = addLink("#{federate_drive_host}/#{dirPublic}/#{resource["path"]}")
assets += "<assetvideo id=\"video\" src=\"#{videoSrc}\" loop=\"true\" auto_play=\"true\"/>\n"
objects += " <Object cull_face=\"none\" id=\"rplane\" js_id=\"video\" lighting=\"false\" pos=\"0 6.5 5.5\" scale=\"4 4 1\" video_id=\"video\"/>\n"
end
end
if audiovisual
# TODO: copy files from a heuristic-based folder instead hardcoding it here
startpos = "pos=\"0 0 -10\""
use_local_asset = "room5"
rplaneSrc = addLink("#{federate_drive_host}/#{dirPublic}/roundedplane.glb")
system("cp /root/templates/audiovisual/roundedplane.glb #{dir}/.")
assets += " <assetobject id=\"rplane\" src=\"#{rplaneSrc}\"/>\n"
objects += " <Object cull_face=\"none\" id=\"rplane\" js_id=\"text_rplane\" lighting=\"false\" pos=\"2.69 1.84 -3.37\" rotation=\"0 45 0\" scale=\"1.6 1 1\"/>\n"
if ! data['keywords'].include?( use_local_asset )
data['keywords'].push( use_local_asset )
end
end
# generate thumbnail if no thumbnail
if data['resources'].length == 1
thumbfile = "thumbnail.jpg"
if model_file
thumbfile = "#{xrf_base}.jpg"
end
system("/root/bin/random_thumbnail.sh","/root/templates/thumbnailseed.jpg","#{dir}/#{thumbfile}","6","2>&1 | sed 's|/root/template||g'")
data['image'] = thumbfile
XRForge.log("✅ generated thumbnail", logfile)
end
if description && !data['keywords'].include?('nodescription')
objects += " <Paragraph pos=\"2.8 1 -3.21\" fwd=\"0 0 1\" lighting=\"false\" rotation=\"180 -45 180\" col=\"0.5 0.8 0.5\" scale=\"2 2 2\" font_size=\"50\" locked=\"false\">#{description}</Paragraph>\n"
end
if model_file
objectSrc = "#{federate_drive_host}/#{dirPublic}/#{model_file.gsub("#","%23")}"
if ! $links.include?(objectSrc)
objectSrc = addLink(objectSrc)
assets += " <assetobject id=\"experience\" src=\"#{objectSrc}\"/>\n"
objects += " <object pos=\"0 0 5\" rotation=\"-180 0 180\" lighting=\"false\" collision_id=\"experience\" id=\"experience\" />"
end
end
use_local_asset = use_local_asset ? "use_local_asset=\"#{use_local_asset}\"" : ""
jml = ERB.new( File.read( templateDir+"JML/room.erb" ) ).result(binding)
data['description'] = data['description'] ? data['description'].gsub(metadataRegex,"") : ""
data['description'] += "\n\n" + ERB.new( File.read( templateDir+"JML/header.erb" ) ).result(binding)
data['description'] += jml
File.write("datapackage.json", JSON.pretty_generate(data) )
end
html = ERB.new( File.read( templateDir+"JML/client.html") ).result(binding)
File.write('.xrforge/janusxr.html', html)
File.write('.xrforge/scene.jml', jml)
XRForge.log("✅ generated scene.jml", logfile)
XRForge.log("✅ generated janusxr.html", logfile)
XRForge.log(" ", logfile)
# tag it!
if ! data['keywords'].include?('janusxr')
data['keywords'].push('janusxr')
File.write("datapackage.json", JSON.pretty_generate(data) )
end
rescue Errno::ENOENT
puts "File #{filename} not found"
rescue JSON::ParserError
puts "Error parsing JSON from #{filename}"
rescue => e
puts "An error occurred: #{e.message}"
end