Files
blender-portable-repo/scripts/addons/blender_kitsu/sqe/opsdata.py
T
2026-03-17 14:58:51 -06:00

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