From c29a147af958a21ba60bb6a504494e6e9b4f948b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Simon=20K=C3=BCnzel?= <simonk@fsmpi.rwth-aachen.de>
Date: Sat, 12 Oct 2024 19:58:25 +0200
Subject: [PATCH] Add thumbnail target and job

---
 .../media_process/basic_targets.py            | 62 +++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/src/videoag_common/media_process/basic_targets.py b/src/videoag_common/media_process/basic_targets.py
index 1ff39ed..275df20 100644
--- a/src/videoag_common/media_process/basic_targets.py
+++ b/src/videoag_common/media_process/basic_targets.py
@@ -1,5 +1,6 @@
 import re
 from typing import Any
+import math
 
 from videoag_common.database import *
 from videoag_common.miscellaneous import *
@@ -121,6 +122,67 @@ class DownscaleVideoTarget(SingleInputTargetProducer):
         pass
 
 
+class SampleThumbnailTarget(SingleInputTargetProducer, SingleOutputTargetProducer):
+    
+    def __init__(self, timestamp_percent: int, **kwargs):
+        super().__init__(**kwargs)
+        self.timestamp_percent = timestamp_percent
+    
+    @classmethod
+    def get_type(cls) -> str:
+        return "sample_thumbnail"
+    
+    @classmethod
+    def _get_args_from_json(cls, json: CJsonObject) -> dict[str, Any]:
+        timestamp_percent = json.get_int("timestamp_percent", 0, 100)
+        return super()._get_args_from_json(json) | {
+            "timestamp_percent": timestamp_percent
+        }
+    
+    def to_json(self) -> dict:
+        return super().to_json() | {
+            "timestamp_percent": self.timestamp_percent
+        }
+    
+    # Can't import Lecture, TargetMedium due to circular dependency
+    # noinspection PyUnresolvedReferences
+    def create_new_target_media_and_job_data(
+            self,
+            session: SessionDb,
+            lecture: "Lecture",
+            input_media_by_id: dict[str, "TargetMedium"],
+            common_new_medium_kwargs: dict[str, Any],
+            intermediate: None,
+    ) -> tuple[list["TargetMedium"], tuple[str, JsonTypes] or None] or None:
+        from videoag_common.objects import ThumbnailTargetMedium, PlainVideoTargetMedium, TargetMediumType
+        input_medium = input_media_by_id[self.source_id]
+        output_medium = ThumbnailTargetMedium(**(
+            common_new_medium_kwargs | {
+                "process_target_id": self.output_id
+            }
+        ))
+        session.add(output_medium)
+        session.flush()  # Ensure id is present
+        output_medium.file_path = output_medium.get_default_file_path_no_ending() + ".jpg"
+        
+        if not isinstance(input_medium, PlainVideoTargetMedium):
+            raise MediaProcessException(f"Input {self.source_id} is not of type {TargetMediumType.PLAIN_VIDEO}")
+        
+        if self.timestamp_percent == 0:
+            time_sec = 0
+        else:
+            time_sec = math.ceil(input_medium.duration_sec * self.timestamp_percent / 100)
+        
+        return [output_medium], (
+            "sample_thumbnail",
+            {
+                "input_file": input_medium.file_path,
+                "output_file": output_medium.file_path,
+                "time_sec": time_sec
+            }
+        )
+
+
 # TODO
 class AddIntroOutroTargetProducer(TargetProducer):
     pass
-- 
GitLab