From fc812c4ec79cf0e57fcba8ec7a478a89e6502fa3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Simon=20K=C3=BCnzel?= <simonk@fsmpi.rwth-aachen.de>
Date: Thu, 10 Oct 2024 23:03:01 +0200
Subject: [PATCH] Add more fields to target media

---
 src/videoag_common/objects/medium.py | 104 ++++++++++++++++++++-------
 1 file changed, 78 insertions(+), 26 deletions(-)

diff --git a/src/videoag_common/objects/medium.py b/src/videoag_common/objects/medium.py
index 1bb0af1..c79916e 100644
--- a/src/videoag_common/objects/medium.py
+++ b/src/videoag_common/objects/medium.py
@@ -67,6 +67,21 @@ class SourceMedium(DeletableApiObject, Base):
             data_notes="Only calculated once this is sorted"
         )
     )
+    file_size: Mapped[int] = api_mapped(
+        mapped_column(sql.types.BigInteger, nullable=True),
+        ApiIntegerField(
+            include_in_data=True,
+            data_notes="Only calculated once this is sorted"
+        )
+    )
+    metadata: Mapped[JsonTypes] = api_mapped(
+        mapped_column(sql.JSON, nullable=True),
+        ApiDataField(
+            include_in_data=True,
+            # See source file sorter for contents
+            data_notes="Only calculated once this is sorted. There are no guarantees regarding the content"
+        )
+    )
     tag: Mapped[str] = mapped_column(String(collation=STRING_COLLATION), nullable=True)
     
     lecture: Mapped[Lecture] = relationship(
@@ -105,7 +120,6 @@ class TargetMedium(DeletableApiObject, Base):
     producer_job_id: Mapped[int] = mapped_column(ForeignKey("job.id"), nullable=True)
     is_produced: Mapped[bool] = mapped_column(nullable=False, default=False)
     to_be_replaced: Mapped[bool] = mapped_column(nullable=False, default=False)
-    file_path: Mapped[str] = mapped_column(String(collation=STRING_COLLATION), nullable=True, index=True)  # TODO move?
     type: Mapped[TargetMediumType] = api_mapped(
         mapped_column(_TARGET_MEDIUM_TYPE_ENUM, nullable=False),
         ApiEnumField(
@@ -127,19 +141,6 @@ class TargetMedium(DeletableApiObject, Base):
         lazy="raise_on_sql"
     )
     
-    @api_include_in_data(
-        type_id="string",
-        data_notes="URL to the mediums's file (Maybe with a redirect)"
-    )
-    def url(self) -> str:
-        # This is not too nice and only works from the API, but we need to access the API config
-        import api
-        return f"{api.config['API_BASE_URL']}/resources/target_medium/{self.id}"
-    
-    def get_default_file_path_no_ending(self):
-        # TODO path
-        return f"{self.process_target_id}.{self.id}"
-    
     @hybrid_method
     def is_active(self, usable_check: bool = True, from_lecture: bool = False, from_publish_medium: bool = False, **kwargs):
         cond = super().is_active(**kwargs)
@@ -194,32 +195,61 @@ class TargetMedium(DeletableApiObject, Base):
         return options
 
 
-# Note that this usually also includes audio
-class PlainVideoTargetMedium(TargetMedium):
-    __tablename__ = None  # Prevent our own base from adding a table name. This should be a single-table inheritance
-    __mapper_args__ = {
-        "polymorphic_identity": TargetMediumType.PLAIN_VIDEO
-    }
+class FileTargetMedium(TargetMedium):
+    file_path: Mapped[str] = mapped_column(String(collation=STRING_COLLATION), nullable=True, index=True)  # TODO move?
+    
+    @api_include_in_data(
+        type_id="string",
+        data_notes="URL to the mediums's file (Maybe with a redirect)"
+    )
+    def url(self) -> str:
+        # This is not too nice and only works from the API, but we need to access the API config
+        import api
+        return f"{api.config['API_BASE_URL']}/resources/target_medium/{self.id}"
     
-    vertical_resolution: Mapped[int] = api_mapped(
+    def get_default_file_path_no_ending(self):
+        # TODO path
+        return f"{self.process_target_id}.{self.id}"
+
+
+class SingleAudioContainingMedium(TargetMedium):
+    
+    audio_sample_rate: Mapped[int] = api_mapped(
+        mapped_column(nullable=True),
+        ApiIntegerField(
+            include_in_data=True,
+            help="In Hz"
+        )
+    )
+    audio_channel_count: Mapped[int] = api_mapped(
+        mapped_column(nullable=True),
+        ApiIntegerField(
+            include_in_data=True
+        )
+    )
+
+
+class SingleVideoContainingMedium(TargetMedium):
+    
+    video_vertical_resolution: Mapped[int] = api_mapped(
         mapped_column(nullable=True),
         ApiIntegerField(
             include_in_data=True
         )
     )
-    horizontal_resolution: Mapped[int] = api_mapped(
+    video_horizontal_resolution: Mapped[int] = api_mapped(
         mapped_column(nullable=True),
         ApiIntegerField(
             include_in_data=True
         )
     )
-    frame_rate_numerator: Mapped[int] = api_mapped(
+    video_frame_rate_numerator: Mapped[int] = api_mapped(
         mapped_column(nullable=True),
         ApiIntegerField(
             include_in_data=True
         )
     )
-    frame_rate_denominator: Mapped[int] = api_mapped(
+    video_frame_rate_denominator: Mapped[int] = api_mapped(
         mapped_column(nullable=True),
         ApiIntegerField(
             include_in_data=True
@@ -227,14 +257,36 @@ class PlainVideoTargetMedium(TargetMedium):
     )
 
 
-class PlainAudioTargetMedium(TargetMedium):
+class PlainVideoTargetMedium(FileTargetMedium, SingleVideoContainingMedium, SingleAudioContainingMedium):
+    __tablename__ = None  # Prevent our own base from adding a table name. This should be a single-table inheritance
+    __mapper_args__ = {
+        "polymorphic_identity": TargetMediumType.PLAIN_VIDEO
+    }
+    
+    duration_sec: Mapped[int] = api_mapped(
+        mapped_column(nullable=True),
+        ApiIntegerField(
+            include_in_data=True
+        )
+    )
+    # TODO check vars not null (except audio)
+
+
+class PlainAudioTargetMedium(FileTargetMedium, SingleAudioContainingMedium):
     __tablename__ = None  # Prevent our own base from adding a table name. This should be a single-table inheritance
     __mapper_args__ = {
         "polymorphic_identity": TargetMediumType.PLAIN_AUDIO
     }
+    
+    duration_sec: Mapped[int] = api_mapped(
+        mapped_column(nullable=True),
+        ApiIntegerField(
+            include_in_data=True
+        )
+    )
 
 
-class ThumbnailTargetMedium(TargetMedium):
+class ThumbnailTargetMedium(FileTargetMedium):
     __tablename__ = None  # Prevent our own base from adding a table name. This should be a single-table inheritance
     __mapper_args__ = {
         "polymorphic_identity": TargetMediumType.THUMBNAIL
-- 
GitLab