2025-12-01
This commit is contained in:
@@ -0,0 +1,265 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user