From 7d66f8bcecad44c0cd63dfc93e9480da8a208006 Mon Sep 17 00:00:00 2001 From: bmcdonough Date: Wed, 17 Sep 2025 22:05:34 +0000 Subject: [PATCH] add subtitle and thumbnail metadata to video summary --- backend/video/serializers.py | 7 ++-- backend/video/src/media_streams.py | 53 ++++++++++++++++++++++-------- frontend/src/pages/Home.tsx | 5 +-- frontend/src/pages/Video.tsx | 16 +++++++-- 4 files changed, 59 insertions(+), 22 deletions(-) diff --git a/backend/video/serializers.py b/backend/video/serializers.py index 55d229f0..315863d9 100644 --- a/backend/video/serializers.py +++ b/backend/video/serializers.py @@ -53,11 +53,12 @@ class StreamItemSerializer(serializers.Serializer): """serialize stream item""" index = serializers.IntegerField() - codec = serializers.CharField() - bitrate = serializers.IntegerField() - type = serializers.ChoiceField(choices=["video", "audio"]) + codec = serializers.CharField(required=False, allow_null=True) + bitrate = serializers.IntegerField(required=False) + type = serializers.ChoiceField(choices=["video", "audio", "subtitle"]) width = serializers.IntegerField(required=False) height = serializers.IntegerField(required=False) + language = serializers.CharField(required=False) class SubtitleItemSerializer(serializers.Serializer): diff --git a/backend/video/src/media_streams.py b/backend/video/src/media_streams.py index 0d8c1823..5b248a40 100644 --- a/backend/video/src/media_streams.py +++ b/backend/video/src/media_streams.py @@ -45,25 +45,37 @@ class MediaStreamExtractor: self._extract_video_metadata(stream) elif codec_type == "audio": self._extract_audio_metadata(stream) + elif codec_type == "subtitle": + self._extract_subtitle_metadata(stream) else: return def _extract_video_metadata(self, stream): """parse video metadata""" - if "bit_rate" not in stream: - # is probably thumbnail - return - - self.metadata.append( - { - "type": "video", - "index": stream["index"], - "codec": stream["codec_name"], - "width": stream["width"], - "height": stream["height"], - "bitrate": int(stream["bit_rate"]), - } - ) + if stream["disposition"]["attached_pic"] == 1: + self.metadata.append( + { + "type": "thumbnail", + "index": stream["index"], + "codec": stream["codec_name"], + "width": stream["width"], + "height": stream["height"], + } + ) + else: + self.metadata.append( + { + "type": "video", + "index": stream["index"], + "codec": stream["codec_name"], + "width": stream["width"], + "height": stream["height"], + "bitrate": int(stream.get("bit_rate", 0)), + "language": stream.get("tags", {}).get( + "language", "unknown" + ), + } + ) def _extract_audio_metadata(self, stream): """extract audio metadata""" @@ -73,6 +85,19 @@ class MediaStreamExtractor: "index": stream["index"], "codec": stream.get("codec_name", "undefined"), "bitrate": int(stream.get("bit_rate", 0)), + "language": stream.get("tags", {}).get("language", "unknown"), + } + ) + + def _extract_subtitle_metadata(self, stream): + """extract subtitle metadata""" + self.metadata.append( + { + "type": "subtitle", + "index": stream["index"], + "codec": stream.get("codec_name", "text"), + "bitrate": int(stream.get("bit_rate", 0)), + "language": stream.get("tags", {}).get("language", "unknown"), } ) diff --git a/frontend/src/pages/Home.tsx b/frontend/src/pages/Home.tsx index d01a96d4..ba4e1c62 100644 --- a/frontend/src/pages/Home.tsx +++ b/frontend/src/pages/Home.tsx @@ -43,10 +43,11 @@ export type StatsType = { export type StreamType = { type: string; index: number; - codec: string; + codec?: string; width?: number; height?: number; - bitrate: number; + bitrate?: number; + language?: string; }; export type Subtitles = { diff --git a/frontend/src/pages/Video.tsx b/frontend/src/pages/Video.tsx index abd1e8ef..cea68307 100644 --- a/frontend/src/pages/Video.tsx +++ b/frontend/src/pages/Video.tsx @@ -467,13 +467,23 @@ const Video = () => { video.streams.map(stream => { return (

- {capitalizeFirstLetter(stream.type)}: {stream.codec}{' '} - {humanFileSize(stream.bitrate, useSiUnits)}/s + {capitalizeFirstLetter(stream.type)}: {stream.codec} + {stream.bitrate && ( + <> + |{' '} + {`${humanFileSize(stream.bitrate, useSiUnits)}/s`} + + )} {stream.width && ( <> | {stream.width}x{stream.height} - )}{' '} + )} + {stream.language && ( + <> + | {stream.language} + + )}

); })}