Update .gitignore to include log files and database journal files. Modify go.mod to update dependencies for go-sqlite3 and cloud.google.com/go/compute/metadata. Enhance Makefile to include logging options for manager and runner commands. Introduce new job token handling in auth package and implement database migration scripts. Refactor manager and runner components to improve job processing and metadata extraction. Add support for video preview in frontend components and enhance WebSocket management for channel subscriptions.

This commit is contained in:
2026-01-02 13:55:19 -06:00
parent edc8ea160c
commit 94490237fe
44 changed files with 9463 additions and 7875 deletions

View File

@@ -339,12 +339,8 @@ object_count = len(scene.objects)
material_count = len(bpy.data.materials)
# Extract Blender version info
# bpy.app.version gives the current running Blender version
# For the file's saved version, we check bpy.data.version (version the file was saved with)
blender_version = {
"current": bpy.app.version_string, # Version of Blender running this script
"file_saved_with": ".".join(map(str, bpy.data.version)) if hasattr(bpy.data, 'version') else None, # Version file was saved with
}
# bpy.data.version gives the version the file was saved with
blender_version = ".".join(map(str, bpy.data.version)) if hasattr(bpy.data, 'version') else bpy.app.version_string
# Build metadata dictionary
metadata = {

View File

@@ -12,6 +12,52 @@ try:
except Exception as e:
print(f"Warning: Could not make paths relative: {e}")
# Auto-enable addons from blender_addons folder in context
# Supports .zip files (installed via Blender API) and already-extracted addons
blend_dir = os.path.dirname(bpy.data.filepath) if bpy.data.filepath else os.getcwd()
addons_dir = os.path.join(blend_dir, "blender_addons")
if os.path.isdir(addons_dir):
print(f"Found blender_addons folder: {addons_dir}")
for item in os.listdir(addons_dir):
item_path = os.path.join(addons_dir, item)
try:
if item.endswith('.zip'):
# Install and enable zip addon using Blender's API
bpy.ops.preferences.addon_install(filepath=item_path)
# Get module name from zip (usually the folder name inside)
import zipfile
with zipfile.ZipFile(item_path, 'r') as zf:
# Find the top-level module name
names = zf.namelist()
if names:
module_name = names[0].split('/')[0]
if module_name.endswith('.py'):
module_name = module_name[:-3]
bpy.ops.preferences.addon_enable(module=module_name)
print(f" Installed and enabled addon: {module_name}")
elif item.endswith('.py') and not item.startswith('__'):
# Single-file addon
bpy.ops.preferences.addon_install(filepath=item_path)
module_name = item[:-3]
bpy.ops.preferences.addon_enable(module=module_name)
print(f" Installed and enabled addon: {module_name}")
elif os.path.isdir(item_path) and os.path.exists(os.path.join(item_path, '__init__.py')):
# Multi-file addon directory - add to path and enable
if addons_dir not in sys.path:
sys.path.insert(0, addons_dir)
bpy.ops.preferences.addon_enable(module=item)
print(f" Enabled addon: {item}")
except Exception as e:
print(f" Error with addon {item}: {e}")
else:
print(f"No blender_addons folder found at: {addons_dir}")
{{UNHIDE_CODE}}
# Read output format from file (created by Go code)
format_file_path = {{FORMAT_FILE_PATH}}
@@ -53,10 +99,10 @@ print(f"Blend file output format: {current_output_format}")
if output_format_override:
print(f"Overriding output format from '{current_output_format}' to '{output_format_override}'")
# Map common format names to Blender's format constants
# For video formats (EXR_264_MP4, EXR_AV1_MP4), we render as EXR frames first
# For video formats, we render as appropriate frame format first
format_to_use = output_format_override.upper()
if format_to_use in ['EXR_264_MP4', 'EXR_AV1_MP4']:
format_to_use = 'EXR' # Render as EXR for video formats
if format_to_use in ['EXR_264_MP4', 'EXR_AV1_MP4', 'EXR_VP9_WEBM']:
format_to_use = 'EXR' # Render as EXR for EXR video formats
format_map = {
'PNG': 'PNG',

View File

@@ -32,22 +32,20 @@ const (
// Job represents a render job
type Job struct {
ID int64 `json:"id"`
UserID int64 `json:"user_id"`
JobType JobType `json:"job_type"` // "render"
Name string `json:"name"`
Status JobStatus `json:"status"`
Progress float64 `json:"progress"` // 0.0 to 100.0
FrameStart *int `json:"frame_start,omitempty"` // Only for render jobs
FrameEnd *int `json:"frame_end,omitempty"` // Only for render jobs
OutputFormat *string `json:"output_format,omitempty"` // Only for render jobs - PNG, JPEG, EXR, etc.
AllowParallelRunners *bool `json:"allow_parallel_runners,omitempty"` // Only for render jobs
TimeoutSeconds int `json:"timeout_seconds"` // Job-level timeout (24 hours default)
BlendMetadata *BlendMetadata `json:"blend_metadata,omitempty"` // Extracted metadata from blend file
CreatedAt time.Time `json:"created_at"`
StartedAt *time.Time `json:"started_at,omitempty"`
CompletedAt *time.Time `json:"completed_at,omitempty"`
ErrorMessage string `json:"error_message,omitempty"`
ID int64 `json:"id"`
UserID int64 `json:"user_id"`
JobType JobType `json:"job_type"` // "render"
Name string `json:"name"`
Status JobStatus `json:"status"`
Progress float64 `json:"progress"` // 0.0 to 100.0
FrameStart *int `json:"frame_start,omitempty"` // Only for render jobs
FrameEnd *int `json:"frame_end,omitempty"` // Only for render jobs
OutputFormat *string `json:"output_format,omitempty"` // Only for render jobs - PNG, JPEG, EXR, etc.
BlendMetadata *BlendMetadata `json:"blend_metadata,omitempty"` // Extracted metadata from blend file
CreatedAt time.Time `json:"created_at"`
StartedAt *time.Time `json:"started_at,omitempty"`
CompletedAt *time.Time `json:"completed_at,omitempty"`
ErrorMessage string `json:"error_message,omitempty"`
}
// RunnerStatus represents the status of a runner
@@ -86,9 +84,8 @@ const (
type TaskType string
const (
TaskTypeRender TaskType = "render"
TaskTypeMetadata TaskType = "metadata"
TaskTypeVideoGeneration TaskType = "video_generation"
TaskTypeRender TaskType = "render"
TaskTypeEncode TaskType = "encode"
)
// Task represents a render task assigned to a runner
@@ -96,8 +93,7 @@ type Task struct {
ID int64 `json:"id"`
JobID int64 `json:"job_id"`
RunnerID *int64 `json:"runner_id,omitempty"`
FrameStart int `json:"frame_start"`
FrameEnd int `json:"frame_end"`
Frame int `json:"frame"`
TaskType TaskType `json:"task_type"`
Status TaskStatus `json:"status"`
CurrentStep string `json:"current_step,omitempty"`
@@ -132,16 +128,18 @@ type JobFile struct {
// CreateJobRequest represents a request to create a new job
type CreateJobRequest struct {
JobType JobType `json:"job_type"` // "render"
Name string `json:"name"`
FrameStart *int `json:"frame_start,omitempty"` // Required for render jobs
FrameEnd *int `json:"frame_end,omitempty"` // Required for render jobs
OutputFormat *string `json:"output_format,omitempty"` // Required for render jobs
AllowParallelRunners *bool `json:"allow_parallel_runners,omitempty"` // Optional for render jobs, defaults to true
RenderSettings *RenderSettings `json:"render_settings,omitempty"` // Optional: Override blend file render settings
UploadSessionID *string `json:"upload_session_id,omitempty"` // Optional: Session ID from file upload
UnhideObjects *bool `json:"unhide_objects,omitempty"` // Optional: Enable unhide tweaks for objects/collections
EnableExecution *bool `json:"enable_execution,omitempty"` // Optional: Enable auto-execution in Blender (adds --enable-autoexec flag, defaults to false)
JobType JobType `json:"job_type"` // "render"
Name string `json:"name"`
FrameStart *int `json:"frame_start,omitempty"` // Required for render jobs
FrameEnd *int `json:"frame_end,omitempty"` // Required for render jobs
OutputFormat *string `json:"output_format,omitempty"` // Required for render jobs
RenderSettings *RenderSettings `json:"render_settings,omitempty"` // Optional: Override blend file render settings
UploadSessionID *string `json:"upload_session_id,omitempty"` // Optional: Session ID from file upload
UnhideObjects *bool `json:"unhide_objects,omitempty"` // Optional: Enable unhide tweaks for objects/collections
EnableExecution *bool `json:"enable_execution,omitempty"` // Optional: Enable auto-execution in Blender (adds --enable-autoexec flag, defaults to false)
BlenderVersion *string `json:"blender_version,omitempty"` // Optional: Override Blender version (e.g., "4.2" or "4.2.3")
PreserveHDR *bool `json:"preserve_hdr,omitempty"` // Optional: Preserve HDR range for EXR encoding (uses HLG with bt709 primaries)
PreserveAlpha *bool `json:"preserve_alpha,omitempty"` // Optional: Preserve alpha channel for EXR encoding (requires AV1 or VP9 codec)
}
// UpdateJobProgressRequest represents a request to update job progress
@@ -227,23 +225,26 @@ type TaskLogEntry struct {
// BlendMetadata represents extracted metadata from a blend file
type BlendMetadata struct {
FrameStart int `json:"frame_start"`
FrameEnd int `json:"frame_end"`
HasNegativeFrames bool `json:"has_negative_frames"` // True if blend file has negative frame numbers (not supported)
RenderSettings RenderSettings `json:"render_settings"`
SceneInfo SceneInfo `json:"scene_info"`
FrameStart int `json:"frame_start"`
FrameEnd int `json:"frame_end"`
HasNegativeFrames bool `json:"has_negative_frames"` // True if blend file has negative frame numbers (not supported)
RenderSettings RenderSettings `json:"render_settings"`
SceneInfo SceneInfo `json:"scene_info"`
MissingFilesInfo *MissingFilesInfo `json:"missing_files_info,omitempty"`
UnhideObjects *bool `json:"unhide_objects,omitempty"` // Enable unhide tweaks for objects/collections
EnableExecution *bool `json:"enable_execution,omitempty"` // Enable auto-execution in Blender (adds --enable-autoexec flag, defaults to false)
UnhideObjects *bool `json:"unhide_objects,omitempty"` // Enable unhide tweaks for objects/collections
EnableExecution *bool `json:"enable_execution,omitempty"` // Enable auto-execution in Blender (adds --enable-autoexec flag, defaults to false)
BlenderVersion string `json:"blender_version,omitempty"` // Detected or overridden Blender version (e.g., "4.2" or "4.2.3")
PreserveHDR *bool `json:"preserve_hdr,omitempty"` // Preserve HDR range for EXR encoding (uses HLG with bt709 primaries)
PreserveAlpha *bool `json:"preserve_alpha,omitempty"` // Preserve alpha channel for EXR encoding (requires AV1 or VP9 codec)
}
// MissingFilesInfo represents information about missing files/addons
type MissingFilesInfo struct {
Checked bool `json:"checked"`
HasMissing bool `json:"has_missing"`
MissingFiles []string `json:"missing_files,omitempty"`
Checked bool `json:"checked"`
HasMissing bool `json:"has_missing"`
MissingFiles []string `json:"missing_files,omitempty"`
MissingAddons []string `json:"missing_addons,omitempty"`
Error string `json:"error,omitempty"`
Error string `json:"error,omitempty"`
}
// RenderSettings represents render settings from a blend file