266 lines
8.4 KiB
Python
266 lines
8.4 KiB
Python
# SPDX-FileCopyrightText: 2021 Blender Studio Tools Authors
|
|
#
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
import re
|
|
from pathlib import Path
|
|
from typing import Any, Dict, List, Tuple, Union, Optional
|
|
from . import pull
|
|
import bpy
|
|
from .. import bkglobals, prefs
|
|
from ..logger import LoggerFactory
|
|
from ..types import Sequence, Task, TaskStatus, Shot, TaskType
|
|
|
|
logger = LoggerFactory.getLogger()
|
|
|
|
_sqe_shot_enum_list: List[Tuple[str, str, str]] = []
|
|
_sqe_not_linked: List[Tuple[str, str, str]] = []
|
|
_sqe_duplicates: List[Tuple[str, str, str]] = []
|
|
_sqe_multi_project: List[Tuple[str, str, str]] = []
|
|
|
|
|
|
def sqe_get_not_linked(self, context):
|
|
return _sqe_not_linked
|
|
|
|
|
|
def sqe_get_duplicates(self, context):
|
|
return _sqe_duplicates
|
|
|
|
|
|
def sqe_get_multi_project(self, context):
|
|
return _sqe_multi_project
|
|
|
|
|
|
def sqe_update_not_linked(context: bpy.types.Context) -> List[Tuple[str, str, str]]:
|
|
"""get all strips that are initialized but not linked yet"""
|
|
enum_list = []
|
|
|
|
if context.selected_sequences:
|
|
strips = context.selected_sequences
|
|
else:
|
|
strips = context.scene.sequence_editor.sequences_all
|
|
|
|
for strip in strips:
|
|
if strip.kitsu.initialized and not strip.kitsu.linked:
|
|
enum_list.append((strip.name, strip.name, ""))
|
|
|
|
return enum_list
|
|
|
|
|
|
def sqe_update_duplicates(context: bpy.types.Context) -> List[Tuple[str, str, str]]:
|
|
"""get all strips that are initialized but not linked yet"""
|
|
enum_list = []
|
|
data_dict = {}
|
|
if context.selected_sequences:
|
|
strips = context.selected_sequences
|
|
else:
|
|
strips = context.scene.sequence_editor.sequences_all
|
|
|
|
# Create data dict that holds all shots ids and the corresponding strips that are linked to it.
|
|
for i in range(len(strips)):
|
|
if strips[i].kitsu.linked:
|
|
# Get shot_id, shot_name, create entry in data_dict if id not existent.
|
|
shot_id = strips[i].kitsu.shot_id
|
|
shot_name = strips[i].kitsu.shot_name
|
|
if shot_id not in data_dict:
|
|
data_dict[shot_id] = {"name": shot_name, "strips": []}
|
|
|
|
# Append i to strips list.
|
|
if strips[i] not in set(data_dict[shot_id]["strips"]):
|
|
data_dict[shot_id]["strips"].append(strips[i])
|
|
|
|
# Comparet to all other strip.
|
|
for j in range(i + 1, len(strips)):
|
|
if shot_id == strips[j].kitsu.shot_id:
|
|
data_dict[shot_id]["strips"].append(strips[j])
|
|
|
|
# Convert in data strucutre for enum property.
|
|
for shot_id, data in data_dict.items():
|
|
if len(data["strips"]) > 1:
|
|
enum_list.append(("", data["name"], shot_id))
|
|
for strip in data["strips"]:
|
|
enum_list.append((strip.name, strip.name, ""))
|
|
|
|
return enum_list
|
|
|
|
|
|
def sqe_update_multi_project(context: bpy.types.Context) -> List[Tuple[str, str, str]]:
|
|
"""get all strips that are initialized but not linked yet"""
|
|
enum_list: List[Tuple[str, str, str]] = []
|
|
data_dict: Dict[str, Any] = {}
|
|
|
|
if context.selected_sequences:
|
|
strips = context.selected_sequences
|
|
else:
|
|
strips = context.scene.sequence_editor.sequences_all
|
|
|
|
# Create data dict that holds project names as key and values the corresponding sequence strips.
|
|
for strip in strips:
|
|
if strip.kitsu.linked:
|
|
project = strip.kitsu.project_name
|
|
if project not in data_dict:
|
|
data_dict[project] = []
|
|
|
|
# Append i to strips list.
|
|
if strip not in set(data_dict[project]):
|
|
data_dict[project].append(strip)
|
|
|
|
# Convert in data strucutre for enum property.
|
|
for project, strips in data_dict.items():
|
|
enum_list.append(("", project, ""))
|
|
for strip in strips:
|
|
enum_list.append((strip.name, strip.name, ""))
|
|
|
|
return enum_list
|
|
|
|
|
|
def resolve_pattern(pattern: str, var_lookup_table: Dict[str, str]) -> str:
|
|
matches = re.findall(r"\<(\w+)\>", pattern)
|
|
matches = list(set(matches))
|
|
# If no variable detected just return value.
|
|
if len(matches) == 0:
|
|
return pattern
|
|
else:
|
|
result = pattern
|
|
for to_replace in matches:
|
|
if to_replace in var_lookup_table:
|
|
to_insert = var_lookup_table[to_replace]
|
|
result = result.replace("<{}>".format(to_replace), to_insert)
|
|
else:
|
|
logger.warning(
|
|
"Failed to resolve variable: %s not defined!", to_replace
|
|
)
|
|
return ""
|
|
return result
|
|
|
|
|
|
def get_shots_enum_for_link_shot_op(
|
|
self: bpy.types.Operator, context: bpy.types.Context
|
|
) -> List[Tuple[str, str, str]]:
|
|
global _sqe_shot_enum_list
|
|
|
|
if not self.sequence_enum:
|
|
return []
|
|
|
|
zseq_active = Sequence.by_id(self.sequence_enum)
|
|
|
|
_sqe_shot_enum_list.clear()
|
|
_sqe_shot_enum_list.extend(
|
|
[(s.id, s.name, s.description or "") for s in zseq_active.get_all_shots()]
|
|
)
|
|
return _sqe_shot_enum_list
|
|
|
|
|
|
def upload_preview(
|
|
context: bpy.types.Context, filepath: Path, task_type: TaskType, comment: str = ""
|
|
) -> None:
|
|
# Get shot by id which is in filename of thumbnail.
|
|
shot_id = filepath.name.split(bkglobals.SPACE_REPLACER)[0]
|
|
shot = Shot.by_id(shot_id)
|
|
|
|
# Find task from task type for that shot, ca be None of no task was added for that task type.
|
|
task = Task.by_name(shot, task_type)
|
|
|
|
if not task:
|
|
# Turns out a entity on the server can have 0 tasks even tough task types exist
|
|
# you have to create a task first before being able to upload a thumbnail.
|
|
task_status = TaskStatus.by_short_name("wip")
|
|
task = Task.new_task(shot, task_type, task_status=task_status)
|
|
else:
|
|
task_status = TaskStatus.by_id(task.task_status_id)
|
|
|
|
# Create a comment, e.G 'Update thumbnail'.
|
|
comment_obj = task.add_comment(task_status, comment=comment)
|
|
|
|
# Add_preview_to_comment.
|
|
task.add_preview_to_comment(comment_obj, filepath.as_posix())
|
|
|
|
logger.info(f"Uploaded preview for shot: {shot.name} under: {task_type.name}")
|
|
|
|
|
|
def init_start_frame_offset(strip: bpy.types.Strip) -> None:
|
|
# Frame start offset.
|
|
offset_start = strip.frame_final_start - strip.frame_start
|
|
# Cast offset start to int, since after Blender 3.3 strip values are floats
|
|
strip.kitsu.frame_start_offset = int(offset_start)
|
|
|
|
|
|
def append_sequence_color(
|
|
context: bpy.types.Context, seq: Sequence
|
|
) -> Optional[Tuple[str, str, str]]:
|
|
"""
|
|
Extend scene.kitsu.sequence_colors property with seq.data['color'] value if it exists.
|
|
"""
|
|
# Pull sequencee color property.
|
|
|
|
if not seq.data:
|
|
logger.info("%s failed to load sequence color. Missing 'data' key")
|
|
return None
|
|
if not "color" in seq.data:
|
|
logger.info("%s failed to load sequence color. Missing data['color'] key")
|
|
return None
|
|
|
|
try:
|
|
item = context.scene.kitsu.sequence_colors[seq.id]
|
|
except:
|
|
item = context.scene.kitsu.sequence_colors.add()
|
|
item.name = seq.id
|
|
logger.info(
|
|
"Added %s to scene.kitsu.seqeuence_colors",
|
|
seq.name,
|
|
)
|
|
finally:
|
|
item.color = tuple(seq.data["color"])
|
|
|
|
return tuple(seq.data["color"])
|
|
|
|
|
|
def push_sequence_color(context: bpy.types.Context, sequence: Sequence) -> None:
|
|
# Updates sequence color and logs.
|
|
try:
|
|
item = context.scene.kitsu.sequence_colors[sequence.id]
|
|
except KeyError:
|
|
logger.info(
|
|
"%s failed to push sequence color. Does not exists in 'context.scene.kitsu.sequence_colors'",
|
|
sequence.name,
|
|
)
|
|
else:
|
|
sequence.update_data({"color": list(item.color)})
|
|
logger.info("%s pushed sequence color", sequence.name)
|
|
|
|
|
|
def create_metadata_strip(
|
|
scene: bpy.types.Scene, name: str, channel, frame_start: int, frame_end: int
|
|
) -> bpy.types.MovieStrip:
|
|
|
|
addon_prefs = prefs.addon_prefs_get(bpy.context)
|
|
strip = scene.sequence_editor.sequences.new_movie(
|
|
name,
|
|
addon_prefs.metadatastrip_file,
|
|
channel,
|
|
frame_start,
|
|
)
|
|
|
|
strip.frame_final_end = frame_end
|
|
|
|
# Set blend alpha.
|
|
strip.blend_alpha = 0
|
|
|
|
init_start_frame_offset(strip)
|
|
|
|
return strip
|
|
|
|
|
|
def link_metadata_strip(
|
|
context, shot: Shot, seq: Sequence, strip: bpy.types.MovieStrip
|
|
) -> bpy.types.MovieStrip:
|
|
# Pull shot meta.
|
|
pull.shot_meta(strip, shot)
|
|
|
|
# Rename strip.
|
|
strip.name = shot.name
|
|
|
|
# Pull sequence color.
|
|
append_sequence_color(context, seq)
|
|
return strip
|