vse_toolbox/operators/operators.py

1419 lines
47 KiB
Python
Raw Normal View History

2023-03-14 13:38:04 +01:00
# SPDX-License-Identifier: GPL-2.0-or-later
import importlib
2023-03-21 18:33:29 +01:00
import json
2023-03-14 13:38:04 +01:00
import re
2023-04-20 00:12:39 +02:00
import time
2023-04-21 21:44:05 +02:00
from pprint import pprint
import csv
from datetime import datetime
import os
2023-04-24 18:51:26 +02:00
from pathlib import Path
2023-04-21 21:44:05 +02:00
2023-04-24 18:51:26 +02:00
import bpy
from bpy.types import (Operator, Menu)
from bpy_extras.io_utils import ImportHelper
from bpy.props import (CollectionProperty, BoolProperty, EnumProperty,
IntProperty, StringProperty)
from bpy.types import PropertyGroup
from bl_operators.presets import AddPresetBase
2023-04-21 21:44:05 +02:00
2023-03-14 13:38:04 +01:00
import vse_toolbox
2023-04-24 18:51:26 +02:00
from vse_toolbox.constants import (ASSET_PREVIEWS, CASTING_BUFFER, CONFIG_DIR,
EDITS, EDIT_SUFFIXES, MOVIES, MOVIE_SUFFIXES, PREVIEWS_DIR, SOUNDS,
SOUND_SUFFIXES, TASK_ITEMS)
2023-04-20 00:12:39 +02:00
2023-04-24 18:51:26 +02:00
from vse_toolbox.sequencer_utils import (clean_sequencer, get_strips, set_active_strip,
import_edit, import_movie, import_sound, rename_strips, render_strips, set_channels,
get_channel_index, new_text_strip, get_strip_render_path, get_strip_sequence_name)
from vse_toolbox.bl_utils import (get_addon_prefs, get_scene_settings, get_strip_settings)
2023-04-25 11:39:06 +02:00
from vse_toolbox.file_utils import (install_module, norm_name, norm_str, open_file, read_file)
2023-03-14 13:38:04 +01:00
2023-04-14 18:55:00 +02:00
2023-03-24 11:42:17 +01:00
class VSETB_OT_tracker_connect(Operator):
bl_idname = "vse_toolbox.tracker_connect"
bl_label = "Connect to Tracker"
bl_description = "Connect to Tracker"
@classmethod
def poll(cls, context):
prefs = get_addon_prefs()
if prefs.tracker:
return True
def execute(self, context):
prefs = get_addon_prefs()
settings = get_scene_settings()
try:
prefs.tracker.connect()
self.report({'INFO'}, f'Sucessfully login to {settings.tracker_name.title()}')
return {"FINISHED"}
except Exception as e:
print('e: ', e)
self.report({'ERROR'}, f'Cannot connect to tracker.')
return {"CANCELLED"}
2023-04-25 18:43:04 +02:00
class VSETB_OT_copy_metadata(Operator):
bl_idname = "vse_toolbox.copy_metadata"
bl_label = "Copy metadata to selected"
bl_description = "Copy Metadata to selected strips"
metadata : StringProperty()
@classmethod
def poll(cls, context):
return context.selected_sequences and context.active_sequence_strip
def execute(self, context):
prefs = get_addon_prefs()
settings = get_scene_settings()
metadata = self.metadata.lower()
active_strip = context.active_sequence_strip
metadata_value = getattr(active_strip.vsetb_strip_settings.metadata, metadata)
for strip in context.selected_sequences:
if strip == context.active_sequence_strip:
continue
setattr(strip.vsetb_strip_settings.metadata, metadata, metadata_value)
return {"FINISHED"}
2023-04-21 21:44:05 +02:00
class VSETB_OT_export_spreadsheet(Operator):
bl_idname = "vse_toolbox.export_spreadsheet"
bl_label = "Export Spreadsheet"
bl_description = "Export Shot data in a table as a csv or an xlsl"
2023-03-14 13:38:04 +01:00
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
2023-04-21 21:44:05 +02:00
settings = get_scene_settings()
return settings.active_project
def invoke(self, context, event):
settings = get_scene_settings()
project = settings.active_project
return context.window_manager.invoke_props_dialog(self)
def draw(self, context):
scn = context.scene
settings = get_scene_settings()
project = settings.active_project
2023-04-22 21:12:21 +02:00
options = project.spreadsheet_options
2023-04-21 21:44:05 +02:00
layout = self.layout
row = layout.row()
row.template_list("VSETB_UL_spreadsheet", "spreadsheet", project, "spreadsheet", project, "spreadsheet_index", rows=8)
col_tool = row.column(align=True)
2023-04-24 18:51:26 +02:00
#bpy.types.VSETB_PT_presets.draw_panel_header(col_tool)
#col_tool.operator('wm.call_menu', icon="PRESET").name = 'VSETB_MT_spreadsheet_presets'
#col_tool.operator('vse_toolbox.load_spreadsheet_preset', icon='PRESET', text="")
op = col_tool.operator('wm.call_panel', icon="PRESET", emboss=False, text='')
op.name = 'VSETB_PT_presets'
op.keep_open = False
col_tool.separator()
2023-04-21 21:44:05 +02:00
col_tool.operator('vse_toolbox.spreadsheet_move', icon='TRIA_UP', text="").direction = 'UP'
col_tool.operator('vse_toolbox.spreadsheet_move', icon='TRIA_DOWN', text="").direction = 'DOWN'
col = layout.column()
col.use_property_split = True
2023-04-22 15:42:38 +02:00
row = col.row(align=True, heading='Custom Name')
#row.use_property_split = True
2023-04-22 21:12:21 +02:00
row.prop(options, 'use_custom_name', text='')
2023-04-22 15:42:38 +02:00
sub = row.row(align=True)
2023-04-22 21:12:21 +02:00
sub.enabled = options.use_custom_name
sub.prop(options, 'custom_name', text='')
2023-04-22 15:42:38 +02:00
col.separator()
row = col.row(align=False)
2023-04-22 21:12:21 +02:00
row.prop(options, "format", expand=True, text='Format')
row.prop(options, 'show_settings', text='', icon='PREFERENCES')
if options.show_settings:
col.prop(options, "separator", expand=True, text='Separator')
if options.format == 'CSV':
col.prop(options, "delimiter", expand=True, text='Delimiter')
2023-04-21 21:44:05 +02:00
2023-04-22 15:42:38 +02:00
col.separator()
2023-04-22 21:12:21 +02:00
col.prop(options, 'open_folder', text='Open Folder')
col.prop(options, 'export_path', text='Export Path')
2023-03-14 13:38:04 +01:00
def execute(self, context):
2023-04-21 21:44:05 +02:00
#self.report({'ERROR'}, f'Export not implemented yet.')
prefs = get_addon_prefs()
settings = get_scene_settings()
project = settings.active_project
2023-04-22 21:12:21 +02:00
options = project.spreadsheet_options
2023-04-21 21:44:05 +02:00
episode = settings.active_episode
cells = [cell for cell in project.spreadsheet if cell.enabled]
rows = []
# Header
rows.append([cell.export_name for cell in cells])
2023-04-22 21:12:21 +02:00
separator = options.separator.replace('\\n', '\n').replace('\\t', '\t').replace('\\r', '\r')
delimiter = options.delimiter.replace('\\n', '\n').replace('\\t', '\t').replace('\\r', '\r')
2023-04-22 15:42:38 +02:00
2023-04-21 21:44:05 +02:00
for strip in get_strips('Shots'):
row = []
for cell in cells:
2023-04-22 15:42:38 +02:00
if cell.type == "METADATA":
2023-04-21 21:44:05 +02:00
row += [getattr(strip.vsetb_strip_settings.metadata, cell.field_name)]
2023-04-22 15:42:38 +02:00
elif cell.type == "ASSET_TYPE":
asset_castings = []
for asset_casting in strip.vsetb_strip_settings.casting:
asset = asset_casting.asset
if not asset.asset_type == cell.name:
continue
2023-04-22 21:12:21 +02:00
if options.use_custom_name:
if asset.get('metadata', {}).get(options.custom_name):
asset_castings.append(asset['metadata'][options.custom_name])
2023-04-22 15:42:38 +02:00
else:
2023-04-22 21:12:21 +02:00
self.report({'ERROR'}, f'The asset {asset.tracker_name} has no data {options.custom_name}')
2023-04-22 15:42:38 +02:00
else:
asset_castings.append(asset.tracker_name)
row += [separator.join(asset_castings)]
2023-04-21 21:44:05 +02:00
elif cell.field_name == 'EPISODE':
row += [settings.active_episode.name]
elif cell.field_name == 'SEQUENCE':
row += [get_strip_sequence_name(strip)]
elif cell.field_name == 'SHOT':
row += [strip.name]
elif cell.field_name == 'DESCRIPTION':
row += [strip.vsetb_strip_settings.description]
elif cell.field_name == 'FRAMES':
row += [strip.frame_final_duration]
rows.append(row)
#print(rows)
2023-04-22 21:12:21 +02:00
export_path = Path(os.path.abspath(bpy.path.abspath(options.export_path)))
2023-04-21 21:44:05 +02:00
export_name = export_path.name
if export_path.suffix or export_name.endswith('{ext}'):
export_path = export_path.parent
else: # It's a directory
if project.type == 'TVSHOW':
export_name = '{date}_{project}_{episode}_{tracker}_shots.{ext}'
else:
export_name = '{date}_{project}_{tracker}_shots.{ext}'
date = datetime.now().strftime('%Y_%m_%d')
project_name = project.name.replace(' ', '_').lower()
episode_name = episode.name.replace(' ', '_').lower() if episode else 'episode'
2023-04-22 21:12:21 +02:00
ext = options.format.lower()
2023-04-21 21:44:05 +02:00
export_name = export_name.format(date=date, project=project_name,
episode=episode_name, tracker=settings.tracker_name.lower(), ext=ext)
export_path = export_path / export_name
#2023_04_11_kitsu_boris_ep01_shots
export_path.parent.mkdir(parents=True, exist_ok=True)
2023-03-14 13:38:04 +01:00
2023-04-22 21:12:21 +02:00
if options.format == 'CSV':
2023-04-22 15:42:38 +02:00
print('Writing .csv file to', export_path)
with open(str(export_path), 'w', newline='\n', encoding='utf-8') as f:
2023-04-22 21:12:21 +02:00
writer = csv.writer(f, delimiter=options.delimiter)
2023-04-22 15:42:38 +02:00
for row in rows:
writer.writerow(row)
2023-04-22 21:12:21 +02:00
elif options.format == 'XLSX':
2023-04-22 15:42:38 +02:00
try:
import openpyxl
2023-04-24 18:51:26 +02:00
except ModuleNotFoundError:
2023-04-22 15:42:38 +02:00
self.report({'INFO'}, 'Installing openpyxl')
openpyxl = install_module('openpyxl')
from openpyxl import Workbook
workbook = Workbook()
worksheet = workbook.active
2023-04-21 21:44:05 +02:00
for row in rows:
2023-04-22 15:42:38 +02:00
worksheet.append(row)
2023-04-21 21:44:05 +02:00
2023-04-22 15:42:38 +02:00
for col in worksheet.columns:
letter = col[0].column_letter
worksheet.column_dimensions[letter].auto_size = True
# Save the file
workbook.save(str(export_path))
2023-04-22 21:12:21 +02:00
if options.open_folder:
2023-04-22 15:42:38 +02:00
open_file(export_path, select=True)
2023-04-21 21:44:05 +02:00
return {"FINISHED"}
2023-03-14 13:38:04 +01:00
2023-04-20 00:12:39 +02:00
def get_task_status_items(self, context):
settings = get_scene_settings()
project = settings.active_project
status_items = [('CURRENT', 'Current', '')]
2023-04-20 18:16:34 +02:00
if project:
status_items += [(t.name, t.name, '') for t in project.task_statuses]
2023-04-20 00:12:39 +02:00
return status_items
def get_task_type_items(self, context):
settings = get_scene_settings()
project = settings.active_project
2023-04-20 18:16:34 +02:00
if not project:
return [('NONE', 'None', '')]
2023-04-20 00:12:39 +02:00
return [(t.name, t.name, '') for t in project.task_types]
class VSETB_OT_upload_to_tracker(Operator):
bl_idname = "vse_toolbox.upload_to_tracker"
bl_label = "Upload to tracker"
bl_description = "Upload selected strip to tracker"
bl_options = {"REGISTER", "UNDO"}
2023-04-21 21:44:05 +02:00
task : EnumProperty(items=get_task_type_items)
status : EnumProperty(items=get_task_status_items)
2023-04-20 00:12:39 +02:00
comment : StringProperty()
2023-04-21 21:44:05 +02:00
add_preview : BoolProperty(default=True)
2023-04-22 15:42:38 +02:00
preview_mode : EnumProperty(items=[(m, m.title().replace('_', ' '), '')
for m in ('ONLY_NEW', 'REPLACE', 'ADD')])
2023-04-21 21:44:05 +02:00
set_main_preview : BoolProperty(default=True)
2023-04-20 00:12:39 +02:00
casting : BoolProperty(default=True)
custom_data : BoolProperty(default=True)
@classmethod
def poll(cls, context):
return True
def invoke(self, context, event):
prefs = get_addon_prefs()
settings = get_scene_settings()
project = settings.active_project
tracker = prefs.tracker
tracker.connect()
#self.bl_label = f"Upload to {settings.tracker_name.title()}"
return context.window_manager.invoke_props_dialog(self)
def draw(self, context):
scn = context.scene
settings = get_scene_settings()
layout = self.layout
col = layout.column()
col.use_property_split = True
col.prop(self, 'task', text='Task')
col.prop(self, 'status', text='Status')
col.prop(self, 'comment', text='Comment')
row = col.row(heading='Add Preview')
row.prop(self, 'add_preview', text='')
row.prop(self, 'preview_mode', text='')
col.separator()
col.prop(self, 'casting', text='Casting')
col.prop(self, 'custom_data', text='Custom Data')
def execute(self, context):
#self.report({'ERROR'}, f'Export not implemented yet.')
prefs = get_addon_prefs()
settings = get_scene_settings()
2023-04-20 18:16:34 +02:00
project = settings.active_project
2023-04-24 18:51:26 +02:00
episode = None
if settings.active_episode:
episode = settings.active_episode.id
2023-04-20 00:12:39 +02:00
tracker = prefs.tracker
status = self.status
if status == 'CURRENT':
status = None
for strip in get_strips(channel='Shots', selected_only=True):
sequence_name = get_strip_sequence_name(strip)
shot_name = strip.name
2023-04-24 18:51:26 +02:00
sequence = tracker.get_sequence(sequence_name, episode=episode)
2023-04-20 18:16:34 +02:00
metadata = strip.vsetb_strip_settings.metadata.to_dict()
2023-04-21 21:44:05 +02:00
#print(metadata)
2023-04-20 18:16:34 +02:00
2023-04-20 00:12:39 +02:00
if not sequence:
self.report({"INFO"}, f'Create sequence {sequence_name} in Kitsu')
2023-04-24 18:51:26 +02:00
sequence = tracker.new_sequence(sequence_name, episode=episode)
2023-04-20 00:12:39 +02:00
shot = tracker.get_shot(shot_name, sequence=sequence)
if not shot:
self.report({"INFO"}, f'Create shot {shot_name} in Kitsu')
shot = tracker.new_shot(shot_name, sequence=sequence)
task = tracker.get_task(self.task, entity=shot)
2023-04-20 18:16:34 +02:00
if not task:
task = tracker.new_task(shot, task_type=self.task)
# print('\n', 'task comment')
# print(task['last_comment'])
preview = None
if self.add_preview:
preview = Path(get_strip_render_path(strip, project.render_template))
2023-04-21 21:44:05 +02:00
#print(preview)
2023-04-20 18:16:34 +02:00
if not preview.exists():
2023-04-24 18:51:26 +02:00
print(f'The preview {preview} not exists')
2023-04-20 18:16:34 +02:00
preview = None
2023-04-21 21:44:05 +02:00
elif task.get('last_comment') and task['last_comment']['previews']:
2023-04-20 18:16:34 +02:00
if self.preview_mode == 'REPLACE':
tracker.remove_comment(task['last_comment'])
elif self.preview_mode == 'ONLY_NEW':
preview = None
2023-04-20 00:12:39 +02:00
2023-04-21 21:44:05 +02:00
#print(f'{preview=}')
#print(f'{status=}')
if status or preview:
tracker.new_comment(task, comment=self.comment, status=status, preview=preview, set_main_preview=self.set_main_preview)
2023-04-20 18:16:34 +02:00
if self.custom_data:
2023-04-21 21:44:05 +02:00
metadata = strip.vsetb_strip_settings.metadata.to_dict()
description = strip.vsetb_strip_settings.description
tracker.update_data(shot, metadata, frames=strip.frame_final_duration, description=description)
if self.casting:
casting = [{'asset_id': a.id, 'nb_occurences': a.instance} for a in strip.vsetb_strip_settings.casting]
tracker.update_casting(shot, casting)
2023-04-20 00:12:39 +02:00
return {"FINISHED"}
2023-03-16 18:32:17 +01:00
class VSETB_OT_auto_select_files(Operator):
bl_idname = "import.auto_select_files"
bl_label = "Auto Select"
bl_description = "Auto Select Files"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return True
def get_items(self, items=[]):
if not items:
return [('NONE', 'None', '', 0)]
return [(e, e, '', i) for i, e in enumerate(sorted(items))]
def execute(self, context):
params = context.space_data.params
directory = Path(params.directory.decode())
EDITS.clear()
MOVIES.clear()
SOUNDS.clear()
edits = []
movies = []
sounds = []
for file_entry in directory.glob('*'):
if file_entry.is_dir():
continue
if file_entry.suffix in EDIT_SUFFIXES:
edits.append(file_entry.name)
elif file_entry.suffix in MOVIE_SUFFIXES:
movies.append(file_entry.name)
elif file_entry.suffix in SOUND_SUFFIXES:
sounds.append(file_entry.name)
EDITS.extend(self.get_items(items=edits))
MOVIES.extend(self.get_items(items=movies))
SOUNDS.extend(self.get_items(items=sounds))
return {'FINISHED'}
2023-03-17 22:55:06 +01:00
class VSETB_OT_import_files(Operator):
2023-04-14 18:55:00 +02:00
bl_idname = "vse_toolbox.import_files"
2023-03-16 18:32:17 +01:00
bl_label = "Import"
bl_description = "Import Edit"
2023-03-14 13:38:04 +01:00
bl_options = {"REGISTER", "UNDO"}
directory : StringProperty(subtype='DIR_PATH')
filepath: StringProperty(
name="File Path",
description="Filepath used for importing the file",
maxlen=1024,
subtype='FILE_PATH',
)
files : CollectionProperty(type=bpy.types.OperatorFileListElement)
2023-03-16 18:32:17 +01:00
clean_sequencer : BoolProperty(
name="Clean Sequencer",
default=False,
description="Clean all existing strips in sequencer",
2023-03-14 13:38:04 +01:00
)
2023-03-16 18:32:17 +01:00
import_edit : BoolProperty(name='', default=True)
edit: EnumProperty(name='', items=lambda s, c: EDITS)
import_movie : BoolProperty(name='', default=False)
movie: EnumProperty(name='', items=lambda s, c: MOVIES)
import_sound : BoolProperty(name='', default=False)
sound: EnumProperty(name='', items=lambda s, c: SOUNDS)
2023-03-14 13:38:04 +01:00
@classmethod
def poll(cls, context):
return True
2023-03-16 18:32:17 +01:00
def draw(self, context):
scn = context.scene
2023-03-21 18:33:29 +01:00
settings = get_scene_settings()
2023-03-16 18:32:17 +01:00
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
col = layout.column(align=True)
col.operator('import.auto_select_files', text='Auto Select')
row = self.layout.row(heading="Import Edit", align=True)
row.prop(self, 'import_edit')
2023-03-17 22:55:06 +01:00
sub = row.row(align=True)
2023-03-16 18:32:17 +01:00
sub.active = self.import_edit
sub.prop(self, 'edit')
row = self.layout.row(heading="Import Movie", align=True)
row.prop(self, 'import_movie')
sub = row.row()
sub.active = self.import_movie
sub.prop(self, 'movie')
row = self.layout.row(heading="Import Sound", align=True)
row.prop(self, 'import_sound')
sub = row.row()
sub.active = self.import_sound
sub.prop(self, 'sound')
col = layout.column()
col.separator()
col.prop(self, 'clean_sequencer')
2023-03-14 13:38:04 +01:00
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
def execute(self, context):
otio = install_module('opentimelineio')
2023-03-16 18:32:17 +01:00
edit_filepath = Path(self.directory, self.edit)
if not edit_filepath.exists():
self.import_edit = False
2023-03-14 13:38:04 +01:00
2023-03-16 18:32:17 +01:00
movie_filepath = Path(self.directory, self.movie)
if not movie_filepath.exists():
self.import_movie = False
sound_filepath = Path(self.directory, self.sound)
if not sound_filepath.exists():
self.import_sound = False
if self.clean_sequencer:
clean_sequencer(
edit=self.import_edit,
movie=self.import_movie,
sound=self.import_sound,
)
if self.import_edit:
print(f'[>.] Loading Edit from: {str(edit_filepath)}')
import_edit(edit_filepath, adapter="cmx_3600")
if self.import_movie:
print(f'[>.] Loading Movie from: {str(movie_filepath)}')
import_movie(movie_filepath)
if self.import_sound:
print(f'[>.] Loading Audio from: {str(sound_filepath)}')
import_sound(sound_filepath)
elif not self.import_sound and self.import_movie:
print(f'[>.] Loading Audio from Movie: {str(movie_filepath)}')
import_sound(movie_filepath)
context.scene.sequence_editor.sequences.update()
return {"FINISHED"}
2023-03-14 13:38:04 +01:00
2023-03-17 20:03:38 +01:00
class VSETB_OT_load_assets(Operator):
bl_idname = "vse_toolbox.load_assets"
bl_label = "Load Assets for current projects"
bl_description = "Load Assets"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
2023-03-21 18:33:29 +01:00
settings = get_scene_settings()
2023-03-17 20:03:38 +01:00
if settings.active_project:
return True
def execute(self, context):
2023-03-21 18:33:29 +01:00
settings = get_scene_settings()
2023-03-17 20:03:38 +01:00
prefs = get_addon_prefs()
tracker = prefs.tracker
2023-03-21 18:33:29 +01:00
tracker.connect()
2023-03-17 20:03:38 +01:00
project = settings.active_project
2023-03-21 18:33:29 +01:00
project.assets.clear()
2023-03-17 20:03:38 +01:00
assets = tracker.get_assets(project['id'])
if not assets:
self.report({'ERROR'}, f'No Assets found for {project.name}.')
2023-03-20 19:05:22 +01:00
2023-03-21 18:33:29 +01:00
for asset_data in assets:
2023-03-17 20:03:38 +01:00
asset = project.assets.add()
2023-03-20 19:05:22 +01:00
2023-03-21 18:33:29 +01:00
asset.name = asset_data['id']
2023-03-20 19:05:22 +01:00
asset.norm_name = norm_name(asset_data['name'], separator=' ', format=str.lower)
2023-03-21 18:33:29 +01:00
2023-03-20 19:05:22 +01:00
asset.tracker_name = asset_data['name']
2023-03-17 20:03:38 +01:00
asset.id = asset_data['id']
asset.asset_type = asset_data['asset_type']
2023-03-21 18:33:29 +01:00
2023-04-22 15:42:38 +02:00
#for key, value in asset_data.get('data', {}).items():
asset['metadata'] = asset_data.get('data', {})
2023-03-21 18:33:29 +01:00
2023-03-20 19:05:22 +01:00
preview_id = asset_data.get('preview_file_id')
if preview_id:
asset.preview = preview_id
2023-03-21 18:33:29 +01:00
preview_path = Path(PREVIEWS_DIR / project.id / preview_id).with_suffix('.png')
2023-03-20 19:05:22 +01:00
tracker.download_preview(preview_id, preview_path)
if preview_id not in ASSET_PREVIEWS:
ASSET_PREVIEWS.load(preview_id, preview_path.as_posix(), 'IMAGE', True)
2023-03-20 19:05:22 +01:00
2023-03-17 20:03:38 +01:00
self.report({'INFO'}, f'Assets for {project.name} successfully loaded')
return {"FINISHED"}
2023-03-14 13:38:04 +01:00
class VSETB_OT_load_projects(Operator):
bl_idname = "vse_toolbox.load_projects"
bl_label = "Load Projects"
bl_description = "Load Projects"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return True
def execute(self, context):
2023-03-21 18:33:29 +01:00
settings = get_scene_settings()
2023-03-14 13:38:04 +01:00
prefs = get_addon_prefs()
tracker = prefs.tracker
2023-04-20 18:16:34 +02:00
old_project_name = settings.project_name.replace(' ', '_').upper()
2023-03-14 13:38:04 +01:00
settings.projects.clear()
tracker.connect()
for project_data in tracker.get_projects():
project = settings.projects.add()
2023-04-19 10:37:38 +02:00
project.type = project_data['production_type'].upper().replace(' ', '')
2023-03-14 13:38:04 +01:00
project.name = project_data['name']
project.id = project_data['id']
2023-04-19 10:37:38 +02:00
if project.type == 'TVSHOW':
2023-04-14 18:55:00 +02:00
for episode_data in tracker.get_episodes(project_data):
episode = project.episodes.add()
episode.name = episode_data['name']
episode.id = episode_data['id']
2023-03-17 20:03:38 +01:00
2023-04-22 15:42:38 +02:00
for metadata_data in tracker.get_metadata_types(project_data):
#pprint(metadata_data)
metadata_type = project.metadata_types.add()
2023-04-21 21:44:05 +02:00
metadata_type.name = metadata_data['name']
metadata_type.field_name = metadata_data['field_name']
2023-04-23 13:07:33 +02:00
#metadata_type['choices'] = metadata_data['choices']
2023-04-25 15:30:05 +02:00
if prefs.sort_metadata_items:
metadata_data['choices'].sort()
2023-04-23 13:07:33 +02:00
for choice in metadata_data['choices']:
choice_item = metadata_type.choices.add()
choice_item.name = choice
2023-04-22 15:42:38 +02:00
metadata_type['entity_type'] = metadata_data['entity_type'].upper()
2023-04-20 00:12:39 +02:00
for status_data in tracker.get_task_statuses(project_data):
#print(metadata_data)
task_status = project.task_statuses.add()
task_status.name = status_data['short_name'].upper()
for task_type_data in tracker.get_shot_task_types(project_data):
task_type = project.task_types.add()
task_type.name = task_type_data['name']
2023-04-04 12:21:45 +02:00
for asset_type_data in tracker.get_asset_types(project_data):
2023-04-14 18:55:00 +02:00
asset_type = project.asset_types.add()
asset_type.name = asset_type_data['name']
2023-04-21 21:44:05 +02:00
project.set_spreadsheet()
2023-04-20 18:16:34 +02:00
for project in settings.projects:
if project.name.replace(' ', '_').upper() == old_project_name:
settings.project_name = project.name
2023-04-25 11:39:06 +02:00
load_settings()
2023-04-20 18:16:34 +02:00
#else:
# print('Could Not restore Project Name')
#if settings.active_project:
# settings.active_project.set_strip_metadata()
2023-04-20 18:16:34 +02:00
#bpy.ops.vse_toolbox.load_assets()
2023-04-14 18:55:00 +02:00
2023-04-22 15:42:38 +02:00
self.report({"INFO"}, 'Successfully Load Tracker Projects')
2023-03-16 18:32:17 +01:00
return {'FINISHED'}
2023-03-14 13:38:04 +01:00
class VSETB_OT_new_episode(Operator):
bl_idname = "vse_toolbox.new_episode"
bl_label = "New Epispde"
bl_description = "Add new Episode to Project"
bl_options = {"REGISTER", "UNDO"}
episode_name : StringProperty(name="Episode Name", default="")
@classmethod
def poll(cls, context):
return True
def invoke(self, context, event):
scn = context.scene
2023-03-21 18:33:29 +01:00
settings = get_scene_settings()
2023-03-14 13:38:04 +01:00
return context.window_manager.invoke_props_dialog(self)
def execute(self, context):
2023-03-21 18:33:29 +01:00
settings = get_scene_settings()
2023-03-14 13:38:04 +01:00
prefs = get_addon_prefs()
tracker = prefs.tracker
episode_name = settings.episode_template.format(index=int(self.episode_name))
2023-04-21 21:44:05 +02:00
#print(self.episode_name)
#print('episode_name: ', episode_name)
2023-03-14 13:38:04 +01:00
episode = tracker.get_episode(episode_name)
if episode:
self.report({'ERROR'}, f'Episode {episode_name} already exists')
return {"CANCELLED"}
tracker.new_episode(episode_name)
# tracker.get_episodes
tracker.update_project()
self.report({'INFO'}, f'Episode {episode_name} successfully created')
return {'FINISHED'}
class VSETB_OT_reload_addon(Operator):
bl_idname = "vse_toolbox.reload_addon"
bl_options = {"UNDO"}
bl_label = 'Reload VSE ToolBox Addon'
bl_description = 'Reload The VSE ToolBox Addon'
def execute(self, context):
print('Execute reload')
vse_toolbox.unregister()
importlib.reload(vse_toolbox)
vse_toolbox.register()
return {'FINISHED'}
class VSETB_OT_rename(Operator):
2023-04-14 18:55:00 +02:00
bl_idname = "vse_toolbox.strips_rename"
2023-03-14 13:38:04 +01:00
bl_label = "Rename Strips"
bl_description = "Rename Strips"
bl_options = {"REGISTER", "UNDO"}
2023-04-25 10:29:02 +02:00
#template : StringProperty(name="Strip Name", default="")
#increment : IntProperty(name="Increment", default=0)
2023-03-14 13:38:04 +01:00
channel_name : StringProperty(name="Channel Name", default="")
2023-04-25 10:29:02 +02:00
selected_only : BoolProperty(name="Selected Only", default=False)
#start_number : IntProperty(name="Start Number", default=0, min=0)
#by_sequence : BoolProperty(
# name="Reset By Sequence",
# description="Reset Start Number for each sequence",
# default=False
#)
2023-03-14 13:38:04 +01:00
@classmethod
def poll(cls, context):
2023-04-25 11:39:06 +02:00
settings = get_scene_settings()
return settings.active_project
2023-03-14 13:38:04 +01:00
def invoke(self, context, event):
scn = context.scene
2023-03-21 18:33:29 +01:00
settings = get_scene_settings()
2023-03-14 13:38:04 +01:00
return context.window_manager.invoke_props_dialog(self)
def draw(self, context):
2023-04-25 11:39:06 +02:00
layout = self.layout
2023-03-14 13:38:04 +01:00
scn = context.scene
2023-03-21 18:33:29 +01:00
settings = get_scene_settings()
2023-04-25 11:39:06 +02:00
project = settings.active_project
2023-03-14 13:38:04 +01:00
2023-03-16 18:32:17 +01:00
col = layout.column()
2023-04-25 11:39:06 +02:00
col.use_property_split = True
col.use_property_decorate = False
2023-03-14 13:38:04 +01:00
if self.channel_name == 'Shots':
2023-04-25 11:39:06 +02:00
col.prop(project, 'shot_template', text='Shot Name')
col.prop(project, 'shot_start_number', text='Start Number')
col.prop(project, 'shot_increment', text='Increment')
col.prop(project, 'reset_by_sequence')
elif self.channel_name == 'Sequences':
col.prop(project, 'sequence_template' ,text='Sequence Name')
col.prop(project, 'sequence_start_number', text='Start Number')
col.prop(project, 'sequence_increment', text='Increment')
2023-04-25 10:29:02 +02:00
col.prop(self, 'selected_only')
2023-03-14 13:38:04 +01:00
def execute(self, context):
2023-04-25 11:39:06 +02:00
scn = context.scene
settings = get_scene_settings()
project = settings.active_project
2023-04-25 10:29:02 +02:00
strips = get_strips(channel=self.channel_name, selected_only=self.selected_only)
2023-04-25 11:39:06 +02:00
if self.channel_name == 'Shots':
rename_strips(strips,
template=project.shot_template,
increment=project.shot_increment, start_number=project.shot_start_number,
by_sequence=project.reset_by_sequence
)
if self.channel_name == 'Sequences':
rename_strips(strips,
template=project.sequence_template,
increment=project.sequence_increment, start_number=project.sequence_start_number
)
2023-03-14 13:38:04 +01:00
return {"FINISHED"}
class VSETB_OT_render(Operator):
2023-04-14 18:55:00 +02:00
bl_idname = "vse_toolbox.strips_render"
2023-03-14 13:38:04 +01:00
bl_label = "Render Shots Strips"
bl_description = "Render Shots Strips"
bl_options = {"REGISTER", "UNDO"}
2023-04-20 00:12:39 +02:00
#selected_only : BoolProperty(name="Selected Only", default=False)
2023-03-14 13:38:04 +01:00
@classmethod
def poll(cls, context):
2023-04-20 00:12:39 +02:00
settings = get_scene_settings()
return settings.active_project
2023-03-14 13:38:04 +01:00
def invoke(self, context, event):
scn = context.scene
2023-03-21 18:33:29 +01:00
settings = get_scene_settings()
2023-03-14 13:38:04 +01:00
return context.window_manager.invoke_props_dialog(self)
def draw(self, context):
scn = context.scene
2023-03-21 18:33:29 +01:00
settings = get_scene_settings()
2023-03-14 13:38:04 +01:00
2023-03-16 18:32:17 +01:00
layout = self.layout
col = layout.column()
2023-03-14 13:38:04 +01:00
col.use_property_split = True
col.use_property_decorate = False
2023-04-20 00:12:39 +02:00
#col.prop(settings, 'channel', text='Channel')
#col.prop(self, 'selected_only')
col.prop(settings.active_project, "render_template")
2023-03-14 13:38:04 +01:00
def execute(self, context):
2023-03-16 18:32:17 +01:00
scn = context.scene
2023-03-21 18:33:29 +01:00
settings = get_scene_settings()
2023-04-20 00:12:39 +02:00
strips = get_strips(channel='Shots', selected_only=True)
2023-03-14 13:38:04 +01:00
2023-04-20 00:12:39 +02:00
start_time = time.perf_counter()
render_strips(strips, settings.active_project.render_template)
self.report({"INFO"}, f'Strips rendered in {time.perf_counter()-start_time} seconds')
2023-03-14 13:38:04 +01:00
return {"FINISHED"}
2023-04-22 21:12:21 +02:00
class VSETB_OT_show_waveform(Operator):
bl_idname = "vse_toolbox.show_waveform"
bl_label = "Show Waveform"
bl_description = "Show Waveform of all audio strips"
bl_options = {"REGISTER", "UNDO"}
enabled : BoolProperty(default=True)
@classmethod
def poll(cls, context):
return True
def execute(self, context):
scn = context.scene
for strip in get_strips(channel='Audio'):
strip.show_waveform = self.enabled
return {"FINISHED"}
2023-04-14 18:55:00 +02:00
class VSETB_OT_set_sequencer(Operator):
bl_idname = "vse_toolbox.set_sequencer"
bl_label = "Set Sequencer"
bl_description = "Set resolution, frame end and channel names"
2023-03-14 13:38:04 +01:00
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return True
def execute(self, context):
scn = context.scene
set_channels()
movie = get_strips(channel='Movie')
if movie:
movie = movie[0]
movie.transform.scale_x = movie.transform.scale_y = 1
elem = movie.strip_elem_from_frame(scn.frame_current)
scn.render.resolution_x = elem.orig_width
scn.render.resolution_y = elem.orig_height
else:
self.report({'INFO'}, f'Cannot set Resolution. No Movie Found.')
2023-04-20 00:12:39 +02:00
scn.view_settings.view_transform = 'Standard'
scn.render.image_settings.file_format = 'FFMPEG'
scn.render.ffmpeg.gopsize = 5
scn.render.ffmpeg.constant_rate_factor = 'HIGH'
scn.render.ffmpeg.format = 'QUICKTIME'
scn.render.ffmpeg.audio_codec = 'AAC'
scn.render.ffmpeg.audio_codec = 'MP3'
scn.render.ffmpeg.audio_mixrate = 44100
scn.render.ffmpeg.audio_bitrate = 128
2023-03-14 13:38:04 +01:00
return {"FINISHED"}
2023-04-24 18:51:26 +02:00
class VSETB_OT_casting_replace(Operator):
bl_idname = "vse_toolbox.casting_replace"
bl_label = "Replace Asset"
bl_description = "Replace Asset of selected strips"
old_asset : StringProperty()
new_asset : StringProperty()
assets : CollectionProperty(type=PropertyGroup)
def execute(self, context):
prefs = get_addon_prefs()
settings = get_scene_settings()
new_asset = next(a for a in settings.active_project.assets if a.tracker_name == self.new_asset)
for strip in get_strips('Shots', selected_only=True):
strip_settings = strip.vsetb_strip_settings
for asset_casting in strip_settings.casting:
if asset_casting.asset.tracker_name == self.old_asset:
print(f'Replace casting on {strip.name}')
asset_casting.name = new_asset.name
asset_casting.id = new_asset.id
asset_casting['_name'] = new_asset.label
strip_settings.casting.update()
self.assets.clear()
return {'FINISHED'}
def invoke(self, context, event):
settings = get_scene_settings()
project = settings.active_project
self.assets.clear()
for asset in project.assets:
item = self.assets.add()
item.name = asset.tracker_name
strip = context.active_sequence_strip
asset_casting_index = strip.vsetb_strip_settings.casting_index
active_asset = strip.vsetb_strip_settings.casting[asset_casting_index].asset
self.old_asset = active_asset.tracker_name
self.new_asset = ''
return context.window_manager.invoke_props_dialog(self)
#
def draw(self, context):
scn = context.scene
settings = get_scene_settings()
project = settings.active_project
layout = self.layout
col = layout.column()
col.use_property_split = True
col.prop_search(self, 'old_asset', self, 'assets', text='Old Asset', icon='ASSET_MANAGER')
col.prop_search(self, 'new_asset', self, 'assets', text='New Asset', icon='ASSET_MANAGER')
2023-03-21 18:33:29 +01:00
def get_asset_items(self, context):
settings = get_scene_settings()
project = settings.active_project
return [(a.id, a.label, '', i) for i, a in enumerate(project.assets)]
2023-03-17 20:03:38 +01:00
class VSETB_OT_casting_add(Operator):
bl_idname = "vse_toolbox.casting_add"
bl_label = "Casting Add"
bl_description = "Add Asset to Castin"
bl_options = {"REGISTER", "UNDO"}
bl_property = "asset_name"
2023-03-21 18:33:29 +01:00
asset_name : EnumProperty(name='', items=get_asset_items)
2023-03-17 20:03:38 +01:00
@classmethod
def poll(cls, context):
active_strip = context.scene.sequence_editor.active_strip
if active_strip:
return True
2023-03-21 18:33:29 +01:00
2023-03-17 20:03:38 +01:00
def invoke(self, context, event):
context.window_manager.invoke_search_popup(self)
2023-03-21 18:33:29 +01:00
return {'FINISHED'}
2023-03-17 20:03:38 +01:00
def execute(self, context):
scn = context.scene
active_strip = scn.sequence_editor.active_strip
2023-03-21 18:33:29 +01:00
settings = get_scene_settings()
strip_settings = get_strip_settings()
2023-03-17 20:03:38 +01:00
project = settings.active_project
2023-03-21 18:33:29 +01:00
if strip_settings.casting.get(self.asset_name):
asset = project.assets[self.asset_name]
self.report({'WARNING'}, f"Asset {asset.label} already casted.")
2023-03-17 20:03:38 +01:00
return {"CANCELLED"}
2023-03-21 18:33:29 +01:00
item = strip_settings.casting.add()
asset = project.assets[self.asset_name]
item.name = asset.name
item.id = project.assets[self.asset_name].id
2023-04-14 18:55:00 +02:00
item['_name'] = asset.label
2023-03-21 18:33:29 +01:00
strip_settings.casting.update()
2023-03-17 20:03:38 +01:00
return {"FINISHED"}
2023-03-21 18:33:29 +01:00
class VSETB_OT_casting_remove(Operator):
bl_idname = "vse_toolbox.casting_remove"
bl_label = "Remove Item from Casting"
bl_description = "Remove Item from Casting"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
active_strip = context.scene.sequence_editor.active_strip
if active_strip:
return True
def invoke(self, context, event):
scn = context.scene
strip_settings = get_strip_settings()
idx = strip_settings.casting_index
try:
item = strip_settings.casting[idx]
except IndexError:
pass
else:
item = strip_settings.casting[strip_settings.casting_index]
2023-04-14 18:55:00 +02:00
label = item.asset.label if item.asset.label else 'Empty'
info = f"Item {label} removed from casting"
2023-03-21 18:33:29 +01:00
strip_settings.casting.remove(idx)
if strip_settings.casting_index == 0:
strip_settings.casting_index = 0
else:
strip_settings.casting_index -= 1
self.report({'INFO'}, info)
return {"FINISHED"}
class VSETB_OT_casting_move(Operator):
bl_idname = "vse_toolbox.casting_move"
2023-04-21 21:44:05 +02:00
bl_label = "Move Casting items"
bl_description = "Move Casting items"
2023-03-17 20:03:38 +01:00
bl_options = {"REGISTER", "UNDO"}
2023-04-21 21:44:05 +02:00
direction: EnumProperty(
2023-03-17 20:03:38 +01:00
items=(
('UP', "Up", ""),
('DOWN', "Down", ""),
)
)
asset_name : StringProperty()
@classmethod
def poll(cls, context):
active_strip = context.scene.sequence_editor.active_strip
if active_strip:
return True
2023-04-21 21:44:05 +02:00
def execute(self, context):
2023-03-17 20:03:38 +01:00
scn = context.scene
2023-03-21 18:33:29 +01:00
strip_settings = get_strip_settings()
idx = strip_settings.casting_index
2023-03-17 20:03:38 +01:00
try:
2023-03-21 18:33:29 +01:00
item = strip_settings.casting[idx]
2023-03-17 20:03:38 +01:00
except IndexError:
pass
else:
2023-04-21 21:44:05 +02:00
if self.direction == 'DOWN' and idx < len(strip_settings.casting) - 1:
2023-03-21 18:33:29 +01:00
item_next = strip_settings.casting[idx+1].name
strip_settings.casting.move(idx, idx+1)
strip_settings.casting_index += 1
2023-03-17 20:03:38 +01:00
2023-04-21 21:44:05 +02:00
elif self.direction == 'UP' and idx >= 1:
2023-03-21 18:33:29 +01:00
item_prev = strip_settings.casting[idx-1].name
strip_settings.casting.move(idx, idx-1)
strip_settings.casting_index -= 1
info = f"Item {item.asset.label} moved to position {(item.asset.label, strip_settings.casting_index + 1)}"
self.report({'INFO'}, info)
2023-03-17 20:03:38 +01:00
2023-03-21 18:33:29 +01:00
return {"FINISHED"}
2023-03-17 20:03:38 +01:00
2023-04-24 18:51:26 +02:00
class VSETB_MT_spreadsheet_presets(Menu):
bl_label = 'Presets'
preset_subdir = 'vse_toolbox'
preset_operator = 'script.execute_preset'
draw = Menu.draw_preset
class VSETB_OT_add_spreadsheet_preset(AddPresetBase, Operator):
bl_idname = "vse_toolbox.add_spreadsheet_preset"
bl_label = "Add Spreadsheet Preset"
bl_description = "Add Spreadsheet Preset"
bl_options = {"REGISTER", "UNDO"}
preset_menu = 'VSETB_MT_spreadsheet_presets'
#preset_menu = 'VSETB_OT_MT_spreadsheet_presets'
# Common variable used for all preset values
#C.scene.vsetb_settings.active_project.spreadsheet_options
preset_defines = [
'scene = bpy.context.scene',
'settings = scene.vsetb_settings',
'project = settings.active_project'
]
# Properties to store in the preset
preset_values = [
'project.spreadsheet',
'project.spreadsheet_options'
]
# Directory to store the presets
preset_subdir = 'vse_toolbox'
2023-04-21 21:44:05 +02:00
class VSETB_OT_spreadsheet_move(Operator):
bl_idname = "vse_toolbox.spreadsheet_move"
bl_label = "Move Spreadsheet items"
bl_description = "Move Spreadsheet items"
bl_options = {"REGISTER", "UNDO"}
direction: EnumProperty(
items=(
('UP', "Up", ""),
('DOWN', "Down", ""),
)
)
def execute(self, context):
scn = context.scene
project = get_scene_settings().active_project
idx = project.spreadsheet_index
try:
item = project.spreadsheet[idx]
except IndexError:
pass
else:
if self.direction == 'DOWN' and idx < len(project.spreadsheet) - 1:
item_next = project.spreadsheet[idx+1].name
project.spreadsheet.move(idx, idx+1)
project.spreadsheet_index += 1
elif self.direction == 'UP' and idx >= 1:
item_prev = project.spreadsheet[idx-1].name
project.spreadsheet.move(idx, idx-1)
project.spreadsheet_index -= 1
return {"FINISHED"}
2023-04-24 18:51:26 +02:00
2023-03-21 18:33:29 +01:00
class VSETB_OT_copy_casting(Operator):
2023-04-14 18:55:00 +02:00
bl_idname = "vse_toolbox.copy_casting"
2023-04-21 21:44:05 +02:00
bl_label = "Copy Casting"
2023-03-21 18:33:29 +01:00
bl_description = "Copy Casting from active strip"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
active_strip = context.scene.sequence_editor.active_strip
strip_settings = get_strip_settings()
if active_strip and strip_settings.casting:
return True
2023-03-17 20:03:38 +01:00
2023-03-21 18:33:29 +01:00
def execute(self, context):
scn = context.scene
active_strip = scn.sequence_editor.active_strip
strip_settings = get_strip_settings()
datas = [c.to_dict() for c in strip_settings.casting]
CASTING_BUFFER.write_text(json.dumps(datas), encoding='utf-8')
2023-03-17 20:03:38 +01:00
return {"FINISHED"}
2023-03-21 18:33:29 +01:00
class VSETB_OT_paste_casting(Operator):
2023-04-14 18:55:00 +02:00
bl_idname = "vse_toolbox.paste_casting"
2023-04-21 21:44:05 +02:00
bl_label = "Paste Casting"
bl_description = "Paste Casting to active strip"
2023-03-21 18:33:29 +01:00
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
active_strip = context.scene.sequence_editor.active_strip
if active_strip:
return True
def execute(self, context):
scn = context.scene
strip_settings = get_strip_settings()
if not CASTING_BUFFER.exists():
self.report({'ERROR'}, f'No Casting to copy.')
return {"CANCELLED"}
casting_datas = json.loads(CASTING_BUFFER.read_text())
2023-04-25 18:43:04 +02:00
for strip in context.selected_sequences:
strip_settings = strip.vsetb_strip_settings
for casting_data in casting_datas:
2023-03-21 18:33:29 +01:00
item = strip.vsetb_strip_settings.casting.add()
2023-04-25 18:43:04 +02:00
item.name = casting_data['name']
item.id = casting_data['id']
item['_name'] = casting_data['_name']
2023-03-21 18:33:29 +01:00
strip_settings.casting.update()
return {"FINISHED"}
2023-04-14 18:55:00 +02:00
class VSETB_OT_set_stamps(Operator):
bl_idname = "vse_toolbox.set_stamps"
bl_label = "Set Stamps"
bl_description = "Set Stamps on Video"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
scn = context.scene
settings = get_scene_settings()
#strip_settings = get_strip_settings()
channel_index = get_channel_index('Stamps')
for strip in get_strips('Stamps'):
if strip.type == 'META':
scn.sequence_editor.sequences.remove(strip)
bpy.ops.sequencer.select_all(action='DESELECT')
2023-04-21 21:44:05 +02:00
crop_x = int(scn.render.resolution_x * 0.4)
crop_max_y = int(scn.render.resolution_y * 0.96)
crop_min_y = int(scn.render.resolution_y * 0.01)
stamp_params = dict(start=scn.frame_start, end=scn.frame_end,
font_size=22, y=0.015, box_margin=0.005, select=True, box_color=(0, 0, 0, 0.5))
2023-04-20 00:12:39 +02:00
2023-04-14 18:55:00 +02:00
# Project Name
2023-04-21 21:44:05 +02:00
project_strip_stamp = new_text_strip('project_name_stamp', channel=1, **stamp_params,
text=settings.active_project.name, x=0.01, align_x='LEFT', align_y='BOTTOM')
2023-04-14 18:55:00 +02:00
2023-04-20 00:12:39 +02:00
project_strip_stamp.crop.max_x = crop_x * 2
2023-04-21 21:44:05 +02:00
project_strip_stamp.crop.max_y = crop_max_y
project_strip_stamp.crop.min_y = crop_min_y
2023-04-20 00:12:39 +02:00
2023-04-14 18:55:00 +02:00
# Shot Name
2023-04-21 21:44:05 +02:00
shot_strip_stamp = new_text_strip('shot_name_stamp', channel=2, **stamp_params,
text='{active_shot_name}', align_y='BOTTOM')
2023-04-14 18:55:00 +02:00
2023-04-20 00:12:39 +02:00
shot_strip_stamp.crop.min_x = crop_x
shot_strip_stamp.crop.max_x = crop_x
2023-04-21 21:44:05 +02:00
shot_strip_stamp.crop.max_y = crop_max_y
shot_strip_stamp.crop.min_y = crop_min_y
2023-04-20 00:12:39 +02:00
2023-04-14 18:55:00 +02:00
# Frame Range
2023-04-21 21:44:05 +02:00
frame_strip_stamp = new_text_strip('frame_range_stamp', channel=3, **stamp_params,
text='{active_shot_frame} / {active_shot_duration}', x=0.99, align_x='RIGHT', align_y='BOTTOM')
2023-04-14 18:55:00 +02:00
2023-04-21 21:44:05 +02:00
frame_strip_stamp.crop.min_x = crop_x *2
frame_strip_stamp.crop.max_y = crop_max_y
frame_strip_stamp.crop.min_y = crop_min_y
2023-04-14 18:55:00 +02:00
bpy.ops.sequencer.meta_make()
stamps_strip = context.active_sequence_strip
stamps_strip.name = 'Stamps'
stamps_strip.channel = channel_index
#stamps_strip = scn.sequence_editor.sequences.new_meta('Stamps', scn.frame_start, scn.frame_end)
#stamps_strip.channel = get_channel_index('Stamps')
scn.frame_set(scn.frame_current) # For update stamps
return {"FINISHED"}
2023-04-25 11:39:06 +02:00
def load_settings():
prefs = get_addon_prefs()
settings = get_scene_settings()
project = settings.active_project
prefs_config_file = prefs.config_path
if not prefs_config_file:
return
prefs_datas = read_file(os.path.expandvars(prefs_config_file))
prefs_datas['trackers'] = prefs_datas.get('trackers')
prefs_datas['spreadsheet'] = prefs_datas.get('spreadsheet')
#print(prefs_datas)
trackers = prefs_datas.pop('trackers')
spreadsheet = prefs_datas.pop('spreadsheet')
project_name = prefs_datas.get('project_name')
if project_name:
settings.project_name = project_name
# Project Properties
for k, v in prefs_datas.items():
try:
setattr(project, k, v)
except Exception:
print(f'Could not set property {k} with value {v} to project {settings.project_name}')
if spreadsheet.get('cells'):
#project.spreadsheet.clear()
for i, cell_data in enumerate(spreadsheet['cells']):
if not 'name' in cell_data:
print(f'cell_data {cell_data} need to have a attribute name')
continue
cell = project.spreadsheet.get(cell_data['name'])
if not cell:
print(f"cell {cell_data['name']} not in spreadsheet")
continue
project.spreadsheet.move(list(project.spreadsheet).index(cell), i)
for prop_name in ('export_name', 'enabled'):
if prop_name in cell_data:
setattr(cell, prop_name, cell_data[prop_name])
if spreadsheet.get('options'):
for k, v in spreadsheet['options'].items():
try:
setattr(project.spreadsheet_options, k, v)
except Exception:
print(f'Could not set option {k} with value {v} to spreadsheet')
2023-04-14 18:55:00 +02:00
classes = (
2023-03-16 18:32:17 +01:00
VSETB_OT_auto_select_files,
2023-03-17 20:03:38 +01:00
VSETB_OT_casting_add,
2023-03-21 18:33:29 +01:00
VSETB_OT_casting_remove,
VSETB_OT_casting_move,
2023-04-24 18:51:26 +02:00
VSETB_OT_add_spreadsheet_preset,
VSETB_MT_spreadsheet_presets,
2023-04-21 21:44:05 +02:00
VSETB_OT_spreadsheet_move,
2023-03-21 18:33:29 +01:00
VSETB_OT_copy_casting,
VSETB_OT_paste_casting,
2023-04-24 18:51:26 +02:00
VSETB_OT_casting_replace,
2023-04-21 21:44:05 +02:00
VSETB_OT_export_spreadsheet,
2023-03-17 22:55:06 +01:00
VSETB_OT_import_files,
2023-03-17 20:03:38 +01:00
VSETB_OT_load_assets,
2023-03-14 13:38:04 +01:00
VSETB_OT_load_projects,
VSETB_OT_new_episode,
VSETB_OT_reload_addon,
VSETB_OT_rename,
VSETB_OT_render,
2023-04-14 18:55:00 +02:00
VSETB_OT_set_sequencer,
2023-03-24 11:42:17 +01:00
VSETB_OT_tracker_connect,
2023-04-20 00:12:39 +02:00
VSETB_OT_set_stamps,
2023-04-22 21:12:21 +02:00
VSETB_OT_upload_to_tracker,
2023-04-25 18:43:04 +02:00
VSETB_OT_show_waveform,
VSETB_OT_copy_metadata
2023-03-14 13:38:04 +01:00
)
def register():
for cls in classes:
bpy.utils.register_class(cls)
def unregister():
for cls in reversed(classes):
bpy.utils.unregister_class(cls)