From e3bad9371bb5a715ca117e45e4022fdb02530767 Mon Sep 17 00:00:00 2001
From: "robin@ynput.io" <robin@ynput.io>
Date: Mon, 2 Dec 2024 17:03:13 -0500
Subject: [PATCH 1/8] Implement review and reviewable source.

---
 client/ayon_flame/api/plugin.py               | 43 ++++++++++++++++---
 .../plugins/create/create_shot_clip.py        | 38 ++++++++++------
 .../plugins/publish/collect_plate.py          | 16 ++++---
 3 files changed, 71 insertions(+), 26 deletions(-)

diff --git a/client/ayon_flame/api/plugin.py b/client/ayon_flame/api/plugin.py
index d9f11f8..01e99eb 100644
--- a/client/ayon_flame/api/plugin.py
+++ b/client/ayon_flame/api/plugin.py
@@ -92,7 +92,7 @@ class PublishableClip:
     rename_default = False
     hierarchy_default = "{_folder_}/{_sequence_}/{_track_}"
     clip_name_default = "shot_{_trackIndex_:0>3}_{_clipIndex_:0>4}"
-    review_track_default = "< none >"
+    review_source_default = None
     base_product_variant_default = "<track_name>"
     count_from_default = 10
     count_steps_default = 10
@@ -167,8 +167,8 @@ def convert(self):
 
         # if track name is in review track name and also if driving track name
         # is not in review track name: skip tag creation
-        if (self.track_name in self.review_layer) and (
-                self.driving_layer not in self.review_layer):
+        if (self.track_name in self.reviewable_source) and (
+                self.driving_layer not in self.reviewable_source):
             return
 
         # deal with clip name
@@ -253,8 +253,8 @@ def _populate_attributes(self):
             "vSyncOn") or self.vertical_sync_default
         self.driving_layer = self.pre_create_data.get(
             "vSyncTrack") or self.driving_layer_default
-        self.review_track = self.pre_create_data.get(
-            "reviewTrack") or self.review_track_default
+        self.review_source = self.pre_create_data.get(
+            "reviewableSource") or self.review_source_default
         self.audio = self.pre_create_data.get("audio") or False
         self.include_handles = self.pre_create_data.get(
             "includeHandles") or self.include_handles_default
@@ -297,7 +297,7 @@ def _convert_to_marker_data(self):
         """
         # define vertical sync attributes
         hero_track = True
-        self.review_layer = ""
+        self.reviewable_source = ""
 
         if (
             self.vertical_sync and
@@ -317,6 +317,11 @@ def _convert_to_marker_data(self):
 
         if self.pre_create_data:
 
+            # backward compatibility for reviewableSource (2024.12.02)
+            if "reviewTrack" in self.pre_create_data:
+                _value = self.marker_data.pop("reviewTrack")
+                self.marker_data["reviewableSource"] = _value
+
             # driving layer is set as positive match
             if hero_track or self.vertical_sync:
                 # mark review layer
@@ -435,6 +440,32 @@ def _convert_to_marker_data(self):
         # add data to return data dict
         self.marker_data.update(tag_hierarchy_data)
 
+        # add review track only to hero track
+        if hero_track and self.reviewable_source:
+            self.marker_data["reviewTrack"] = self.reviewable_source
+        else:
+            self.marker_data["reviewTrack"] = None
+
+        # add only review related data if reviewable source is set
+        if self.reviewable_source:
+            review_switch = True
+            reviewable_source = self.reviewable_source
+
+            if self.vertical_sync and not hero_track:
+                review_switch = False
+                reviewable_source = False
+
+            if review_switch:
+                self.marker_data["review"] = True
+            else:
+                self.marker_data.pop("review", None)
+
+            if reviewable_source:
+                self.marker_data["reviewableSource"] = reviewable_source
+            else:
+                self.marker_data.pop("reviewableSource", None)
+
+
     def _solve_tag_hierarchy_data(self, hierarchy_formatting_data):
         """ Solve marker data from hierarchy data and templates. """
         # fill up clip name and hierarchy keys
diff --git a/client/ayon_flame/plugins/create/create_shot_clip.py b/client/ayon_flame/plugins/create/create_shot_clip.py
index bc3d604..2b0e515 100644
--- a/client/ayon_flame/plugins/create/create_shot_clip.py
+++ b/client/ayon_flame/plugins/create/create_shot_clip.py
@@ -217,7 +217,7 @@ def _on_value_change(self, event):
             reviewable_source = next(
                 attr_def
                 for attr_def in attr_defs
-                if attr_def.key == "reviewTrack"
+                if attr_def.key == "reviewableSource"
             )
             reviewable_source.enabled = review_value
 
@@ -227,7 +227,10 @@ def get_attr_defs_for_instance(self, instance):
 
         current_sequence = lib.get_current_sequence(lib.CTX.selection)
         if current_sequence is not None:
-            gui_tracks = get_video_track_names(current_sequence)
+            gui_tracks = [
+                {"value": tr_name, "label": f"Track: {tr_name}"}
+                for tr_name in get_video_track_names(current_sequence)
+            ]
         else:
             gui_tracks = []
 
@@ -250,9 +253,9 @@ def get_attr_defs_for_instance(self, instance):
                         default=False,
                     ),
                     EnumDef(
-                        "reviewTrack",
-                        label="Review Track",
-                        tooltip=("Selecting source from review tracks."),
+                        "reviewableSource",
+                        label="Reviewable Source",
+                        tooltip=("Selecting source for reviewable files."),
                         items=gui_tracks,
                         enabled=current_review,
                     ),
@@ -318,7 +321,10 @@ def header_label(text):
 
         current_sequence = lib.get_current_sequence(lib.CTX.selection)
         if current_sequence is not None:
-            gui_tracks = get_video_track_names(current_sequence)
+            gui_tracks = [
+                {"value": tr_name, "label": f"Track: {tr_name}"}
+                for tr_name in get_video_track_names(current_sequence)
+            ]
         else:
             gui_tracks = []
 
@@ -460,11 +466,15 @@ def header_label(text):
                 items=['plate', 'take'],
             ),
             EnumDef(
-                "reviewTrack",
-                label="Use Review Track",
+                "reviewableSource",
+                label="Reviewable Source",
                 tooltip="Generate preview videos on fly, if "
                         "'< none >' is defined nothing will be generated.",
-                items=['< none >'] + gui_tracks,
+                items=[
+                    {"value": None, "label": "< none >"},
+                    {"value": "clip_media", "label": "[ Clip's media ]"},
+                ]
+                + gui_tracks,
             ),
             BoolDef(
                 "export_audio",
@@ -680,10 +690,10 @@ def create(self, product_name, instance_data, pre_create_data):
                         }
                     })
                     # add reviewable source to plate if shot has it
-                    if sub_instance_data.get("reviewTrack"):
+                    if sub_instance_data.get("reviewableSource"):
                         sub_instance_data["creator_attributes"].update({
-                            "reviewTrack": sub_instance_data[
-                                "reviewTrack"],
+                            "reviewableSource": sub_instance_data[
+                                "reviewableSource"],
                             "review": True,
                         })
 
@@ -804,9 +814,9 @@ def _collect_legacy_instance(self, segment, marker_data):
             })
 
             # add reviewable source to plate if shot has it
-            if sub_instance_data.get("reviewTrack") != "< none >":
+            if sub_instance_data.get("reviewableSource") != "< none >":
                 sub_instance_data["creator_attributes"].update({
-                    "reviewTrack": sub_instance_data[
+                    "reviewableSource": sub_instance_data[
                         "reviewTrack"],
                     "review": True,
                 })
diff --git a/client/ayon_flame/plugins/publish/collect_plate.py b/client/ayon_flame/plugins/publish/collect_plate.py
index edf52a6..784e391 100644
--- a/client/ayon_flame/plugins/publish/collect_plate.py
+++ b/client/ayon_flame/plugins/publish/collect_plate.py
@@ -31,14 +31,18 @@ def process(self, instance):
 
         review_switch = instance.data["creator_attributes"].get(
             "review")
-        review_track = instance.data["creator_attributes"].get(
-            "reviewTrack")
+        reviewableSource = instance.data["creator_attributes"].get(
+            "reviewableSource")
 
-        instance.data.pop("review", None)
         if review_switch:
-            instance.data["reviewTrack"] = review_track
-        else:
-            instance.data.pop("reviewTrack", None)
+            if reviewable_source == "clip_media":
+                instance.data["families"].append("review")
+            else:
+                instance.data["reviewTrack"] = reviewable_source
+
+        # remove review keys from instance data
+        instance.data.pop("reviewableSource", None)
+        instance.data.pop("review", None)
 
         # Retrieve instance data from parent instance shot instance.
         parent_instance_id = instance.data["parent_instance_id"]

From 769f3eb432aa387a4fd875573de1f3906a3fb99d Mon Sep 17 00:00:00 2001
From: "robin@ynput.io" <robin@ynput.io>
Date: Mon, 2 Dec 2024 17:13:23 -0500
Subject: [PATCH 2/8] Implement review and reviewable source.

---
 client/ayon_flame/api/plugin.py | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/client/ayon_flame/api/plugin.py b/client/ayon_flame/api/plugin.py
index 01e99eb..14b52f9 100644
--- a/client/ayon_flame/api/plugin.py
+++ b/client/ayon_flame/api/plugin.py
@@ -200,11 +200,6 @@ def convert(self):
                 }
             })
 
-        if self.marker_data["heroTrack"] and self.review_layer:
-            self.marker_data["reviewTrack"] = self.review_layer
-        else:
-            self.marker_data["reviewTrack"] = "< none >"
-
         return self.current_segment
 
     def _populate_segment_default_data(self):
@@ -325,10 +320,10 @@ def _convert_to_marker_data(self):
             # driving layer is set as positive match
             if hero_track or self.vertical_sync:
                 # mark review layer
-                if self.review_track and (
-                        self.review_track not in self.review_track_default):
+                if self.review_source and (
+                        self.review_source not in self.review_source_default):
                     # if review layer is defined and not the same as default
-                    self.review_layer = self.review_track
+                    self.reviewable_source  = self.review_source
 
                 # shot num calculate
                 if self.index_from_segment:

From cd124f85425a318e29d8daf9299a22bce072007e Mon Sep 17 00:00:00 2001
From: "robin@ynput.io" <robin@ynput.io>
Date: Mon, 2 Dec 2024 17:21:14 -0500
Subject: [PATCH 3/8] Implement review and reviewable source.

---
 client/ayon_flame/api/plugin.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/client/ayon_flame/api/plugin.py b/client/ayon_flame/api/plugin.py
index 14b52f9..91de2d1 100644
--- a/client/ayon_flame/api/plugin.py
+++ b/client/ayon_flame/api/plugin.py
@@ -321,7 +321,7 @@ def _convert_to_marker_data(self):
             if hero_track or self.vertical_sync:
                 # mark review layer
                 if self.review_source and (
-                        self.review_source not in self.review_source_default):
+                        self.review_source != self.review_source_default):
                     # if review layer is defined and not the same as default
                     self.reviewable_source  = self.review_source
 

From 076addade80efce4cfe1b1e8bd3e66503e0af31f Mon Sep 17 00:00:00 2001
From: "robin@ynput.io" <robin@ynput.io>
Date: Mon, 2 Dec 2024 17:39:25 -0500
Subject: [PATCH 4/8] Implement review and reviewable source.

---
 client/ayon_flame/api/plugin.py                      | 5 +----
 client/ayon_flame/plugins/create/create_shot_clip.py | 4 ++--
 client/ayon_flame/plugins/publish/collect_plate.py   | 2 +-
 3 files changed, 4 insertions(+), 7 deletions(-)

diff --git a/client/ayon_flame/api/plugin.py b/client/ayon_flame/api/plugin.py
index 91de2d1..f81c7dd 100644
--- a/client/ayon_flame/api/plugin.py
+++ b/client/ayon_flame/api/plugin.py
@@ -455,10 +455,7 @@ def _convert_to_marker_data(self):
             else:
                 self.marker_data.pop("review", None)
 
-            if reviewable_source:
-                self.marker_data["reviewableSource"] = reviewable_source
-            else:
-                self.marker_data.pop("reviewableSource", None)
+            self.marker_data["reviewableSource"] = reviewable_source
 
 
     def _solve_tag_hierarchy_data(self, hierarchy_formatting_data):
diff --git a/client/ayon_flame/plugins/create/create_shot_clip.py b/client/ayon_flame/plugins/create/create_shot_clip.py
index 2b0e515..86e0652 100644
--- a/client/ayon_flame/plugins/create/create_shot_clip.py
+++ b/client/ayon_flame/plugins/create/create_shot_clip.py
@@ -624,10 +624,10 @@ def create(self, product_name, instance_data, pre_create_data):
 
             # Create new product(s) instances.
             clip_instances = {}
-            # desable shot creator if heroTrack is not enabled
+            # disable shot creator if heroTrack is not enabled
             all_creators[shot_creator_id] = segment_instance_data.get(
                 "heroTrack", False)
-            # desable audio creator if audio is not enabled
+            # disable audio creator if audio is not enabled
             all_creators[audio_creator_id] = (
                 segment_instance_data.get("heroTrack", False) and
                 pre_create_data.get("export_audio", False)
diff --git a/client/ayon_flame/plugins/publish/collect_plate.py b/client/ayon_flame/plugins/publish/collect_plate.py
index 784e391..0e081fe 100644
--- a/client/ayon_flame/plugins/publish/collect_plate.py
+++ b/client/ayon_flame/plugins/publish/collect_plate.py
@@ -31,7 +31,7 @@ def process(self, instance):
 
         review_switch = instance.data["creator_attributes"].get(
             "review")
-        reviewableSource = instance.data["creator_attributes"].get(
+        reviewable_source = instance.data["creator_attributes"].get(
             "reviewableSource")
 
         if review_switch:

From 76a8a2cc9479b2811764f5f5b788cbe97e83ca25 Mon Sep 17 00:00:00 2001
From: "robin@ynput.io" <robin@ynput.io>
Date: Mon, 2 Dec 2024 17:45:30 -0500
Subject: [PATCH 5/8] Implement review and reviewable source.

---
 .../ayon_flame/plugins/create/create_shot_clip.py | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/client/ayon_flame/plugins/create/create_shot_clip.py b/client/ayon_flame/plugins/create/create_shot_clip.py
index 86e0652..490df86 100644
--- a/client/ayon_flame/plugins/create/create_shot_clip.py
+++ b/client/ayon_flame/plugins/create/create_shot_clip.py
@@ -256,8 +256,16 @@ def get_attr_defs_for_instance(self, instance):
                         "reviewableSource",
                         label="Reviewable Source",
                         tooltip=("Selecting source for reviewable files."),
-                        items=gui_tracks,
-                        enabled=current_review,
+                        items=(
+                            [
+                                {
+                                    "value": "clip_media",
+                                    "label": "[ Clip's media ]",
+                                },
+                            ]
+                            + gui_tracks
+                        ),
+                        disabled=not current_review,
                     ),
                 ]
             )
@@ -468,8 +476,7 @@ def header_label(text):
             EnumDef(
                 "reviewableSource",
                 label="Reviewable Source",
-                tooltip="Generate preview videos on fly, if "
-                        "'< none >' is defined nothing will be generated.",
+                tooltip="Select source for reviewable files.",
                 items=[
                     {"value": None, "label": "< none >"},
                     {"value": "clip_media", "label": "[ Clip's media ]"},

From 9e4a05927bf07e2ed613d71b4e409f372acdf9b0 Mon Sep 17 00:00:00 2001
From: "robin@ynput.io" <robin@ynput.io>
Date: Tue, 3 Dec 2024 17:27:37 -0500
Subject: [PATCH 6/8] Report fix clip_media reviewable source.

---
 .../plugins/publish/collect_plate.py          | 38 ++++++++++++++++++-
 1 file changed, 36 insertions(+), 2 deletions(-)

diff --git a/client/ayon_flame/plugins/publish/collect_plate.py b/client/ayon_flame/plugins/publish/collect_plate.py
index 0e081fe..4a8c7d6 100644
--- a/client/ayon_flame/plugins/publish/collect_plate.py
+++ b/client/ayon_flame/plugins/publish/collect_plate.py
@@ -29,18 +29,52 @@ def process(self, instance):
 
         instance.data["otioClip"] = otio_clip
 
+        # solve reviewable options
         review_switch = instance.data["creator_attributes"].get(
             "review")
         reviewable_source = instance.data["creator_attributes"].get(
             "reviewableSource")
 
-        if review_switch:
+        if review_switch is True:
             if reviewable_source == "clip_media":
                 instance.data["families"].append("review")
+                instance.data.pop("reviewTrack", None)
+
+                # Retrieve source clip media from otio clip.
+                # image sequence
+                if hasattr(otio_clip.media_reference, "target_url_for_image_number"):
+                    file_url = otio_clip.media_reference.target_url_for_image_number(0)
+                    sequence_length = (
+                        otio_clip.media_reference.end_frame()
+                        - otio_clip.media_reference.start_frame
+                    )
+                    file_names = [
+                        os.path.basename(
+                            otio_clip.media_reference.target_url_for_image_number(frame)
+                        )
+                        for frame in range(0, sequence_length)
+                    ]
+
+                # movie
+                else:
+                    file_url = otio_clip.media_reference.target_url
+                    file_names = os.path.basename(file_url)
+
+                _, ext = os.path.splitext(file_url)
+
+                repre = {
+                    "name": ext[1:],
+                    "ext": ext[1:],
+                    "files": file_names,
+                    "stagingDir": os.path.dirname(file_url),
+                    "tags": ["review", "delete"]
+                }
+                instance.data["representations"].append(repre)
+
             else:
                 instance.data["reviewTrack"] = reviewable_source
 
-        # remove review keys from instance data
+        # remove creator-specific review keys from instance data
         instance.data.pop("reviewableSource", None)
         instance.data.pop("review", None)
 

From 5728a8af2f225b90555260c2f71614bbb240521f Mon Sep 17 00:00:00 2001
From: "robin@ynput.io" <robin@ynput.io>
Date: Tue, 3 Dec 2024 17:32:06 -0500
Subject: [PATCH 7/8] Fix import os.

---
 client/ayon_flame/plugins/publish/collect_plate.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/client/ayon_flame/plugins/publish/collect_plate.py b/client/ayon_flame/plugins/publish/collect_plate.py
index 4a8c7d6..a9d1c17 100644
--- a/client/ayon_flame/plugins/publish/collect_plate.py
+++ b/client/ayon_flame/plugins/publish/collect_plate.py
@@ -1,3 +1,4 @@
+import os
 import pyblish
 
 import ayon_flame.api as ayfapi

From 7b3c2f988e47baad02ccf42f6d536fbdd044388a Mon Sep 17 00:00:00 2001
From: "robin@ynput.io" <robin@ynput.io>
Date: Wed, 4 Dec 2024 16:51:58 -0500
Subject: [PATCH 8/8] Report clip_media changes from Hiero

---
 .../plugins/publish/collect_plate.py          | 33 -------------------
 1 file changed, 33 deletions(-)

diff --git a/client/ayon_flame/plugins/publish/collect_plate.py b/client/ayon_flame/plugins/publish/collect_plate.py
index a9d1c17..058e894 100644
--- a/client/ayon_flame/plugins/publish/collect_plate.py
+++ b/client/ayon_flame/plugins/publish/collect_plate.py
@@ -1,4 +1,3 @@
-import os
 import pyblish
 
 import ayon_flame.api as ayfapi
@@ -40,38 +39,6 @@ def process(self, instance):
             if reviewable_source == "clip_media":
                 instance.data["families"].append("review")
                 instance.data.pop("reviewTrack", None)
-
-                # Retrieve source clip media from otio clip.
-                # image sequence
-                if hasattr(otio_clip.media_reference, "target_url_for_image_number"):
-                    file_url = otio_clip.media_reference.target_url_for_image_number(0)
-                    sequence_length = (
-                        otio_clip.media_reference.end_frame()
-                        - otio_clip.media_reference.start_frame
-                    )
-                    file_names = [
-                        os.path.basename(
-                            otio_clip.media_reference.target_url_for_image_number(frame)
-                        )
-                        for frame in range(0, sequence_length)
-                    ]
-
-                # movie
-                else:
-                    file_url = otio_clip.media_reference.target_url
-                    file_names = os.path.basename(file_url)
-
-                _, ext = os.path.splitext(file_url)
-
-                repre = {
-                    "name": ext[1:],
-                    "ext": ext[1:],
-                    "files": file_names,
-                    "stagingDir": os.path.dirname(file_url),
-                    "tags": ["review", "delete"]
-                }
-                instance.data["representations"].append(repre)
-
             else:
                 instance.data["reviewTrack"] = reviewable_source