rewrite import_shots and cleanup
This commit is contained in:
+21
-4
@@ -40,15 +40,26 @@ class VSETB_OT_load_settings(Operator):
|
||||
def execute(self, context):
|
||||
prefs = get_addon_prefs()
|
||||
settings = get_scene_settings()
|
||||
project = settings.active_project
|
||||
|
||||
if not prefs.config_path:
|
||||
return {'FINISHED'}
|
||||
return {'CANCELLED'}
|
||||
|
||||
addon_config = read_file(os.path.expandvars(prefs.config_path))
|
||||
|
||||
if not addon_config:
|
||||
return {'CANCELLED'}
|
||||
|
||||
addon_config['trackers'] = addon_config.get('trackers')
|
||||
trackers = addon_config.pop('trackers')
|
||||
trackers_config = addon_config.pop('trackers')
|
||||
for tracker_config in trackers_config:
|
||||
tracker_name = norm_str(tracker_config.pop('name'))
|
||||
|
||||
if not hasattr(prefs.trackers, tracker_name):
|
||||
continue
|
||||
|
||||
tracker = getattr(prefs.trackers, tracker_name)
|
||||
for k, v in tracker_config.items():
|
||||
setattr(tracker, k, v)
|
||||
|
||||
addon_config['spreadsheet_export'] = addon_config.get('spreadsheet_export', {})
|
||||
spreadsheet_export_config = addon_config.pop('spreadsheet_export')
|
||||
@@ -57,10 +68,15 @@ class VSETB_OT_load_settings(Operator):
|
||||
spreadsheet_import_config = addon_config.pop('spreadsheet_import')
|
||||
|
||||
project_name = addon_config.get('project_name')
|
||||
if project_name:
|
||||
if project_name not in settings.projects:
|
||||
project = settings.projects.add()
|
||||
project.name = project_name
|
||||
settings.project_name = project_name
|
||||
#if project_name and project_name in settings.projects:
|
||||
# settings.project_name = project_name
|
||||
|
||||
# Project Properties
|
||||
project = settings.active_project
|
||||
for k, v in addon_config.items():
|
||||
try:
|
||||
setattr(project, k, v)
|
||||
@@ -132,6 +148,7 @@ class VSETB_OT_load_settings(Operator):
|
||||
except Exception:
|
||||
print(f'Could not set option {k} with value {v} to spreadsheet')
|
||||
|
||||
self.report({"INFO"}, 'Settings loaded with sucess')
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ class VSETB_OT_render(Operator):
|
||||
if project.render_sequence:
|
||||
print('Render Sequences...')
|
||||
for strip in get_strips(channel='Sequences', selected_only=project.render_selected_only):
|
||||
print(strip.name)
|
||||
#print(strip.name)
|
||||
strip_settings = strip.vsetb_strip_settings
|
||||
strip_data = {**format_data, **strip_settings.format_data}
|
||||
|
||||
|
||||
+351
-43
@@ -1,5 +1,9 @@
|
||||
|
||||
from pathlib import Path
|
||||
from os.path import expandvars
|
||||
import re
|
||||
import glob
|
||||
from tempfile import gettempdir
|
||||
|
||||
import bpy
|
||||
from bpy.types import Operator, UIList
|
||||
@@ -9,11 +13,11 @@ from vse_toolbox.constants import (EDITS, EDIT_SUFFIXES, MOVIES, MOVIE_SUFFIXES,
|
||||
SOUNDS, SOUND_SUFFIXES)
|
||||
|
||||
from vse_toolbox.sequencer_utils import (clean_sequencer, import_edit, import_movie,
|
||||
import_sound, get_strips, get_channel_index)
|
||||
import_sound, get_strips, get_channel_index, get_empty_channel, scale_clip_to_fit)
|
||||
|
||||
from vse_toolbox.bl_utils import get_scene_settings
|
||||
from vse_toolbox.file_utils import install_module
|
||||
|
||||
from vse_toolbox.bl_utils import (get_scene_settings, get_addon_prefs, get_scene_settings)
|
||||
from vse_toolbox.file_utils import install_module, parse, find_last
|
||||
#from vse_toolbox.template import Template
|
||||
|
||||
class VSETB_OT_auto_select_files(Operator):
|
||||
bl_idname = "vse_toolbox.auto_select_files"
|
||||
@@ -194,15 +198,26 @@ class VSETB_UL_import_task(UIList):
|
||||
def draw_item(self, context, layout, data, item, icon, active_data,
|
||||
active_propname, index):
|
||||
|
||||
layout.separator(factor=0.5)
|
||||
layout.prop(item, 'import_enabled', text='')
|
||||
layout.label(text=item.name)
|
||||
|
||||
class VSETB_OT_import_shots(Operator):
|
||||
bl_idname = "vse_toolbox.import_shots"
|
||||
bl_label = "Import Shots"
|
||||
bl_description = "Import Shots for disk or tracker"
|
||||
|
||||
def get_task_items(self, context):
|
||||
settings = get_scene_settings()
|
||||
project = settings.active_project
|
||||
|
||||
return [(t, t, '') for t in project.task_types.keys()]
|
||||
class VSETB_OT_select_task(Operator):
|
||||
bl_idname = "vse_toolbox.select_task"
|
||||
bl_label = "Select Task"
|
||||
bl_description = "Select Task"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
bl_property = "task"
|
||||
|
||||
task: EnumProperty(name="My Search", items=get_task_items)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return True
|
||||
@@ -212,76 +227,369 @@ class VSETB_OT_import_shots(Operator):
|
||||
settings = get_scene_settings()
|
||||
project = settings.active_project
|
||||
|
||||
from gadget import Project
|
||||
project.task_types[self.task].import_enabled = True
|
||||
|
||||
p = Project.from_env()
|
||||
p.shots.fetch()
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
context.window_manager.invoke_search_popup(self)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class VSETB_OT_unselect_task(Operator):
|
||||
bl_idname = "vse_toolbox.unselect_task"
|
||||
bl_label = "Unselect Task"
|
||||
bl_description = "Unselect Task"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
task : StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
scn = context.scene
|
||||
settings = get_scene_settings()
|
||||
project = settings.active_project
|
||||
|
||||
project.task_types[self.task].import_enabled = False
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
def get_sequence_items(self, context):
|
||||
settings = get_scene_settings()
|
||||
project = settings.active_project
|
||||
|
||||
return [(t, t, '') for t in project.sequences.keys()]
|
||||
class VSETB_OT_select_sequence(Operator):
|
||||
bl_idname = "vse_toolbox.select_sequence"
|
||||
bl_label = "Select Sequence"
|
||||
bl_description = "Select Sequence"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
bl_property = "sequence"
|
||||
|
||||
sequence: EnumProperty(name="My Search", items=get_sequence_items)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
scn = context.scene
|
||||
settings = get_scene_settings()
|
||||
project = settings.active_project
|
||||
|
||||
project.sequences[self.sequence].import_enabled = True
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
context.window_manager.invoke_search_popup(self)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class VSETB_OT_unselect_sequence(Operator):
|
||||
bl_idname = "vse_toolbox.unselect_sequence"
|
||||
bl_label = "Unselect sequence"
|
||||
bl_description = "Unselect sequence"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
sequence : StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
scn = context.scene
|
||||
settings = get_scene_settings()
|
||||
project = settings.active_project
|
||||
|
||||
project.sequences[self.sequence].import_enabled = False
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
class VSETB_OT_import_shots(Operator):
|
||||
bl_idname = "vse_toolbox.import_shots"
|
||||
bl_label = "Import Shots"
|
||||
bl_description = "Import Shots for disk or tracker"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return get_scene_settings().active_project
|
||||
|
||||
def set_sequencer_channels(self, task_types):
|
||||
scn = bpy.context.scene
|
||||
channels = ['Shots', 'Sequences', 'Stamps']
|
||||
#channel_index = len(task_types * 3) + len(channels) + 1
|
||||
|
||||
channel_index = 1
|
||||
|
||||
for task_type in task_types:
|
||||
audio_channel = scn.sequence_editor.channels[channel_index]
|
||||
audio_channel.name = f'{task_type} Audio'
|
||||
audio_channel.mute = (task_type != task_types[-1])
|
||||
|
||||
video_channel = scn.sequence_editor.channels[channel_index+1]
|
||||
video_channel.name = f'{task_type} Video'
|
||||
|
||||
tasks = [t for t in project.task_types if t.import_enabled]
|
||||
for i, task_type in enumerate(tasks):
|
||||
channel_index = 9 + i
|
||||
channel_index += 3
|
||||
|
||||
scn.sequence_editor.channels[channel_index].name = task_type.name
|
||||
for channel in channels:
|
||||
scn.sequence_editor.channels[channel_index].name = channel
|
||||
|
||||
channel_index += 1
|
||||
|
||||
# Create Channels:
|
||||
scn.sequence_editor.channels[9]
|
||||
def get_preview_dir(self):
|
||||
preview_dir = Path(bpy.app.tempdir, 'previews')
|
||||
if bpy.data.filepath:
|
||||
preview_dir = Path(bpy.data.filepath).parent / 'previews'
|
||||
return preview_dir
|
||||
|
||||
for strip in get_strips('Shots'):
|
||||
for i, task_type in enumerate(tasks):
|
||||
shot = p.shots[strip.name]
|
||||
versions = shot.tasks[task_type.name].outputs[0].versions.fetch()
|
||||
def download_preview(self, task_type, shot):
|
||||
prefs = get_addon_prefs()
|
||||
tracker = prefs.tracker
|
||||
|
||||
if versions:
|
||||
print(versions[-1])
|
||||
|
||||
imported_strip = import_movie(versions[-1].path)
|
||||
imported_strip.frame_start = strip.frame_start
|
||||
task = tracker.get_task(task_type.id or task_type.name, entity=shot)
|
||||
last_comment = tracker.get_last_comment_with_preview(task)
|
||||
if not last_comment:
|
||||
return
|
||||
|
||||
if imported_strip.frame_final_duration != strip.frame_final_duration:
|
||||
print(f'strip {strip.name} has different duration')
|
||||
imported_strip.color_tag = 'COLOR_03'
|
||||
shot_name = shot['name']
|
||||
sequence_name = f"{shot['sequence_name']}_"
|
||||
if shot_name.startswith(sequence_name):
|
||||
shot_name = shot_name.replace(sequence_name, '', 1)
|
||||
|
||||
preview_dir = self.get_preview_dir()
|
||||
|
||||
filepath = Path(preview_dir, f'{sequence_name}{shot_name}_{task_type.name}')
|
||||
filepath.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
last_preview = last_comment['previews'][0]
|
||||
tracker.download_preview_file(last_preview, str(filepath))
|
||||
|
||||
return filepath
|
||||
|
||||
def conform_render(self, clip):
|
||||
scn = bpy.context.scene
|
||||
scn.render.resolution_x = clip.elements[0].orig_width
|
||||
scn.render.resolution_y = clip.elements[0].orig_height
|
||||
scn.render.fps = int(clip.elements[0].orig_fps)
|
||||
|
||||
scn.view_settings.view_transform = 'Standard'
|
||||
|
||||
def find_shot_preview(self, sequence, shot_name, task_type):
|
||||
settings = get_scene_settings()
|
||||
project = settings.active_project
|
||||
import_shots = project.import_shots
|
||||
|
||||
pattern = Path(
|
||||
import_shots.shot_folder_template,
|
||||
import_shots.import_video_template)
|
||||
|
||||
# Normalize name in snake_case for now
|
||||
sequence = sequence.name.lower().replace(' ', '_')
|
||||
shot = parse(project.shot_template, shot_name)['shot']
|
||||
task = task_type.name.lower().replace(' ', '_')
|
||||
|
||||
return find_last(pattern, sequence=sequence, shot=shot, task=task)
|
||||
|
||||
def execute(self, context):
|
||||
scn = context.scene
|
||||
settings = get_scene_settings()
|
||||
project = settings.active_project
|
||||
import_shots = project.import_shots
|
||||
|
||||
prefs = get_addon_prefs()
|
||||
tracker = prefs.tracker
|
||||
tracker.admin_connect()
|
||||
|
||||
task_types = [t for t in project.task_types if t.import_enabled]
|
||||
sequences = [s for s in project.sequences if s.import_enabled]
|
||||
|
||||
conformed = False
|
||||
|
||||
self.set_sequencer_channels([t.name for t in task_types])
|
||||
frame_index = 1
|
||||
for sequence in sequences:
|
||||
shots_data = tracker.get_shots(sequence=sequence.id)
|
||||
sequence_start = frame_index
|
||||
for shot_data in shots_data:
|
||||
frames = int(shot_data['nb_frames'])
|
||||
|
||||
strip = scn.sequence_editor.sequences.new_effect(
|
||||
name=shot_data['name'],
|
||||
type='COLOR',
|
||||
channel=get_channel_index('Shots'),
|
||||
frame_start=frame_index,
|
||||
frame_end=frame_index + frames
|
||||
)
|
||||
strip.blend_alpha = 0
|
||||
strip.color = (0.5, 0.5, 0.5)
|
||||
|
||||
for task_type in task_types:
|
||||
if import_shots.import_source == 'DISK':
|
||||
preview = self.find_shot_preview(sequence, shot_data['name'], task_type)
|
||||
#print(videos)
|
||||
#return {"FINISHED"}
|
||||
|
||||
imported_strip.frame_final_end = strip.frame_final_end
|
||||
else:
|
||||
preview = self.download_preview(task_type, shot_data)
|
||||
|
||||
imported_strip.channel = get_channel_index(task_type.name)
|
||||
print(get_channel_index(task_type.name), imported_strip.channel)
|
||||
else:
|
||||
print(f'No movie for {strip.name} of task {task_type.name}')
|
||||
if not preview:
|
||||
print(f'No preview found for shot {shot_data["name"]}')
|
||||
continue
|
||||
|
||||
print(f'Loading Preview from {preview}')
|
||||
|
||||
# Load Video
|
||||
channel_index = get_channel_index(f'{task_type.name} Video')
|
||||
video_clip = import_movie(preview)
|
||||
video_clip.frame_start = frame_index
|
||||
video_clip.channel = channel_index
|
||||
|
||||
# for task_type in tasks:
|
||||
# for strip in get_strips(task_type.name):
|
||||
# strip.channel = get_channel_index(task_type.name)
|
||||
if not conformed:
|
||||
self.conform_render(video_clip)
|
||||
conformed = True
|
||||
|
||||
scale_clip_to_fit(video_clip)
|
||||
|
||||
# Load Audio
|
||||
channel_index = get_channel_index(f'{task_type.name} Audio')
|
||||
audio_clip = import_sound(preview, frame_start=frame_index,
|
||||
frame_end=video_clip.frame_final_end)
|
||||
audio_clip.channel = channel_index
|
||||
|
||||
frame_index += frames
|
||||
|
||||
strip = scn.sequence_editor.sequences.new_effect(
|
||||
name=sequence.name,
|
||||
type='COLOR',
|
||||
channel=get_channel_index('Sequences'),
|
||||
frame_start=sequence_start,
|
||||
frame_end=frame_index
|
||||
)
|
||||
strip.blend_alpha = 0
|
||||
strip.color = (0.25, 0.25, 0.25)
|
||||
|
||||
scn.frame_start = 1
|
||||
scn.frame_end = frame_index -1
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def draw(self, context):
|
||||
settings = get_scene_settings()
|
||||
project = settings.active_project
|
||||
import_shots = project.import_shots
|
||||
|
||||
layout = self.layout
|
||||
|
||||
col = layout.column(align=False)
|
||||
col.use_property_split = True
|
||||
col.use_property_decorate = False
|
||||
|
||||
row = col.row(align=True)
|
||||
row.prop(project, "import_source", text='Source', expand=True)
|
||||
row.prop(import_shots, "import_source", text='Videos Source', expand=True)
|
||||
|
||||
if import_shots.import_source == 'DISK':
|
||||
#col.prop(import_shots, "sequence_dir_template", text='Sequence Dir')
|
||||
col.prop(import_shots, "shot_folder_template", text='Shot Folder')
|
||||
col.prop(import_shots, "import_video_template", text='Video')
|
||||
col.separator()
|
||||
else:
|
||||
col.prop(import_shots, "previews_folder", text='Previews Folder')
|
||||
col.separator()
|
||||
#if bpy.data.filepath:
|
||||
#col.label(text=f' {self.get_preview_dir()}')
|
||||
#else:
|
||||
# col.label(icon="ERROR", text="Save your Blender to keep the previews")
|
||||
|
||||
row = col.row(align=True)
|
||||
row.prop(project, 'import_task', text='Import Tasks')
|
||||
row.prop(import_shots, 'import_task', text='Import Tasks')
|
||||
row.operator("vse_toolbox.select_task", text='', icon='ADD')
|
||||
|
||||
if project.import_task == 'SELECTED':
|
||||
col.use_property_split = False
|
||||
col.template_list("VSETB_UL_import_task", "import_task", project, "task_types", project, "task_type_index", rows=8)
|
||||
tasks = [t for t in project.task_types if t.import_enabled]
|
||||
|
||||
if import_shots.import_task == "FROM_LIST":
|
||||
if tasks:
|
||||
split = col.split(factor=0.4)
|
||||
split.row()
|
||||
box = split.box()
|
||||
box_col = box.column(align=True)
|
||||
|
||||
for task_type in tasks:
|
||||
row = box_col.row(align=True)
|
||||
sub = row.row(align=True)
|
||||
sub.enabled = False
|
||||
sub.alignment = 'LEFT'
|
||||
sub.scale_x = 0.15
|
||||
sub.prop(task_type, 'color', text='')
|
||||
|
||||
op = row.operator("vse_toolbox.unselect_task", text=task_type.name)
|
||||
op.task = task_type.name
|
||||
|
||||
row.separator(factor=0.5)
|
||||
op = row.operator("vse_toolbox.unselect_task", text='', icon='REMOVE', emboss=False)
|
||||
op.task = task_type.name
|
||||
else:
|
||||
split = col.split(factor=0.4)
|
||||
split.row()
|
||||
row = split.row()
|
||||
row.label(icon="ERROR")
|
||||
row.label(text='Add at least one task')
|
||||
|
||||
# Choose Sequences
|
||||
row = col.row(align=True)
|
||||
row.prop(import_shots, 'import_sequence', text='Import Sequences')
|
||||
row.operator("vse_toolbox.select_sequence", text='', icon='ADD')
|
||||
|
||||
sequences = [s for s in project.sequences if s.import_enabled]
|
||||
if import_shots.import_sequence == "FROM_LIST":
|
||||
if sequences:
|
||||
split = col.split(factor=0.4)
|
||||
split.row()
|
||||
box = split.box()
|
||||
box_col = box.column(align=True)
|
||||
|
||||
for sequence in sequences:
|
||||
row = box_col.row(align=True)
|
||||
op = row.operator("vse_toolbox.unselect_sequence", text=sequence.name)
|
||||
op.sequence = sequence.name
|
||||
|
||||
row.separator(factor=0.5)
|
||||
op = row.operator("vse_toolbox.unselect_sequence", text='', icon='REMOVE', emboss=False)
|
||||
op.sequence = sequence.name
|
||||
else:
|
||||
split = col.split(factor=0.4)
|
||||
split.row()
|
||||
row = split.row()
|
||||
row.label(icon="ERROR")
|
||||
row.label(text='Add at least one Sequence')
|
||||
|
||||
def invoke(self, context, event):
|
||||
scn = context.scene
|
||||
settings = get_scene_settings()
|
||||
project = settings.active_project
|
||||
|
||||
tmp_dir = Path(gettempdir(), 'reviews')
|
||||
|
||||
if bpy.data.filepath and Path(project.import_shots.previews_folder) == tmp_dir:
|
||||
tmp_dir = '//sources'
|
||||
|
||||
if not bpy.data.filepath and project.import_shots.previews_folder == '//sources':
|
||||
project.import_shots.previews_folder = str(tmp_dir)
|
||||
|
||||
# if not bpy.data.filepath:
|
||||
# self.report({"ERROR"}, "Save your Blender file first")
|
||||
# return {"CANCELLED"}
|
||||
|
||||
return context.window_manager.invoke_props_dialog(self)
|
||||
return context.window_manager.invoke_props_dialog(self, width=400)
|
||||
|
||||
def check(self, context):
|
||||
return True
|
||||
|
||||
|
||||
classes = (
|
||||
VSETB_OT_select_sequence,
|
||||
VSETB_OT_unselect_sequence,
|
||||
VSETB_OT_unselect_task,
|
||||
VSETB_OT_select_task,
|
||||
VSETB_UL_import_task,
|
||||
VSETB_OT_auto_select_files,
|
||||
VSETB_OT_import_files,
|
||||
|
||||
+197
-27
@@ -1,4 +1,5 @@
|
||||
from os.path import expandvars
|
||||
from os.path import expandvars, abspath
|
||||
from pathlib import Path
|
||||
import bpy
|
||||
from bpy.types import Operator
|
||||
from bpy.props import (BoolProperty, StringProperty)
|
||||
@@ -7,6 +8,8 @@ from vse_toolbox.sequencer_utils import (get_strips, rename_strips, set_channels
|
||||
get_channel_index, new_text_strip, get_strip_at, get_channel_name)
|
||||
|
||||
from vse_toolbox.bl_utils import get_scene_settings, get_strip_settings
|
||||
from vse_toolbox.constants import REVIEW_TEMPLATE_BLEND
|
||||
from shutil import copy2
|
||||
|
||||
|
||||
class VSETB_OT_rename(Operator):
|
||||
@@ -17,8 +20,7 @@ class VSETB_OT_rename(Operator):
|
||||
|
||||
#template : StringProperty(name="Strip Name", default="")
|
||||
#increment : IntProperty(name="Increment", default=0)
|
||||
channel_name : StringProperty(name="Channel Name", default="")
|
||||
selected_only : BoolProperty(name="Selected Only", default=False)
|
||||
selected_only : BoolProperty(name="Selected Only", default=True)
|
||||
#start_number : IntProperty(name="Start Number", default=0, min=0)
|
||||
#by_sequence : BoolProperty(
|
||||
# name="Reset By Sequence",
|
||||
@@ -29,7 +31,8 @@ class VSETB_OT_rename(Operator):
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
settings = get_scene_settings()
|
||||
return settings.active_project
|
||||
strip = context.active_sequence_strip
|
||||
return settings.active_project and get_channel_name(strip) in ('Shots', 'Sequences')
|
||||
|
||||
def invoke(self, context, event):
|
||||
scn = context.scene
|
||||
@@ -43,39 +46,62 @@ class VSETB_OT_rename(Operator):
|
||||
settings = get_scene_settings()
|
||||
project = settings.active_project
|
||||
|
||||
episode = project.episode_name
|
||||
sequence = str(project.sequence_start_number).zfill(project.sequence_padding)
|
||||
shot = str(project.shot_start_number).zfill(project.shot_padding)
|
||||
|
||||
strip = context.active_sequence_strip
|
||||
channel_name = get_channel_name(strip)
|
||||
|
||||
col = layout.column()
|
||||
col.use_property_split = True
|
||||
col.use_property_decorate = False
|
||||
|
||||
if self.channel_name == 'Shots':
|
||||
if channel_name == 'Shots':
|
||||
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, 'shot_padding', text='Padding')
|
||||
col.prop(project, 'reset_by_sequence')
|
||||
elif self.channel_name == 'Sequences':
|
||||
|
||||
|
||||
elif 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')
|
||||
col.prop(project, 'sequence_padding', text='Padding')
|
||||
|
||||
col.prop(self, 'selected_only')
|
||||
|
||||
if channel_name == 'Shots':
|
||||
label = project.shot_template.format(episode=episode, sequence=sequence, shot=shot)
|
||||
elif channel_name == 'Sequences':
|
||||
label = project.sequence_template.format(episode=episode, sequence=sequence)
|
||||
|
||||
col.label(text=f'Renaming {label}')
|
||||
|
||||
def execute(self, context):
|
||||
scn = context.scene
|
||||
settings = get_scene_settings()
|
||||
project = settings.active_project
|
||||
|
||||
strips = get_strips(channel=self.channel_name, selected_only=self.selected_only)
|
||||
if self.channel_name == 'Shots':
|
||||
strip = context.active_sequence_strip
|
||||
channel_name = get_channel_name(strip)
|
||||
|
||||
strips = get_strips(channel=channel_name, selected_only=self.selected_only)
|
||||
if 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
|
||||
by_sequence=project.reset_by_sequence,
|
||||
padding=project.shot_padding
|
||||
)
|
||||
|
||||
if self.channel_name == 'Sequences':
|
||||
if channel_name == 'Sequences':
|
||||
rename_strips(strips,
|
||||
template=project.sequence_template,
|
||||
increment=project.sequence_increment, start_number=project.sequence_start_number
|
||||
increment=project.sequence_increment, start_number=project.sequence_start_number,
|
||||
padding=project.sequence_padding
|
||||
)
|
||||
|
||||
return {"FINISHED"}
|
||||
@@ -180,10 +206,10 @@ class VSETB_OT_set_stamps(Operator):
|
||||
font_size=font_size, y=margin, box_margin=box_margin, select=True, box_color=(0, 0, 0, 0.5))
|
||||
|
||||
# Project Name
|
||||
project_text = '{project_name}'
|
||||
project_text = '{project}'
|
||||
if project.type == 'TVSHOW':
|
||||
project_text = '{project_name} / {episode_name}'
|
||||
project_strip_stamp = new_text_strip('project_name_stamp', channel=1, **stamp_params,
|
||||
project_text = '{project} / ep{episode}'
|
||||
project_strip_stamp = new_text_strip('project_stamp', channel=1, **stamp_params,
|
||||
text=project_text, x=0.01, align_x='LEFT', align_y='BOTTOM')
|
||||
|
||||
project_strip_stamp.crop.max_x = crop_x * 2
|
||||
@@ -191,16 +217,16 @@ class VSETB_OT_set_stamps(Operator):
|
||||
|
||||
# Shot Name
|
||||
|
||||
shot_strip_stamp = new_text_strip('shot_name_stamp', channel=2, **stamp_params,
|
||||
text='{sequence_name} / {shot_name}', align_y='BOTTOM')
|
||||
shot_strip_stamp = new_text_strip('shot_stamp', channel=2, **stamp_params,
|
||||
text='sq{sequence} / sh{shot}', align_y='BOTTOM')
|
||||
|
||||
shot_strip_stamp.crop.min_x = crop_x
|
||||
shot_strip_stamp.crop.max_x = crop_x
|
||||
shot_strip_stamp.crop.max_y = crop_max_y
|
||||
|
||||
# Frame Range
|
||||
frame_strip_stamp = new_text_strip('frame_range_stamp', channel=3, **stamp_params,
|
||||
text='{shot_frame} / {shot_duration}', x=0.99, align_x='RIGHT', align_y='BOTTOM')
|
||||
# Frame
|
||||
frame_strip_stamp = new_text_strip('frame_stamp', channel=3, **stamp_params,
|
||||
text='{shot_frame} / {shot_duration} {timecode}', x=0.99, align_x='RIGHT', align_y='BOTTOM')
|
||||
|
||||
frame_strip_stamp.crop.min_x = crop_x *2
|
||||
frame_strip_stamp.crop.max_y = crop_max_y
|
||||
@@ -269,10 +295,11 @@ class VSETB_OT_next_shot(Operator):
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
class VSETB_OT_open_shot_dir(Operator):
|
||||
bl_idname = "vse_toolbox.open_shot_dir"
|
||||
bl_label = "Open Shot Dir"
|
||||
bl_description = "Open Shot Dir"
|
||||
|
||||
class VSETB_OT_open_shot_folder(Operator):
|
||||
bl_idname = "vse_toolbox.open_shot_folder"
|
||||
bl_label = "Open Shot Folder"
|
||||
bl_description = "Open Shot Folder"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
@classmethod
|
||||
@@ -289,13 +316,154 @@ class VSETB_OT_open_shot_dir(Operator):
|
||||
|
||||
format_data = {**settings.format_data, **project.format_data, **strip_settings.format_data}
|
||||
|
||||
shot_dir_template = expandvars(project.shot_dir_template)
|
||||
shot_dir_path = shot_dir_template.format(**format_data)
|
||||
bpy.ops.wm.path_open(filepath=shot_dir_path)
|
||||
shot_folder_template = expandvars(project.import_shots.shot_folder_template)
|
||||
shot_folder_path = shot_folder_template.format(**format_data)
|
||||
bpy.ops.wm.path_open(filepath=shot_folder_path)
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class VSETB_OT_collect_files(Operator):
|
||||
bl_idname = "vse_toolbox.collect_files"
|
||||
bl_label = "Collect Files"
|
||||
bl_description = "Collect Files"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
collect_folder: StringProperty(
|
||||
name="Collect Folder", default="//sources", subtype='DIR_PATH')
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if bpy.data.is_saved:
|
||||
return True
|
||||
|
||||
cls.poll_message_set('Save the blend to collect files')
|
||||
|
||||
def execute(self, context):
|
||||
strip = context.active_sequence_strip
|
||||
settings = get_scene_settings()
|
||||
project = settings.active_project
|
||||
|
||||
|
||||
strips = [s for s in context.scene.sequence_editor.sequences_all if s.type in ('MOVIE', 'SOUND')]
|
||||
context.window_manager.progress_begin(0, len(strips))
|
||||
|
||||
for i, strip in enumerate(strips):
|
||||
context.window_manager.progress_update(i)
|
||||
|
||||
if strip.type == 'MOVIE':
|
||||
src_path = strip.filepath
|
||||
elif strip.type == 'SOUND':
|
||||
src_path = strip.sound.filepath
|
||||
|
||||
src_path = Path(abspath(bpy.path.abspath(src_path)))
|
||||
dst_path = Path(bpy.path.abspath(self.collect_folder), src_path.name)
|
||||
|
||||
if src_path == dst_path:
|
||||
continue
|
||||
|
||||
dst_path.parent.mkdir(exist_ok=True, parents=True)
|
||||
|
||||
print(f'Copy file from {src_path} to {dst_path}')
|
||||
copy2(str(src_path), str(dst_path))
|
||||
|
||||
rel_path = bpy.path.relpath(str(dst_path))
|
||||
if len(Path(rel_path).as_posix()) < len(dst_path.as_posix()):
|
||||
dst_path = rel_path
|
||||
|
||||
if strip.type == 'MOVIE':
|
||||
strip.filepath = str(dst_path)
|
||||
elif strip.type == 'SOUND':
|
||||
strip.sound.filepath = str(dst_path)
|
||||
|
||||
context.window_manager.progress_end()
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
def invoke(self, context, event):
|
||||
scn = context.scene
|
||||
settings = get_scene_settings()
|
||||
|
||||
return context.window_manager.invoke_props_dialog(self)
|
||||
|
||||
|
||||
class WM_OT_split_view(Operator):
|
||||
"""Toggle Split sequencer view"""
|
||||
|
||||
bl_idname = "wm.split_view"
|
||||
bl_label = "Split View"
|
||||
|
||||
def get_preview_areas(self, context):
|
||||
return [
|
||||
x for x in context.screen.areas
|
||||
if x.type == "SEQUENCE_EDITOR" and x.spaces[0].view_type == "PREVIEW"
|
||||
]
|
||||
|
||||
def invoke(self, context, event):
|
||||
preview_areas = self.get_preview_areas(context)
|
||||
|
||||
if not preview_areas:
|
||||
return {"CANCELLED"}
|
||||
|
||||
scn = context.scene
|
||||
video_channels = [i for i, c in enumerate(scn.sequence_editor.channels) if 'Video' in c.name]
|
||||
|
||||
if len(video_channels) == 2 and len(preview_areas) == 1:
|
||||
# Split area
|
||||
with bpy.context.temp_override(area=preview_areas[0]):
|
||||
bpy.ops.screen.area_split(direction="VERTICAL")
|
||||
|
||||
# Disable toolbar on right panel
|
||||
# Update areas
|
||||
preview_areas = self.get_preview_areas(context)
|
||||
|
||||
preview_areas[-1].spaces[0].display_channel = video_channels[-1]
|
||||
preview_areas[0].spaces[0].display_channel = video_channels[-2]
|
||||
|
||||
preview_areas[0].spaces[0].show_gizmo_navigate = False
|
||||
preview_areas[-1].spaces[0].show_gizmo_navigate = False
|
||||
# Hide toolbar
|
||||
#preview_areas[0].spaces[0].show_region_toolbar = False
|
||||
|
||||
else:
|
||||
# Give the remaining area to have the left area's channel displayed
|
||||
|
||||
# Show toolbar of remaning area
|
||||
#preview_areas[0].spaces[0].show_region_toolbar = True
|
||||
|
||||
# Join areas
|
||||
# Simulates the mouse position as being between the two areas horizontally
|
||||
# and a bit above the bottom corner vertically
|
||||
cursor_x = int(preview_areas[0].x - (preview_areas[0].x - preview_areas[1].width) / 2)
|
||||
cursor_y = preview_areas[0].y + 10
|
||||
|
||||
bpy.ops.screen.area_join(cursor=(cursor_x, cursor_y))
|
||||
|
||||
preview_areas = self.get_preview_areas(context)
|
||||
|
||||
preview_areas[0].spaces[0].display_channel = 0
|
||||
|
||||
# Force UI update, due to Blender bug, delete when fixed -> https://developer.blender.org/T65529
|
||||
bpy.ops.screen.area_swap(cursor=(preview_areas[0].x, preview_areas[0].y))
|
||||
bpy.ops.screen.area_swap(cursor=(preview_areas[0].x, preview_areas[0].y))
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
'''
|
||||
class VSETB_OT_set_review_workspace(Operator):
|
||||
"""Set Review Workspace"""
|
||||
|
||||
bl_idname = "vse_toolbox.set_workspace"
|
||||
bl_label = "Set Review Workspace"
|
||||
|
||||
|
||||
def execute(self, context):
|
||||
bpy.ops.workspace.append_activate(idname='Review', filepath=str(REVIEW_TEMPLATE_BLEND))
|
||||
|
||||
return {"FINISHED"}
|
||||
'''
|
||||
|
||||
|
||||
addon_keymaps = []
|
||||
def register_keymaps():
|
||||
addon = bpy.context.window_manager.keyconfigs.addon
|
||||
@@ -331,7 +499,9 @@ classes = (
|
||||
VSETB_OT_show_waveform,
|
||||
VSETB_OT_previous_shot,
|
||||
VSETB_OT_next_shot,
|
||||
VSETB_OT_open_shot_dir
|
||||
VSETB_OT_open_shot_folder,
|
||||
VSETB_OT_collect_files,
|
||||
WM_OT_split_view
|
||||
)
|
||||
|
||||
def register():
|
||||
|
||||
+112
-68
@@ -3,6 +3,8 @@ import os
|
||||
from os.path import expandvars
|
||||
from pathlib import Path
|
||||
from pprint import pprint
|
||||
import webbrowser
|
||||
from functools import partial
|
||||
|
||||
import bpy
|
||||
from bpy.types import (Operator, )
|
||||
@@ -59,7 +61,7 @@ class VSETB_OT_load_assets(Operator):
|
||||
prefs = get_addon_prefs()
|
||||
tracker = prefs.tracker
|
||||
|
||||
tracker.connect()
|
||||
tracker.admin_connect()
|
||||
project = settings.active_project
|
||||
project.assets.clear()
|
||||
|
||||
@@ -125,7 +127,7 @@ class VSETB_OT_load_projects(Operator):
|
||||
tracker = prefs.tracker
|
||||
prev_project_name = settings.project_name
|
||||
|
||||
tracker.connect()
|
||||
tracker.admin_connect()
|
||||
|
||||
project_datas = tracker.get_projects()
|
||||
for project_data in sorted(project_datas, key=lambda x: x['name']):
|
||||
@@ -137,7 +139,6 @@ class VSETB_OT_load_projects(Operator):
|
||||
project.name = project_data['name']
|
||||
project.id = project_data['id']
|
||||
|
||||
|
||||
if project.type == 'TVSHOW':
|
||||
episode_datas = tracker.get_episodes(project_data)
|
||||
for episode_data in episode_datas:
|
||||
@@ -154,6 +155,17 @@ class VSETB_OT_load_projects(Operator):
|
||||
for ep in reversed(project.episodes):
|
||||
if ep.name not in ep_names:
|
||||
project.episodes.remove(list(project.episodes).index(ep))
|
||||
else:
|
||||
# Add sequences
|
||||
sequences_data = tracker.get_sequences(project_data)
|
||||
for sequence_data in sequences_data:
|
||||
sequence = project.sequences.get(sequence_data['name'])
|
||||
|
||||
if not sequence:
|
||||
sequence = project.sequences.add()
|
||||
|
||||
sequence.name = sequence_data['name']
|
||||
sequence.id = sequence_data['id']
|
||||
|
||||
project.metadata_types.clear()
|
||||
for metadata_data in tracker.get_metadata_types(project_data):
|
||||
@@ -183,6 +195,7 @@ class VSETB_OT_load_projects(Operator):
|
||||
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']
|
||||
task_type.id = task_type_data['id']
|
||||
task_type.color = self.hex_to_rgb(task_type_data['color'])[:3]
|
||||
|
||||
project.set_shot_tasks()
|
||||
@@ -200,11 +213,11 @@ class VSETB_OT_load_projects(Operator):
|
||||
if project.name not in project_names:
|
||||
settings.projects.remove(list(settings.projects).index(project))
|
||||
|
||||
# Restore previous project
|
||||
settings.project_name = prev_project_name
|
||||
|
||||
bpy.ops.vse_toolbox.load_settings()
|
||||
|
||||
if prev_project_name != '/' and prev_project_name in settings.projects:
|
||||
settings.project_name = prev_project_name
|
||||
|
||||
#if settings.active_project:
|
||||
# settings.active_project.set_strip_metadata()
|
||||
|
||||
@@ -216,7 +229,7 @@ class VSETB_OT_load_projects(Operator):
|
||||
|
||||
class VSETB_OT_new_episode(Operator):
|
||||
bl_idname = "vse_toolbox.new_episode"
|
||||
bl_label = "New Epispde"
|
||||
bl_label = "New Episode"
|
||||
bl_description = "Add new Episode to Project"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
@@ -254,42 +267,12 @@ class VSETB_OT_new_episode(Operator):
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
def get_task_status_items(self, context):
|
||||
settings = get_scene_settings()
|
||||
project = settings.active_project
|
||||
|
||||
status_items = [('CURRENT', 'Current', '')]
|
||||
|
||||
if project:
|
||||
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
|
||||
|
||||
if not project:
|
||||
return [('NONE', 'None', '')]
|
||||
|
||||
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=True)
|
||||
preview_mode : EnumProperty(items=[(m, m.title().replace('_', ' '), '')
|
||||
for m in ('ONLY_NEW', 'REPLACE', 'ADD')])
|
||||
set_main_preview : BoolProperty(default=True)
|
||||
casting : BoolProperty(default=True)
|
||||
custom_data : BoolProperty(default=True)
|
||||
tasks_comment: BoolProperty(default=True)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return True
|
||||
@@ -297,49 +280,66 @@ class VSETB_OT_upload_to_tracker(Operator):
|
||||
def invoke(self, context, event):
|
||||
prefs = get_addon_prefs()
|
||||
settings = get_scene_settings()
|
||||
project = settings.active_project
|
||||
self.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)
|
||||
return context.window_manager.invoke_props_dialog(self, width=350)
|
||||
|
||||
def draw(self, context):
|
||||
scn = context.scene
|
||||
settings = get_scene_settings()
|
||||
upload_to_tracker = self.project.upload_to_tracker
|
||||
|
||||
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.use_property_decorate = False
|
||||
col.prop(upload_to_tracker, 'render_strips', text='Render Strips')
|
||||
if upload_to_tracker.render_strips:
|
||||
col.use_property_split = False
|
||||
col.prop(upload_to_tracker, 'render_strip_template', text='')
|
||||
col.use_property_split = True
|
||||
#else:
|
||||
# col.label(text=f'Source: {self.project.render_video_strip_template}')
|
||||
|
||||
col.separator()
|
||||
col.prop(self, 'casting', text='Casting')
|
||||
col.prop(self, 'custom_data', text='Custom Data')
|
||||
col.prop(self, 'tasks_comment', text='Tasks Comment')
|
||||
col.prop(self, 'set_main_preview', text='Set Main Preview')
|
||||
|
||||
col.prop(upload_to_tracker, 'task', text='Task')
|
||||
col.prop(upload_to_tracker, 'status', text='Status')
|
||||
col.prop(upload_to_tracker, 'comment', text='Comment')
|
||||
row = col.row(heading='Add Preview')
|
||||
row.prop(upload_to_tracker, 'add_preview', text='')
|
||||
row.prop(upload_to_tracker, 'preview_mode', text='')
|
||||
if upload_to_tracker.add_preview and not upload_to_tracker.render_strips:
|
||||
col.use_property_split = False
|
||||
col.prop(self.project, 'render_video_strip_template', text='')
|
||||
col.use_property_split = True
|
||||
|
||||
col.separator()
|
||||
col.prop(upload_to_tracker, 'custom_data', text='Custom Data')
|
||||
col.prop(upload_to_tracker, 'update_frames', text='Update frames')
|
||||
col.prop(upload_to_tracker, 'casting', text='Casting')
|
||||
col.prop(upload_to_tracker, 'tasks_comment', text='Tasks Comment')
|
||||
col.prop(upload_to_tracker, 'set_main_preview', text='Set Main Preview')
|
||||
|
||||
def execute(self, context):
|
||||
#self.report({'ERROR'}, f'Export not implemented yet.')
|
||||
prefs = get_addon_prefs()
|
||||
settings = get_scene_settings()
|
||||
project = settings.active_project
|
||||
upload_to_tracker = self.project.upload_to_tracker
|
||||
|
||||
episode = None
|
||||
if settings.active_episode:
|
||||
episode = settings.active_episode.id
|
||||
|
||||
format_data = {**settings.format_data, **project.format_data}
|
||||
|
||||
format_data = {**settings.format_data, **self.project.format_data}
|
||||
|
||||
tracker = prefs.tracker
|
||||
|
||||
status = self.status
|
||||
status = upload_to_tracker.status
|
||||
if status == 'CURRENT':
|
||||
status = None
|
||||
|
||||
@@ -360,15 +360,19 @@ class VSETB_OT_upload_to_tracker(Operator):
|
||||
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)
|
||||
task = tracker.get_task(upload_to_tracker.task, entity=shot)
|
||||
if not task:
|
||||
task = tracker.new_task(shot, task_type=self.task)
|
||||
task = tracker.new_task(shot, task_type=upload_to_tracker.task)
|
||||
|
||||
preview = None
|
||||
if self.add_preview:
|
||||
if upload_to_tracker.add_preview:
|
||||
|
||||
strip_data = {**format_data, **strip_settings.format_data}
|
||||
preview_template = expandvars(project.render_video_strip_template)
|
||||
if upload_to_tracker.render_strips:
|
||||
preview_template = expandvars(upload_to_tracker.render_strip_template)
|
||||
else:
|
||||
preview_template = expandvars(self.project.render_video_strip_template)
|
||||
|
||||
preview = preview_template.format(**strip_data)
|
||||
preview = Path(os.path.abspath(bpy.path.abspath(preview)))
|
||||
#print(preview)
|
||||
@@ -377,24 +381,41 @@ class VSETB_OT_upload_to_tracker(Operator):
|
||||
preview = None
|
||||
|
||||
elif task.get('last_comment') and task['last_comment']['previews']:
|
||||
if self.preview_mode == 'REPLACE':
|
||||
if upload_to_tracker.preview_mode == 'REPLACE':
|
||||
tracker.remove_comment(task['last_comment'])
|
||||
elif self.preview_mode == 'ONLY_NEW':
|
||||
elif upload_to_tracker.preview_mode == 'ONLY_NEW':
|
||||
preview = None
|
||||
|
||||
if status or preview:
|
||||
tracker.new_comment(task, comment=self.comment, status=status, preview=preview, set_main_preview=self.set_main_preview)
|
||||
comment_data = None
|
||||
if status or comment or preview:
|
||||
comment_data = tracker.new_comment(task, comment=upload_to_tracker.comment, status=status)
|
||||
if preview:
|
||||
print('Upload preview from', preview)
|
||||
preview_data = tracker.new_preview(
|
||||
task=task,
|
||||
comment=comment_data,
|
||||
preview=preview)
|
||||
|
||||
if self.custom_data:
|
||||
description = strip_settings.description
|
||||
tracker.update_data(shot, metadata, frames=strip.frame_final_duration, description=description)
|
||||
if upload_to_tracker.set_main_preview:
|
||||
bpy.app.timers.register(partial(tracker.set_main_preview, preview_data), first_interval=10)
|
||||
|
||||
params = {}
|
||||
if upload_to_tracker.custom_data:
|
||||
params['custom_data'] = metadata
|
||||
params['description'] = strip_settings.description
|
||||
|
||||
if self.casting:
|
||||
if upload_to_tracker.update_frames:
|
||||
params['frames'] = strip.frame_final_duration
|
||||
|
||||
if params:
|
||||
tracker.update_data(shot, **params)
|
||||
|
||||
if upload_to_tracker.casting:
|
||||
casting = [{'asset_id': a.id, 'nb_occurences': a.instance} for a in strip_settings.casting]
|
||||
tracker.update_casting(shot, casting)
|
||||
|
||||
if self.tasks_comment:
|
||||
for task_type in project.task_types:
|
||||
if upload_to_tracker.tasks_comment:
|
||||
for task_type in self.project.task_types:
|
||||
|
||||
task = getattr(strip_settings.tasks, norm_name(task_type.name))
|
||||
tracker_task = tracker.get_task(task_type.name, entity=shot)
|
||||
@@ -405,6 +426,28 @@ class VSETB_OT_upload_to_tracker(Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class VSETB_OT_open_shot_on_tracker(Operator):
|
||||
bl_idname = "vse_toolbox.open_shot_on_tracker"
|
||||
bl_label = "Open Shot on Tracker"
|
||||
bl_description = "Open Shot on Tracker"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
prefs = get_addon_prefs()
|
||||
if prefs.tracker:
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
prefs = get_addon_prefs()
|
||||
tracker = prefs.tracker
|
||||
|
||||
strips = get_strips(channel='Shots', selected_only=True)
|
||||
url = tracker.get_shots_search_url([s.name for s in strips])
|
||||
|
||||
webbrowser.open_new_tab(url)
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
@persistent
|
||||
def set_asset_items(scene=None):
|
||||
ASSET_ITEMS.clear()
|
||||
@@ -420,6 +463,7 @@ classes = (
|
||||
VSETB_OT_new_episode,
|
||||
VSETB_OT_tracker_connect,
|
||||
VSETB_OT_upload_to_tracker,
|
||||
VSETB_OT_open_shot_on_tracker
|
||||
)
|
||||
|
||||
def register():
|
||||
|
||||
Reference in New Issue
Block a user