Compare commits

..

No commits in common. "d01c42c3a7e257464a002e3033e508a23cfaada6" and "4cce6c8cf8df219571212d3524a7e25b24ead073" have entirely different histories.

12 changed files with 47 additions and 157 deletions

3
.idea/.gitignore vendored
View file

@ -1,3 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml

View file

@ -1,17 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="false" level="WARNING" enabled_by_default="false">
<option name="ignoredIdentifiers">
<list>
<option value="PySide6.QtWidgets.QHeaderView.*" />
</list>
</option>
</inspection_tool>
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
<option name="processCode" value="true" />
<option name="processLiterals" value="true" />
<option name="processComments" value="true" />
</inspection_tool>
</profile>
</component>

View file

@ -1,6 +0,0 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

View file

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.13" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13 (python.fast-api-converter)" project-jdk-type="Python SDK" />
</project>

View file

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/python.fast-api-converter.iml" filepath="$PROJECT_DIR$/.idea/python.fast-api-converter.iml" />
</modules>
</component>
</project>

View file

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.venv" />
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.13 (python.fast-api-converter)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">
<option name="format" value="PLAIN" />
<option name="myDocStringFormat" value="Plain" />
</component>
<component name="TestRunnerService">
<option name="PROJECT_TEST_RUNNER" value="py.test" />
</component>
</module>

View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

Binary file not shown.

View file

@ -26,7 +26,6 @@ convert_task = 0
# Settings
language = ["ger", "eng"]
subtitle_codec_blacklist = ["hdmv_pgs_subtitle", "dvd_subtitle"]
process_count = 1
# Test
@ -47,27 +46,28 @@ async def queue_video():
convert_task += 1
asyncio.create_task(video_convert(obj))
async def get_ffprobe(select, obj):
async def video_convert(obj):
global convert_task
# Audio ------------------------------------------------------------------------------------------------------------
command = [
"ffprobe", "-v",
"error",
"-select_streams",
f"{select}", "-show_entries",
"stream=index,channels,codec_name,tags:stream_tags=language,tags:format=duration",
"a", "-show_entries",
"stream=index,channels,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)
duration = json_data.get("format", {"duration": 999}).get("duration")
obj.duration = float(duration) if duration.isdigit() else 0.0
return json_data
obj.duration = json_data.get("format", {"duration":999}).get("duration")
except Exception as e:
convert_task -= 1
@ -75,12 +75,6 @@ async def get_ffprobe(select, 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,
@ -93,9 +87,9 @@ async def video_convert(obj):
"-svtav1-params", "tune=0:film-grain=8",
]
if "streams" in json_data_audio:
if "streams" in json_data:
i = 0
for audio_stream in json_data_audio["streams"]:
for audio_stream in json_data["streams"]:
if audio_stream.get("tags", {}).get("language", None) in language:
command.extend([
"-map", f"0:{audio_stream['index']}",
@ -104,26 +98,10 @@ async def video_convert(obj):
f"-ac", str(audio_stream['channels'])
])
i += 1
# 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.extend(["-map", "0:s?", "-c:s", "copy"])
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(
@ -148,20 +126,38 @@ 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(1024)
line = await obj.progress.stderr.read(2048)
line_decoded = line.decode().strip()
print(line_decoded)
obj.extract_convert_data(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
json_data = json.dumps(obj.to_dict())
await queue.put(json_data)

View file

@ -1,6 +1,4 @@
import os
import re
from datetime import datetime
class Video:
@ -8,13 +6,13 @@ class Video:
self.id = id(self)
self.source_file = path
self.output_file = f"{path.rsplit(".", 1)[0]}.webm"
self.frame = 0
self.fps = 0
self.q = 0
self.size = 0
self.frame = None
self.fps = None
self.q = None
self.size = None
self.time = 0
self.bitrate = 0
self.speed = 0
self.bitrate = None
self.speed = None
self.finished = 0
self.progress = None
self.duration = 1
@ -41,50 +39,15 @@ class Video:
"loading": self.loading
}
def extract_convert_data(self, line_decoded):
frame = re.findall(r"frame=\s*(\d+)", line_decoded)
self.frame = frame[0] if frame else 0
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(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 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
return time_in_s
def calc_loading(self):
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
self.loading = round(self.time / float(self.duration) * 100, None)

View file

@ -17,10 +17,6 @@ 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";