diff --git a/manyfold/root/hook.d/experience_updated/1000-extract-textures.rb b/manyfold/root/hook.d/experience_updated/1000-extract-textures.rb new file mode 100755 index 0000000..0bb0369 --- /dev/null +++ b/manyfold/root/hook.d/experience_updated/1000-extract-textures.rb @@ -0,0 +1,83 @@ +#!/usr/bin/env ruby + +require 'json' +require_relative './../../xrforge.rb' + +# Check if a filename is provided +if ARGV.length != 1 + puts "Usage: #{$0} " + exit 1 +end + +filename = ARGV[0] + +require 'base64' +require 'json' + +begin + + # Change the directory + dir = File.dirname(filename) + Dir.chdir( dir ) + # Read and parse the JSON file + data = JSON.parse( File.read( "datapackage.json" ) ) + logfile = File.join( File.dirname(filename), ".xrforge/log.txt" ) + + + data['resources'].each do |resource| + ext = File.extname(resource['path']) + filenameWithoutExt = File.basename(resource['path'], ext) + if ! XRForge::MODEL_EXT.any?( ext ) + next # skip unknown 3d files + end + if ! resource['path'].match(/^[a-zA-Z0-9]/) + next # skip filenames like '_generated.glb' e.g. (produced by hooks) + end + + XRForge.log("✅ unpacking textures", logfile) + gltf_path = ".xrforge/#{filenameWithoutExt}.gltf" + system("assimp export #{resource['path']} #{gltf_path} --embed-textures") + Dir.chdir("#{dir}/.xrforge") + system("assimp extract #{filenameWithoutExt}.gltf | sed 's|/.*/||g'") + Dir.chdir(dir) + + # Read and parse the GLTF JSON + gltf = JSON.parse(File.read(gltf_path)) + + # Ensure images section exists + unless gltf['images'] && gltf['images'].is_a?(Array) + puts "✅ No 'images' array found in #{gltf_path}" + next + end + + # Iterate through the images array + gltf['images'].each_with_index do |img, i| + name = img['name'] + next unless name && !name.empty? + + old_filename = "#{dir}/.xrforge/#{filenameWithoutExt}_img#{i}.png" + new_filename = "#{dir}/#{name}.png" + + puts old_filename + puts new_filename + + # move file to modeldirectory (but dont overwrite if user overwrite it) + if File.exist?(old_filename) && !File.exist?(new_filename) + puts "✅ Renaming #{old_filename} -> #{new_filename}" + File.rename(old_filename, new_filename) + else + puts "✅ Not overwriting (useruploaded) #{new_filename}" + end + end + end + + XRForge.log(" ", logfile) + +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 + diff --git a/manyfold/root/hook.d/experience_updated/1050-compile-textures.rb b/manyfold/root/hook.d/experience_updated/1050-compile-textures.rb new file mode 100755 index 0000000..80abea5 --- /dev/null +++ b/manyfold/root/hook.d/experience_updated/1050-compile-textures.rb @@ -0,0 +1,80 @@ +#!/usr/bin/env ruby + +require 'json' +require_relative './../../xrforge.rb' + +# Check if a filename is provided +if ARGV.length != 1 + puts "Usage: #{$0} " + exit 1 +end + +filename = ARGV[0] + +require 'base64' +require 'json' + +begin + + # Change the directory + dir = File.dirname(filename) + Dir.chdir( dir ) + # Read and parse the JSON file + data = JSON.parse( File.read( "datapackage.json" ) ) + logfile = File.join( File.dirname(filename), ".xrforge/log.txt" ) + update = false + + data['resources'].each do |resource| + ext = File.extname(resource['path']) + filenameWithoutExt = File.basename(resource['path'], ext) + if ! XRForge::MODEL_EXT.any?( ext ) + next # skip unknown 3d files + end + if ! resource['path'].match(/^[a-zA-Z0-9]/) + next # skip filenames like '_generated.glb' e.g. (produced by hooks) + end + + XRForge.log("✅ compiling textures", logfile) + gltf_path = ".xrforge/#{filenameWithoutExt}.gltf" + + # Read and parse the GLTF JSON + gltf = JSON.parse(File.read(gltf_path)) + + # Ensure images section exists + unless gltf['images'] && gltf['images'].is_a?(Array) + XRForge.log("✅ No 'images' array found in #{gltf_path}",logfile) + next + end + + # Iterate through the images array + gltf['images'].each_with_index do |img, i| + name = img['name'] + next unless name && !name.empty? + + new_filename = "#{dir}/#{name}.png" + + # move file to modeldirectory (but dont overwrite if user overwrite it) + XRForge.log("🤔 checking #{new_filename}",logfile) + if File.exist?(new_filename) + XRForge.log("✅ importing #{new_filename} -> #{resource['path']}",logfile) + img['uri'] = "#{name}.png" + update = true + end + end + if update + File.write( gltf_path, JSON.pretty_generate(gltf) ) + XRForge.log("✅ writing #{resource['path']}",logfile) + system("assimp export #{gltf_path} #{resource['path']} --embed-textures") + end + end + + XRForge.log(" ", logfile) + +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 + diff --git a/manyfold/root/hook.d/experience_updated/250-to-textures.rb b/manyfold/root/hook.d/experience_updated/250-to-textures.rb deleted file mode 100755 index 7dd3c6e..0000000 --- a/manyfold/root/hook.d/experience_updated/250-to-textures.rb +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env ruby - -require 'json' -require_relative './../../xrforge.rb' - -# Check if a filename is provided -if ARGV.length != 1 - puts "Usage: #{$0} " - exit 1 -end - -puts "TODO" -exit 0 - -filename = ARGV[0] - -require 'base64' -require 'json' - -# Updates the 'uri' of an image in a GLTF hash when a matching PNG filename is found. -# -# gltf: a parsed JSON hash from a .gltf file -# png_path: path to the PNG file to embed -# -# returns: true if updated successfully, false if not found -def update_gltf_image(gltf, png_path) - # Get base name (without extension) - name = File.basename(png_path, '.png') - - # Find image entry with the same name - image_entry = gltf['images']&.find { |img| img['name'] == name } - - unless image_entry - warn "No image named '#{name}' found in GLTF" - return false - end - - # Read and base64-encode the PNG file - data = File.binread(png_path) - encoded = Base64.strict_encode64(data) - - # Update the URI field with the base64-encoded PNG data URI - image_entry['uri'] = "data:image/png;base64,#{encoded}" - - puts "Updated image '#{name}' in GLTF" - true -end - -begin - - # Change the directory - dir = File.dirname(filename) - Dir.chdir( File.dirname(filename) ) - # Read and parse the JSON file - data = JSON.parse( File.read( "datapackage.json" ) ) - - ext = File.extname(filename) - filenameWithoutExt = File.basename(filename, ext) - - if ! XRForge::MODEL_EXT.any?( ext ) - exit(0) # not a 3d file - end - - logfile = File.join( File.dirname(filename), ".xrforge/log.txt" ) - XRForge.log("✅ unpacking textures", logfile) - gltf_path = ".xrforge/#{filenameWithoutExt}.gltf" - system("assimp export #{filename} #{gltf_path}") - system("assimp extract #{filename} | sed 's|/.*/||g'") - - # Read and parse the GLTF JSON - gltf = JSON.parse(File.read(gltf_path)) - - # Ensure images section exists - unless gltf['images'] && gltf['images'].is_a?(Array) - abort("No 'images' array found in #{gltf_path}") - end - - # Iterate through the images array - gltf['images'].each_with_index do |img, i| - name = img['name'] - next unless name && !name.empty? - - old_filename = "website_img#{i}.png" - new_filename = "#{name}.png" - - if File.exist?(old_filename) - XRForge.log("✅ Renaming #{old_filename} -> #{new_filename}", logfile) - File.rename(old_filename, new_filename) - end - end - - XRForge.log(" ", logfile) - -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 - diff --git a/manyfold/root/hook.d/experience_updated/300-package_xrf.rb b/manyfold/root/hook.d/experience_updated/300-package_xrf.rb index eee41b9..f8438c1 100755 --- a/manyfold/root/hook.d/experience_updated/300-package_xrf.rb +++ b/manyfold/root/hook.d/experience_updated/300-package_xrf.rb @@ -49,10 +49,12 @@ begin if model_file XRForge.log("✅ Final model file: '#{model_file}'", logfile) # update datapackage + data['main'] = model_file if ! data['keywords'].include?('xrfragments') data['keywords'].push('xrfragments') - File.write("datapackage.json", JSON.pretty_generate(data) ) end + File.write("datapackage.json", JSON.pretty_generate(data) ) + system("assimp export #{model_file} .xrforge/scene.gltf") else XRForge.log("❌ No suitable 3D file found for XR Fragments-compatible experience", logfile) # update datapackage diff --git a/manyfold/root/hook.d/experience_updated/500-mastodon-post.rb b/manyfold/root/hook.d/experience_updated/500-mastodon-post.rb index 5990376..ebe968c 100755 --- a/manyfold/root/hook.d/experience_updated/500-mastodon-post.rb +++ b/manyfold/root/hook.d/experience_updated/500-mastodon-post.rb @@ -67,8 +67,8 @@ begin data = JSON.parse( File.read( "datapackage.json" ) ) logfile = File.join( File.dirname(filename), ".xrforge/log.txt" ) - data['keywords'].any? do |tag| - if tag.match?(/@.*@.*\./) # scan for activitypub handle (@foo@mastodon.online e.g.) + data['keywords'].each do |tag| + if tag.match?(/^@.*@.*\./) # scan for activitypub handle (@foo@mastodon.online e.g.) generate(tag,filename,dir,data,logfile) end end diff --git a/manyfold/root/templates/mastodon-post/mastodon-post.sh b/manyfold/root/templates/mastodon-post/mastodon-post.sh index 4605ad9..4768e1d 100755 --- a/manyfold/root/templates/mastodon-post/mastodon-post.sh +++ b/manyfold/root/templates/mastodon-post/mastodon-post.sh @@ -3,17 +3,22 @@ test -n "$5" || { echo "usage: ./mastodon-post.sh <link> <handle> out="$5" tmpdir=/tmp/.mastodon-post +outdir="$(dirname "$out")" mydir="$(dirname $(readlink -f $0))" +bgfile="$outdir"/mastodon-post-bg.png cd $mydir +set -x # create tmp workspace test -d $tmpdir && rm -rf $tmpdir mkdir $tmpdir cp * $tmpdir/. +# use template PNG from modeldir +test -f "$bgfile" || cp $tmpdir/mastodon-post-bg.png "$bgfile" +cp "$bgfile" $tmpdir/. rm $tmpdir/mastodon-post.png # IMPORTANT: prevent newer/older imagemagick -clobber (non)existence -set -x -magick $tmpdir/mastodon-post-bg.png \ +magick "$bgfile" \ \( -size 580x -background none -pointsize 32 -interline-spacing 10 -fill \#FFF -font Montserrat-SemiBold.ttf "caption:$1" \) \ -gravity center -composite \ -pointsize 20 \