diff --git a/common_py/src/videoag_common/media_process/ffmpeg_target.py b/common_py/src/videoag_common/media_process/ffmpeg_target.py index fa38a52319e2bcd18377e6f30ae709902806f1dc..74d4b9b299535dc988e49a7224dafad0ba85b811 100644 --- a/common_py/src/videoag_common/media_process/ffmpeg_target.py +++ b/common_py/src/videoag_common/media_process/ffmpeg_target.py @@ -168,18 +168,17 @@ class FFmpegFilterGraphTargetProducer(TargetProducer): process_sha256: str, input_media_by_id: dict[str, "MediumMetadata"] ) -> tuple[str, _I] or None: - sha256 = bytearray(32) + hash_concat = "" intermediate = [] for node in self._ordered_node_list: node_res = node.calculate_current_input_hash(session, lecture, process_sha256, input_media_by_id) if node_res is None: return None node_sha256, node_intermediate = node_res - sha256 = bytearray(x ^ y for x, y in zip(sha256, bytearray.fromhex(node_sha256))) + hash_concat += node_sha256 intermediate.append(node_intermediate) - assert len(sha256) == 32 - return sha256.hex(), intermediate + return hash_sha256(hash_concat), intermediate def create_job_data_to_produce_files(self, session: SessionDb, diff --git a/common_py/src/videoag_common/media_process/jnode/video_slide_jnode.py b/common_py/src/videoag_common/media_process/jnode/video_slide_jnode.py index a78a50d192ddcf804be14012ca0ced8e2d78f616..41bbb185e46d792e799063ccd6612226725fdf52 100644 --- a/common_py/src/videoag_common/media_process/jnode/video_slide_jnode.py +++ b/common_py/src/videoag_common/media_process/jnode/video_slide_jnode.py @@ -9,7 +9,7 @@ from videoag_common.ffmpeg import * from ..ffmpeg_target import JGraphContext from .basic_jnodes import EqualInOutNodeJGraphNode -from ..target import _I +from ..error import MediaProcessException if TYPE_CHECKING: from videoag_common.objects import Lecture, MediumMetadata, MediumFile @@ -95,6 +95,16 @@ class TextVideoSlideRow(VideoSlideRow): raise ValueError(f"Unknown variable '{var_name}'") return lecture_vars[var_name] return self._text_replace_vars(_var_replace) + + def get_used_lecture_variables(self) -> set[str]: + used_vars = set() + + def _var_counter_replace(var_name: str): + used_vars.add(var_name) + return "" + + self._text_replace_vars(_var_counter_replace) + return used_vars class SpacerVideoSlideRow(VideoSlideRow): @@ -115,6 +125,13 @@ class VideoSlide(JsonDataClass): def __post_init__(self): if sum(row.height for row in self.rows) > 100: raise JsonSerializableInitException("Sum of row 'height' values must be <= 100") + + def get_used_lecture_variables(self) -> set[str]: + used_vars = set() + for row in self.rows: + if isinstance(row, TextVideoSlideRow): + used_vars.update(row.get_used_lecture_variables()) + return used_vars class VideoTimePosition(JsonSerializableEnum): @@ -139,7 +156,15 @@ class VideoSlideJGraphNode(EqualInOutNodeJGraphNode): input_media_by_id: dict[str, "MediumMetadata"] ) -> tuple[str, dict[str, str]] or None: lecture_text_vars = get_lecture_text_vars(lecture) - return hash_json_sha256(lecture_text_vars), lecture_text_vars + used_lecture_text_vars = {} + for var_name in self.slide.get_used_lecture_variables(): + val = lecture_text_vars[var_name] + if val is None or val == "": + raise MediaProcessException(f"Lecture text variable '{var_name}' is null or empty. Set a value or don't" + f" use the variable in the video slide") + used_lecture_text_vars[var_name] = val + + return hash_json_sha256(used_lecture_text_vars), used_lecture_text_vars def create_job_data_to_build_filter_graph(self, session: SessionDb,