From d01c42c3a7e257464a002e3033e508a23cfaada6 Mon Sep 17 00:00:00 2001 From: data Date: Tue, 18 Feb 2025 18:57:18 +0100 Subject: [PATCH] =?UTF-8?q?DatenPaket=20f=C3=BCr=20die=20Websocket=20?= =?UTF-8?q?=C3=BCberarbeitet=20um=20Fehler=20vorzubeugen.=20Den=20ffmpeg?= =?UTF-8?q?=20Befehl=20f=C3=BCr=20Subtitle=20angepasst=20und=20im=20Javasc?= =?UTF-8?q?ript=20ebenfalls=20eine=20Fehlerbehandlung=20eingesetzt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/main.py | 70 ++++++++++++++++++++++++---------------------- app/video_class.py | 67 ++++++++++++++++++++++++++++++++++---------- app/webs/webs.js | 4 +++ 3 files changed, 93 insertions(+), 48 deletions(-) diff --git a/app/main.py b/app/main.py index 6c78312..4955e9c 100755 --- a/app/main.py +++ b/app/main.py @@ -26,6 +26,7 @@ convert_task = 0 # Settings language = ["ger", "eng"] +subtitle_codec_blacklist = ["hdmv_pgs_subtitle", "dvd_subtitle"] process_count = 1 # Test @@ -46,28 +47,27 @@ async def queue_video(): convert_task += 1 asyncio.create_task(video_convert(obj)) -async def video_convert(obj): +async def get_ffprobe(select, obj): global convert_task - # Audio ------------------------------------------------------------------------------------------------------------ command = [ "ffprobe", "-v", "error", "-select_streams", - "a", "-show_entries", - "stream=index,channels,tags:stream_tags=language,tags:format=duration", + f"{select}", "-show_entries", + "stream=index,channels,codec_name,tags:stream_tags=language,tags:format=duration", "-of", "json", obj.source_file ] - json_data = {} - try: result = subprocess.run(command, stdout=subprocess.PIPE, text=True) json_data = json.loads(result.stdout) print(json_data) - obj.duration = json_data.get("format", {"duration":999}).get("duration") + duration = json_data.get("format", {"duration": 999}).get("duration") + obj.duration = float(duration) if duration.isdigit() else 0.0 + return json_data except Exception as e: convert_task -= 1 @@ -75,6 +75,12 @@ async def video_convert(obj): obj.error.append(f"ffprobe ---- {e}") print(obj.error) +async def video_convert(obj): + global convert_task + + json_data_audio = await get_ffprobe("a", obj) + json_data_subtitles = await get_ffprobe("s", obj) + # Konvertierung ---------------------------------------------------------------------------------------------------- command = [ "ffmpeg", "-y", "-i", obj.source_file, @@ -87,9 +93,9 @@ async def video_convert(obj): "-svtav1-params", "tune=0:film-grain=8", ] - if "streams" in json_data: + if "streams" in json_data_audio: i = 0 - for audio_stream in json_data["streams"]: + for audio_stream in json_data_audio["streams"]: if audio_stream.get("tags", {}).get("language", None) in language: command.extend([ "-map", f"0:{audio_stream['index']}", @@ -98,10 +104,26 @@ async def video_convert(obj): f"-ac", str(audio_stream['channels']) ]) i += 1 - - command.extend(["-map", "0:s?", "-c:s", "copy"]) + + # Subtitle-Streams einbinden + if "streams" in json_data_subtitles: + for subtitle_stream in json_data_subtitles["streams"]: + if subtitle_stream.get("codec_name") not in subtitle_codec_blacklist: + if subtitle_stream.get("tags", {}).get("language", None) in language: + command.extend([ + "-map", f"0:{subtitle_stream['index']}", + ]) + command.append(obj.output_file) + """ + ffmpeg_cm = "" + for cm in command: + ffmpeg_cm += f"{cm} " + + print(ffmpeg_cm) + """ + # Prozess try: process_video = await asyncio.create_subprocess_exec( @@ -126,38 +148,20 @@ async def read_output(): while True: active_processes = [obj for obj in video_files.values() if obj.progress] + print(active_processes) + if not active_processes: await asyncio.sleep(10) # Kein aktives Video -> kurz warten continue for obj in active_processes: if obj.progress: - line = await obj.progress.stderr.read(2048) + line = await obj.progress.stderr.read(1024) line_decoded = line.decode().strip() print(line_decoded) - frame = re.findall(r"frame=\s*(\d+)", line_decoded) - obj.frame = frame[0] if frame else obj.frame - - fps = re.findall(r"fps=\s*(\d+.\d+)", line_decoded) - obj.fps = fps[0] if fps else obj.fps - - q = re.findall(r"q=\s*(\d+.\d+)", line_decoded) - obj.q = q[0] if q else obj.q - - size = re.findall(r"size=\s*(\d+)", line_decoded) - obj.size = round(int(size[0]) / 1024, 2) if size else obj.size - - time = re.findall(r"time=\s*(\d+:\d+:\d+)", line_decoded) - time_v = time[0] if time else time - obj.time = obj.time_in_sec(time_v) - - bitrate = re.findall(r"bitrate=\s*(\d+)", line_decoded) - obj.bitrate = round(int(bitrate[0]) / 1024, 2) if bitrate else obj.bitrate - - speed = re.findall(r"speed=\s*(\d+\.\d+)", line_decoded) - obj.speed = speed[0] if speed else obj.speed + obj.extract_convert_data(line_decoded) json_data = json.dumps(obj.to_dict()) await queue.put(json_data) diff --git a/app/video_class.py b/app/video_class.py index 6193aa8..94f2276 100644 --- a/app/video_class.py +++ b/app/video_class.py @@ -1,4 +1,6 @@ import os +import re +from datetime import datetime class Video: @@ -6,13 +8,13 @@ class Video: self.id = id(self) self.source_file = path self.output_file = f"{path.rsplit(".", 1)[0]}.webm" - self.frame = None - self.fps = None - self.q = None - self.size = None + self.frame = 0 + self.fps = 0 + self.q = 0 + self.size = 0 self.time = 0 - self.bitrate = None - self.speed = None + self.bitrate = 0 + self.speed = 0 self.finished = 0 self.progress = None self.duration = 1 @@ -39,15 +41,50 @@ class Video: "loading": self.loading } - @staticmethod - def time_in_sec(time): - if time != 0: - h_m_s = str(time).split(":") - time_in_s = int(h_m_s[0]) * 3600 + int(h_m_s[1]) * 60 + int(h_m_s[2]) - else: - time_in_s = 0 + def extract_convert_data(self, line_decoded): + frame = re.findall(r"frame=\s*(\d+)", line_decoded) + self.frame = frame[0] if frame else 0 - return time_in_s + fps = re.findall(r"fps=\s*(\d+.\d+)", line_decoded) + self.fps = fps[0] if fps else 0 + + q = re.findall(r"q=\s*(\d+.\d+)", line_decoded) + self.q = q[0] if q else 0 + + size = re.findall(r"size=\s*(\d+)", line_decoded) + self.size = self.convert_kb_mb(size[0]) if size else 0 + + time = re.findall(r"time=\s*(\d+:\d+:\d+)", line_decoded) + time_v = time[0] if time else "" + self.time = self.time_in_sec(time_v) + + bitrate = re.findall(r"bitrate=\s*(\d+)", line_decoded) + self.bitrate = self.convert_kb_mb(bitrate[0]) if bitrate else 0 + + speed = re.findall(r"speed=\s*(\d+\.\d+)", line_decoded) + self.speed = speed[0] if speed else 0 + + @staticmethod + def is_time_format(s): + return bool(re.fullmatch(r"\d{2}:\d{2}:\d{2}(\.\d{1,2})?", s)) + + def time_in_sec(self, time_str): + if self.is_time_format(time_str): + try: + t = datetime.strptime(time_str, "%H:%M:%S.%f") + return t.hour * 3600 + t.minute * 3600 + t.second + t.microsecond / 1_000_000 + except ValueError: + return None def calc_loading(self): - self.loading = round(self.time / float(self.duration) * 100, None) + if self.duration != 0: + self.loading = round(self.time / self.duration * 100, None) + else: + self.loading = 0 + + @staticmethod + def convert_kb_mb(digits): + if digits.isdigit(): + return round(int(digits) / 1024, 2) + else: + return 0 \ No newline at end of file diff --git a/app/webs/webs.js b/app/webs/webs.js index 73113e1..6545aaf 100644 --- a/app/webs/webs.js +++ b/app/webs/webs.js @@ -17,6 +17,10 @@ ws.onmessage = function(event) { } }; +ws.onerror = function(event) { + console.error("WebSocket Fehler:", event); +}; + function createVideoElement(id, source, target, path) { let container = document.createElement("div"); container.className = "video";