pull/5/head
Christophe SEUX 2023-04-20 00:12:39 +02:00
parent 93134f25a9
commit d2caf90ea2
8 changed files with 505 additions and 142 deletions

View File

@ -23,6 +23,8 @@ SOUND_SUFFIXES = ['.mp3', '.aaf', '.flac', '.wav']
CONFIG_DIR = Path(appdirs.user_config_dir(__package__.split('.')[0]))
PREVIEWS_DIR = CONFIG_DIR / 'thumbnails'
TASK_ITEMS = []
ASSET_PREVIEWS = bpy.utils.previews.new()
CASTING_BUFFER = CONFIG_DIR / 'casting.json'

View File

@ -4,6 +4,7 @@ import bpy
import importlib
import json
import re
import time
import vse_toolbox
from bpy_extras.io_utils import ImportHelper
@ -29,6 +30,7 @@ from vse_toolbox.constants import (
PREVIEWS_DIR,
SOUNDS,
SOUND_SUFFIXES,
TASK_ITEMS
)
from vse_toolbox.sequencer_utils import (
clean_sequencer,
@ -41,8 +43,11 @@ from vse_toolbox.sequencer_utils import (
render_strips,
set_channels,
get_channel_index,
new_text_strip
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
from vse_toolbox.file_utils import install_module, norm_name, norm_str
@ -88,6 +93,133 @@ class VSETB_OT_export_csv(Operator):
return {"CANCELLED"}
def get_task_status_items(self, context):
settings = get_scene_settings()
project = settings.active_project
status_items = [('CURRENT', 'Current', '')]
status_items += [(t.name, t.name, '') for t in project.task_statuses]
return status_items
def get_task_type_items(self, context):
settings = get_scene_settings()
project = settings.active_project
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"}
task: EnumProperty(items=get_task_type_items)
status: EnumProperty(items=get_task_status_items)
comment : StringProperty()
add_preview : BoolProperty(default=False)
preview_mode : EnumProperty(items=[(m, m.title().replace('_', ' '), '') for m in ('ONLY_NEW', 'REPLACE', 'ADD')])
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()
#project = settings.active_project
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
sequence = tracker.get_sequence(sequence_name)
if not sequence:
self.report({"INFO"}, f'Create sequence {sequence_name} in Kitsu')
sequence = tracker.new_sequence(sequence_name)
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)
print(task)
tracker.new_comment(task, comment=self.comment, status=status)
#status = tracker.get_task(shot, self.task)
# if self.add_preview:
# strip_movie_path = Path(get_strip_render_path(strip, template))
# if path.exists():
# else:
# self.report({"WARNING"}, f"{strip_movie_path} not exist, skipped")
return {"FINISHED"}
# if add_to_kitsu:
# shot_name = T['shot_tracker_name'].fields['shot'].format(data['shot'])
# seq_name = T['sequence_tracker_name'].fields['sequence'].format(data['sequence'])
# sequence = p.sequences.add(seq_name)
# shot = sequence.shots.add(shot_name)
# animatic_task = shot.tasks.add('animatic')
# animatic_task.comments.new(
# comment=f'Reel edit v{version:03d}',
# status='done',
# preview=movie_output,
# set_main_preview=True
# )
# shot_data = {
# 'fps': int(FPS),
# 'frame_in': strip.frame_final_start,
# 'frame_out': strip.frame_final_end-1,
# 'nb_frames': strip.frame_final_duration
# }
# shot.update_data(shot_data)
# return {"CANCELLED"}
class VSETB_OT_auto_select_files(Operator):
bl_idname = "import.auto_select_files"
bl_label = "Auto Select"
@ -317,8 +449,6 @@ class VSETB_OT_load_projects(Operator):
tracker.connect()
for project_data in tracker.get_projects():
project = settings.projects.add()
project.type = project_data['production_type'].upper().replace(' ', '')
project.name = project_data['name']
@ -335,6 +465,15 @@ class VSETB_OT_load_projects(Operator):
metadata_type = project.metadata_types.add()
metadata_type.name = metadata_data['field_name']
metadata_type['choices'] = metadata_data['choices']
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']
for asset_type_data in tracker.get_asset_types(project_data):
asset_type = project.asset_types.add()
@ -465,11 +604,12 @@ class VSETB_OT_render(Operator):
bl_description = "Render Shots Strips"
bl_options = {"REGISTER", "UNDO"}
selected_only : BoolProperty(name="Selected Only", default=False)
#selected_only : BoolProperty(name="Selected Only", default=False)
@classmethod
def poll(cls, context):
return True
settings = get_scene_settings()
return settings.active_project
def invoke(self, context, event):
scn = context.scene
@ -485,15 +625,20 @@ class VSETB_OT_render(Operator):
col = layout.column()
col.use_property_split = True
col.use_property_decorate = False
col.prop(settings, 'channel', text='Channel')
col.prop(self, 'selected_only')
#col.prop(settings, 'channel', text='Channel')
#col.prop(self, 'selected_only')
col.prop(settings.active_project, "render_template")
def execute(self, context):
scn = context.scene
settings = get_scene_settings()
strips = get_strips(channel=settings.channel, selected_only=self.selected_only)
strips = get_strips(channel='Shots', selected_only=True)
render_strips(strips)
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')
return {"FINISHED"}
@ -522,6 +667,16 @@ class VSETB_OT_set_sequencer(Operator):
else:
self.report({'INFO'}, f'Cannot set Resolution. No Movie Found.')
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
return {"FINISHED"}
@ -744,6 +899,9 @@ class VSETB_OT_set_stamps(Operator):
bpy.ops.sequencer.select_all(action='DESELECT')
crop_x = int(scn.render.resolution_x * 0.33)
crop_y = int(scn.render.resolution_y * 0.95)
# Project Name
project_strip_stamp = new_text_strip(
'project_name_stamp', channel=1, start=scn.frame_start, end=scn.frame_end,
@ -752,6 +910,9 @@ class VSETB_OT_set_stamps(Operator):
box_color=(0, 0, 0, 0.5), box_margin=0.005,
)
project_strip_stamp.crop.max_x = crop_x * 2
project_strip_stamp.crop.max_y = crop_y
# Shot Name
shot_strip_stamp = new_text_strip(
f'shot_name_stamp', channel=2, start=scn.frame_start, end=scn.frame_end,
@ -760,6 +921,10 @@ class VSETB_OT_set_stamps(Operator):
box_color=(0, 0, 0, 0.5), box_margin=0.005,
)
shot_strip_stamp.crop.min_x = crop_x
shot_strip_stamp.crop.max_x = crop_x
shot_strip_stamp.crop.max_y = crop_y
# Frame Range
frame_strip_stamp = new_text_strip(
'frame_range_stamp', channel=3, start=scn.frame_start, end=scn.frame_end,
@ -768,6 +933,8 @@ class VSETB_OT_set_stamps(Operator):
box_color=(0, 0, 0, 0.5), box_margin=0.005,
)
frame_strip_stamp.crop.min_x = int(scn.render.resolution_x * 0.66)
frame_strip_stamp.crop.max_y = crop_y
# for shot_strip in get_strips('Shots'):
# # Shot Name
# shot_strip_stamp = new_text_strip(
@ -806,7 +973,8 @@ classes = (
VSETB_OT_render,
VSETB_OT_set_sequencer,
VSETB_OT_tracker_connect,
VSETB_OT_set_stamps
VSETB_OT_set_stamps,
VSETB_OT_upload_to_tracker
)
def register():

View File

@ -86,9 +86,13 @@ class VSETB_PT_sequencer(VSETB_main, Panel):
col.operator('vse_toolbox.set_sequencer', text='Set-Up Sequencer', icon='SEQ_SEQUENCER')
#row = col.row()
episode = project.episode_name
sequence_label = project.sequence_template.format(episode=episode, index=project.sequence_start_number)
shot_label = project.shot_template.format(episode=episode, sequence=sequence_label, index=project.shot_start_number)
shot_label = ''
sequence_label = ''
if project:
episode = project.episode_name
sequence_label = project.sequence_template.format(episode=episode, index=project.sequence_start_number)
shot_label = project.shot_template.format(episode=episode, sequence=sequence_label, index=project.shot_start_number)
#row.separator()
@ -106,19 +110,41 @@ class VSETB_PT_sequencer(VSETB_main, Panel):
row.enabled = False
op = row.operator('vse_toolbox.strips_rename', text=f'Rename {channel_name} ( {label} )', icon='SORTALPHA')
op.channel_name = channel_name
if channel_name == 'Shots':
op.start_number = project.shot_start_number
op.template = project.shot_template
op.increment = project.shot_increment
else:
op.start_number = project.sequence_start_number
op.template = project.sequence_template
op.increment =project.sequence_increment
if project:
op.channel_name = channel_name
if channel_name == 'Shots':
op.start_number = project.shot_start_number
op.template = project.shot_template
op.increment = project.shot_increment
else:
op.start_number = project.sequence_start_number
op.template = project.sequence_template
op.increment = project.sequence_increment
col.operator('vse_toolbox.set_stamps', text='Set Stamps', icon='COLOR')
class VSETB_PT_settings(VSETB_main, Panel):
bl_label = "Settings"
bl_parent_id = "VSETB_PT_main"
bl_options = {'DEFAULT_CLOSED'}
#def draw_header_preset(self, context):
# self.layout.operator('vse_toolbox.import_files', icon='IMPORT', text='', emboss=False)
def draw(self, context):
prefs = get_addon_prefs()
layout = self.layout
settings = get_scene_settings()
project = settings.active_project
col = layout.column()
#row = col.row(align=True)
col.prop(project, 'sequence_template')
col.prop(project, 'shot_template')
col.prop(project, 'render_template')
class VSETB_PT_imports(VSETB_main, Panel):
bl_label = "Imports"
bl_parent_id = "VSETB_PT_main"
@ -154,7 +180,10 @@ class VSETB_PT_exports(VSETB_main, Panel):
# TODO FAIRE DES VRAIS OPS
layout.operator('vse_toolbox.strips_render', text='Render Strips', icon='SEQUENCE')
layout.operator('vse_toolbox.export_csv', text='Export', icon='EXPORT')
tracker_label = settings.tracker_name.title().replace('_', ' ')
layout.operator('vse_toolbox.upload_to_tracker', text=f'Upload to {tracker_label}', icon='EXPORT')
layout.operator('vse_toolbox.export_csv', text='Export csv', icon='SPREADSHEET')
class VSETB_PT_casting(VSETB_main, Panel):

View File

@ -48,16 +48,18 @@ def load_trackers():
if not Tracker in obj.__mro__:
continue
if obj is Tracker or obj.name in (a.name for a in TRACKERS):
if obj is Tracker or name in (a.__name__ for a in TRACKERS):
continue
try:
print(f'Register Plugin {name}')
print(f'Register Tracker {name}')
bpy.utils.register_class(obj)
setattr(Trackers, norm_str(obj.name), PointerProperty(type=obj))
#obj.register()
setattr(Trackers, norm_str(name), PointerProperty(type=obj))
TRACKERS.append(obj)
except Exception as e:
print(f'Could not register library_type {name}')
print(f'Could not register Tracker {name}')
print(e)
def load_tracker_prefs():

View File

@ -41,15 +41,20 @@ def on_project_updated(self, context):
settings = get_scene_settings()
settings['episodes'] = 0
print('Update active Project')
#print('Update active Project')
bpy.ops.vse_toolbox.load_assets()
if settings.active_project:
settings.active_project.set_strip_metadata()
os.environ['TRACKER_PROJECT_ID'] = settings.active_project.id
def on_episode_updated(self, context):
os.environ['TRACKER_EPISODE_ID'] = settings.active_episode.id
def get_tracker_items(self, context):
return [(norm_str(a.name, format=str.upper), a.name, "", i) for i, a in enumerate(TRACKERS)]
return [(norm_str(a.__name__, format=str.upper), a.__name__, "", i) for i, a in enumerate(TRACKERS)]
class Asset(PropertyGroup):
@ -97,6 +102,14 @@ class MetadataType(PropertyGroup):
choice : EnumProperty(items=lambda s, c: [(c, c.replace(' ', '_').upper(), '') for c in s['choices']])
class TaskType(PropertyGroup):
__annotations__ = {}
class TaskStatus(PropertyGroup):
__annotations__ = {}
class Metadata(PropertyGroup):
__annotations__ = {}
@ -131,11 +144,17 @@ class Project(PropertyGroup):
shot_template : StringProperty(
name="Shot Name", default="{sequence}_sh{index:04d}")
episode_name : EnumProperty(items=get_episodes_items)
render_template : StringProperty(
name="Render Name", default="//render/{strip_name}.{ext}")
episode_name : EnumProperty(items=get_episodes_items, update=on_episode_updated)
episodes : CollectionProperty(type=Episode)
assets : CollectionProperty(type=Asset)
asset_types : CollectionProperty(type=AssetType)
metadata_types : CollectionProperty(type=MetadataType)
task_types : CollectionProperty(type=TaskType)
task_statuses : CollectionProperty(type=TaskStatus)
type : StringProperty()
def set_strip_metadata(self):
@ -272,9 +291,11 @@ classes=(
Asset,
AssetCasting,
AssetType,
TaskStatus,
Episode,
Metadata,
MetadataType,
TaskType,
Project,
VSETB_UL_casting,
VSETB_PGT_scene_settings,
@ -290,6 +311,7 @@ def load_handler(dummy):
settings = get_scene_settings()
if settings.active_project:
settings.active_project.set_strip_metadata()
os.environ['TRACKER_PROJECT_ID'] = settings.active_project.id
def register():

View File

@ -5,10 +5,10 @@ import re
import urllib3
import traceback
import time
import uuid
from bpy.props import PointerProperty, StringProperty
from pathlib import Path
from vse_toolbox.bl_utils import get_addon_prefs, get_scene_settings
from vse_toolbox.file_utils import install_module, norm_str
from vse_toolbox.resources.trackers.tracker import Tracker
@ -18,34 +18,163 @@ except Exception as e:
print('Could not install gazu')
print(e)
LOGIN = None
class Kitsu(Tracker):
name = "Kitsu"
url: StringProperty()
login: StringProperty()
password: StringProperty(subtype='PASSWORD')
project_name = None
def connect(self, url=None, login=None, password=None):
'''Connect to kitsu api using provided url, login and password'''
global LOGIN
urllib3.disable_warnings()
if url is None:
url = self.url
if login is None:
login = self.login
if password is None:
password = self.password
if not url:
print(f'Kitsu Url: {self.url} is empty')
return
if login == LOGIN:
return
if not url.endswith('/api'):
url += '/api'
print(f'Info: Setting Host for kitsu {url}')
gazu.client.set_host(url)
if not gazu.client.host_is_up():
print('Error: Kitsu Host is down')
try:
print(f'Info: Log in to kitsu as {login}')
res = gazu.log_in(login, password)
LOGIN = login
print(f'Info: Sucessfully login to Kitsu as {res["user"]["full_name"]}')
return res['user']
except Exception as e:
print(f'Error: {traceback.format_exc()}')
def get_id(self, data):
if isinstance(data, str):
if self.is_id(data):
return data
#return None
elif isinstance(data, dict):
return data['id']
elif data: # Should be a Class
return data.id
def is_id(self, id):
if not isinstance(id, str):
return False
try:
uuid.UUID(id)
return True
except ValueError:
return False
def get_project(self, project=None):
if project:
project_id = self.get_id(project)
if project_id:
return project_id
return gazu.project.get_project_by_name(project)
if os.environ.get('TRACKER_PROJECT_ID'):
return os.environ['TRACKER_PROJECT_ID']
elif os.environ.get('TRACKER_PROJECT_NAME'):
return os.environ['TRACKER_PROJECT_NAME']
def draw_prefs(self, layout):
layout.prop(self, 'url', text='Url')
layout.prop(self, 'login', text='Login')
layout.prop(self, 'password', text='Password')
def get_projects(self):
return gazu.project.all_open_projects()
def get_episode(self, episode, project=None):
project = self.get_project(project)
if episode:
episode_id = self.get_id(episode)
if episode_id:
return episode_id
return gazu.shot.get_episode_by_name(project, episode)
if os.environ.get('TRACKER_EPISODE_ID'):
return os.environ['TRACKER_EPISODE_ID']
elif os.environ.get('TRACKER_EPISODE_NAME'):
return os.environ['TRACKER_EPISODE_NAME']
def get_episodes(self, project):
return gazu.shot.all_episodes_for_project(project)
def get_episode(self, name):
return gazu.shot.get_episode_by_name(self.project, name)
def get_task_type(self, task_type=None):
print('get_task_type', task_type)
return gazu.task.get_task_type_by_name(task_type)
def get_asset_types(self, project):
def get_shot_task_types(self, project=None):
project = self.get_project(project)
task_types = gazu.task.all_task_types_for_project(project)
return [t for t in task_types if t['for_entity'].lower() == 'shot']
def get_shots_metadata(self, project=None):
project = self.get_project(project)
metadatas = []
for metadata in gazu.project.all_metadata_descriptors(project):
if metadata['entity_type'] == 'Shot' and metadata['name']:
metadatas.append(metadata)
return metadatas
def get_task_status(self, status=None):
status_id = self.get_id(status)
if status_id:
return status_id
return gazu.client.fetch_first('task-status', {"short_name": status.lower()})
def get_task_statuses(self, project=None):
project = self.get_project(project)
return gazu.task.all_task_statuses_for_project(project)
def get_asset_types(self, project=None):
project = self.get_project(project)
return gazu.asset.all_asset_types_for_project(project)
def get_assets(self, project):
def get_sequence(self, sequence, project=None):
print(f'get_sequence({sequence=}, {project=})')
project = self.get_project(project)
sequence_id = self.get_id(sequence)
if sequence_id:
return sequence_id
return gazu.shot.get_sequence_by_name(project, sequence)
def get_shot(self, shot, sequence, project=None):
print(f'get_shot({shot=}, {sequence=}, {project=})')
project = self.get_project(project)
sequence = self.get_sequence(sequence, project)
if not sequence:
return
shot_id = self.get_id(shot)
if shot_id:
return shot_id
return gazu.shot.get_shot_by_name(sequence, shot)
def get_assets(self, project=None):
project = self.get_project(project)
assets = gazu.asset.all_assets_for_project(project)
entity_types = self.get_asset_types(project)
entity_types_ids = {e['id']: e['name'] for e in entity_types}
@ -55,14 +184,54 @@ class Kitsu(Tracker):
return assets
def get_shots_metadata(self, project):
metadatas = []
def get_last_comment(self, task):
task = self.get_id(task)
return gazu.task.get_last_comment_for_task(task)
for metadata in gazu.project.all_metadata_descriptors(project):
if metadata['entity_type'] == 'Shot' and metadata['name']:
metadatas.append(metadata)
def get_task(self, task=None, entity=None):
entity = self.get_id(entity)
return metadatas
task_type = self.get_task_type(task)
print('task_type', task_type)
print('task_type', task_type)
task = gazu.task.get_task_by_name(entity, task_type)
#task = gazu.task.get_task(task['id'])
task['last_comment'] = self.get_last_comment(task)
return task
def new_comment(self, task, status=None, comment='', preview=None, set_main_preview=False):
#task = self.get_task(task)
#print('Add Comment', status)
if status is None:
#print(task)
status = {'id' : task['task_status_id']}
else:
status = self.get_task_status(status)
comment = gazu.task.add_comment(
task=task,
task_status=status,
comment=comment )
if preview:
logging.info(f'Adding Preview to Kitsu {preview}')
preview = self.add_preview(
task=task,
comment=comment,
preview=str(preview) )
if set_main_preview:
gazu.task.set_main_preview(preview)
return comment
def download_preview(self, preview_id, filepath):
if isinstance(filepath, str):
@ -74,100 +243,43 @@ class Kitsu(Tracker):
filepath.parent.mkdir(parents=True, exist_ok=True)
gazu.files.download_preview_file_thumbnail(preview_id, filepath.as_posix())
def connect(self, url=None, login=None, password=None):
'''Connect to kitsu api using provided url, login and password'''
def new_sequence(self, sequence, episode=None, project=None):
project = self.get_project(project)
urllib3.disable_warnings()
params = dict(name=sequence, project=project)
episode = self.get_episode(episode)
if episode:
params['episode'] = episode
if not self.url:
print(f'Kitsu Url: {self.url} is empty')
return
return gazu.shot.new_sequence(**params)
url = self.url
if not url.endswith('/api'):
url += '/api'
def new_shot(self, shot, sequence, nb_frames=None, frame_in=None,
frame_out=None, description='', custom_data=None, project=None):
print(f'Info: Setting Host for kitsu {url}')
gazu.client.set_host(url)
project = self.get_project(project)
sequence = self.get_sequence(sequence)
if not gazu.client.host_is_up():
print('Error: Kitsu Host is down')
custom_data = custom_data or {}
try:
print(f'Info: Log in to kitsu as {self.login}')
res = gazu.log_in(self.login, self.password)
print(f'Info: Sucessfully login to Kitsu as {res["user"]["full_name"]}')
return res['user']
except Exception as e:
print(f'Error: {traceback.format_exc()}')
if frame_in is not None:
custom_data["frame_in"] = frame_in
if frame_out is not None:
custom_data["frame_out"] = frame_out
def get_asset_path(self, name, catalog, directory=None):
directory = directory or self.source_directory
return Path(directory, self.get_asset_relative_path(name, catalog))
params = dict(name=shot, data=custom_data,
sequence_id=self.get_id(sequence), description=description)
def get_asset_info(self, data, asset_path):
modified = time.time_ns()
catalog = data['entity_type_name'].title()
asset_path = self.prop_rel_path(asset_path, 'source_directory')
if nb_frames is not None:
params["nb_frames"] = nb_frames
asset_info = dict(
filepath=asset_path,
modified=modified,
library_id=self.library.id,
assets=[dict(
catalog=catalog,
metadata=data.get('data', {}),
description=data['description'],
tags=[],
type=self.data_type,
name=data['name'])
]
)
return asset_info
shot = self.get_shot(shot=shot, sequence=sequence)
if shot:
return shot
else:
path = f"data/projects/{self.get_id(project)}/shots"
return gazu.client.post(path, params)
def fetch(self):
"""Gather in a list all assets found in the folder"""
print(f'Fetch Assets for {self.library.name}')
self.connect()
template_file = Template(self.template_file)
template_name = Template(self.template_name)
project = gazu.client.fetch_first('projects', {'name': self.project_name})
entity_types = gazu.client.fetch_all('entity-types')
entity_types_ids = {e['id']: e['name'] for e in entity_types}
cache = self.read_cache()
for asset_data in gazu.asset.all_assets_for_project(project):
asset_data['entity_type_name'] = entity_types_ids[asset_data.pop('entity_type_id')]
asset_name = asset_data['name']
asset_field_data = dict(asset_name=asset_name, type=asset_data['entity_type_name'], source_directory=self.source_directory)
try:
asset_field_data.update(template_name.parse(asset_name))
except Exception:
print(f'Warning: Could not parse {asset_name} with template {template_name}')
asset_path = template_file.find(asset_field_data)
if not asset_path:
print(f'Warning: Could not find file for {template_file.format(asset_field_data)}')
continue
asset_path = self.prop_rel_path(asset_path, 'source_directory')
asset_cache_data = dict(
catalog=asset_data['entity_type_name'].title(),
metadata=asset_data.get('data', {}),
description=asset_data['description'],
tags=[],
type=self.data_type,
name=asset_data['name']
)
cache.add_asset_cache(asset_cache_data, filepath=asset_path)
return cache
def draw_prefs(self, layout):
layout.prop(self, 'url', text='Url')
layout.prop(self, 'login', text='Login')
layout.prop(self, 'password', text='Password')

View File

@ -1,4 +1,9 @@
import bpy
from bpy.types import PropertyGroup
from bpy.props import PointerProperty, StringProperty
from vse_toolbox.file_utils import norm_str
class Tracker(PropertyGroup):
pass
pass

View File

@ -1,10 +1,11 @@
# SPDX-License-Identifier: GPL-2.0-or-later
import bpy
import re
from bpy.app.handlers import persistent
from pathlib import Path
import bpy
from bpy.app.handlers import persistent
from vse_toolbox.bl_utils import get_scene_settings, get_strip_settings
from vse_toolbox.constants import SOUND_SUFFIXES
@ -122,9 +123,31 @@ def set_channels():
for i, c in enumerate(items.keys(), start=1):
scn.sequence_editor.channels[i].name = c.title()
def render_strips(strips):
def get_strip_render_path(strip, template):
return template.format(strip_name=strip.name, ext=Path(scn.render.frame_path()).suffix)
def render_strips(strips, template):
scn = bpy.context.scene
scene_start = scn.frame_start
scene_end = scn.frame_end
for strip in strips:
print(strip.name)
#print(render_template, strip.name, path)
scn.frame_start = strip.frame_final_start
scn.frame_end = strip.frame_final_end - 1
## render animatic
#strip_render_path = render_template.format(strip_name=strip.name, ext=Path(scn.render.frame_path()).suffix)
scn.render.filepath = get_strip_render_path(strip, template)
#print(scn.render.filepath)
print(f'Render Strip to {scn.render.filepath}')
#bpy.ops.render.render(animation=True)
bpy.ops.render.opengl(animation=True, sequencer=True)
scn.frame_start = scene_start
scn.frame_end = scene_end
def import_edit(filepath, adapter="cmx_3600", clean_sequencer=False):
import opentimelineio as otio