From a17f05ef21ff3719fb98488260a1dfc3c357825b Mon Sep 17 00:00:00 2001 From: simon Date: Sat, 15 Apr 2023 17:45:20 +0700 Subject: [PATCH] index streams and file size --- tubearchivist/home/src/es/index_mapping.json | 27 +++++++ tubearchivist/home/src/index/video.py | 17 +++- tubearchivist/home/src/index/video_streams.py | 78 +++++++++++++++++++ tubearchivist/home/templates/home/video.html | 42 ++++++---- tubearchivist/static/css/style.css | 4 + 5 files changed, 153 insertions(+), 15 deletions(-) diff --git a/tubearchivist/home/src/es/index_mapping.json b/tubearchivist/home/src/es/index_mapping.json index b47ea44..6641159 100644 --- a/tubearchivist/home/src/es/index_mapping.json +++ b/tubearchivist/home/src/es/index_mapping.json @@ -146,6 +146,9 @@ "type": "keyword", "index": false }, + "media_size": { + "type": "long" + }, "tags": { "type": "text", "analyzer": "english", @@ -239,6 +242,30 @@ } } }, + "streams": { + "properties": { + "type": { + "type": "keyword", + "index": false + }, + "index": { + "type": "short", + "index": false + }, + "codec": { + "type": "text" + }, + "width": { + "type": "short" + }, + "height": { + "type": "short" + }, + "bitrate": { + "type": "integer" + } + } + }, "sponsorblock": { "properties": { "last_refresh": { diff --git a/tubearchivist/home/src/index/video.py b/tubearchivist/home/src/index/video.py index f9afffa..f3ade1c 100644 --- a/tubearchivist/home/src/index/video.py +++ b/tubearchivist/home/src/index/video.py @@ -16,7 +16,10 @@ from home.src.index import playlist as ta_playlist from home.src.index.generic import YouTubeItem from home.src.index.subtitle import YoutubeSubtitle from home.src.index.video_constants import VideoTypeEnum -from home.src.index.video_streams import DurationConverter +from home.src.index.video_streams import ( + DurationConverter, + MediaStreamExtractor, +) from home.src.ta.helper import clean_string, randomizor from home.src.ta.ta_redis import RedisArchivist from ryd_client import ryd_client @@ -153,6 +156,7 @@ class YoutubeVideo(YouTubeItem, YoutubeSubtitle): self._add_stats() self.add_file_path() self.add_player(media_path) + self.add_streams(media_path) if self.config["downloads"]["integrate_ryd"]: self._get_ryd_stats() @@ -254,6 +258,17 @@ class YoutubeVideo(YouTubeItem, YoutubeSubtitle): } ) + def add_streams(self, media_path=False): + """add stream metadata""" + vid_path = self._get_vid_path(media_path) + media = MediaStreamExtractor(vid_path) + self.json_data.update( + { + "streams": media.extract_metadata(), + "media_size": media.get_file_size(), + } + ) + def _get_vid_path(self, media_path=False): """get path of media file""" if media_path: diff --git a/tubearchivist/home/src/index/video_streams.py b/tubearchivist/home/src/index/video_streams.py index 01873a8..e477760 100644 --- a/tubearchivist/home/src/index/video_streams.py +++ b/tubearchivist/home/src/index/video_streams.py @@ -1,6 +1,8 @@ """extract metadata from video streams""" +import json import subprocess +from os import stat class DurationConverter: @@ -52,3 +54,79 @@ class DurationConverter: duration_str = duration_str + "00:" duration_str = duration_str + str(secs).zfill(2) return duration_str + + +class MediaStreamExtractor: + """extract stream metadata""" + + def __init__(self, media_path): + self.media_path = media_path + self.metadata = [] + + def extract_metadata(self): + """entry point to extract metadata""" + + cmd = [ + "ffprobe", + "-v", + "quiet", + "-print_format", + "json", + "-show_streams", + "-show_format", + self.media_path, + ] + result = subprocess.run( + cmd, capture_output=True, text=True, check=False + ) + + if result.returncode != 0: + return self.metadata + + streams = json.loads(result.stdout).get("streams") + for stream in streams: + self.process_stream(stream) + + return self.metadata + + def process_stream(self, stream): + """parse stream to metadata""" + codec_type = stream.get("codec_type") + if codec_type == "video": + self._extract_video_metadata(stream) + elif codec_type == "audio": + self._extract_audio_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"]), + } + ) + + def _extract_audio_metadata(self, stream): + """extract audio metadata""" + self.metadata.append( + { + "type": "audio", + "index": stream["index"], + "codec": stream["codec_name"], + "bitrate": int(stream["bit_rate"]), + } + ) + + def get_file_size(self): + """get filesize in bytes""" + return stat(self.media_path).st_size diff --git a/tubearchivist/home/templates/home/video.html b/tubearchivist/home/templates/home/video.html index a500a9c..698d2a8 100644 --- a/tubearchivist/home/templates/home/video.html +++ b/tubearchivist/home/templates/home/video.html @@ -56,20 +56,6 @@ {% else %}

Youtube: Deactivated

{% endif %} - {% if reindex %} -

Reindex scheduled

- {% else %} -
- -
- {% endif %} -
- - -
- Are you sure? -
-
@@ -89,6 +75,34 @@
+
+
+
+ {% if reindex %} +

Reindex scheduled

+ {% else %} +
+ +
+ {% endif %} + + +
+ Are you sure? +
+
+
+
+ {% if video.media_size %} +

File size: {{ video.media_size|filesizeformat }}

+ {% endif %} + {% if video.streams %} + {% for stream in video.streams %} +

{{ stream.type|title }}: {{ stream.codec }} {{ stream.bitrate|filesizeformat }}/s{% if stream.width %} | {{ stream.width }}x{{ stream.height}}{% endif %}

+ {% endfor %} + {% endif %} +
+
{% if video.tags %}
diff --git a/tubearchivist/static/css/style.css b/tubearchivist/static/css/style.css index 4119946..07b59c0 100644 --- a/tubearchivist/static/css/style.css +++ b/tubearchivist/static/css/style.css @@ -660,6 +660,10 @@ video:-webkit-full-screen { background-color: var(--highlight-bg); } +.info-box-item p { + width: 100%; +} + .description-text { width: 100%; }