210 lines
8.3 KiB
Ruby
Executable file
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
|
|
|