mirror of
https://github.com/myronblair/kino-app
synced 2026-06-30 17:50:16 -05:00
auto-commit for 14921357-f5e2-4aba-b4c1-a07a52c800cc
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
"""HLS transcoding via ffmpeg. Background-runs and updates DB."""
|
||||
import asyncio
|
||||
import logging
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
logger = logging.getLogger("kino.transcode")
|
||||
|
||||
|
||||
async def transcode_to_hls(
|
||||
source: Path,
|
||||
out_dir: Path,
|
||||
on_status,
|
||||
):
|
||||
"""
|
||||
Run ffmpeg to produce HLS playlist + segments.
|
||||
`on_status(status, error=None)` is awaited at start/end with status one of
|
||||
'running'|'done'|'failed'.
|
||||
Uses stream-copy where possible (fast, no re-encode).
|
||||
"""
|
||||
if not source.is_file():
|
||||
await on_status("failed", error=f"Source missing: {source}")
|
||||
return
|
||||
out_dir.mkdir(parents=True, exist_ok=True)
|
||||
playlist = out_dir / "playlist.m3u8"
|
||||
|
||||
cmd = [
|
||||
"ffmpeg", "-y",
|
||||
"-i", str(source),
|
||||
"-c:v", "copy",
|
||||
"-c:a", "copy",
|
||||
"-bsf:v", "h264_mp4toannexb",
|
||||
"-f", "hls",
|
||||
"-hls_time", "6",
|
||||
"-hls_list_size", "0",
|
||||
"-hls_playlist_type", "vod",
|
||||
"-hls_segment_filename", str(out_dir / "seg_%04d.ts"),
|
||||
str(playlist),
|
||||
]
|
||||
|
||||
await on_status("running")
|
||||
try:
|
||||
proc = await asyncio.create_subprocess_exec(
|
||||
*cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE,
|
||||
)
|
||||
_stdout, stderr = await proc.communicate()
|
||||
if proc.returncode != 0:
|
||||
err = stderr.decode("utf-8", errors="ignore")[-500:]
|
||||
logger.error(f"ffmpeg failed: {err}")
|
||||
await on_status("failed", error=err[:200])
|
||||
# cleanup partial files
|
||||
shutil.rmtree(out_dir, ignore_errors=True)
|
||||
return
|
||||
await on_status("done")
|
||||
except FileNotFoundError:
|
||||
await on_status("failed", error="ffmpeg not installed")
|
||||
except Exception as e:
|
||||
logger.exception("transcode crashed")
|
||||
await on_status("failed", error=str(e))
|
||||
shutil.rmtree(out_dir, ignore_errors=True)
|
||||
|
||||
|
||||
def srt_to_vtt(srt_text: str) -> str:
|
||||
"""Convert SRT subtitles to WebVTT format (simple, no styling)."""
|
||||
lines = srt_text.replace("\r\n", "\n").split("\n")
|
||||
out = ["WEBVTT", ""]
|
||||
for line in lines:
|
||||
# Replace SRT timestamp commas with VTT dots
|
||||
if "-->" in line:
|
||||
out.append(line.replace(",", "."))
|
||||
else:
|
||||
out.append(line)
|
||||
return "\n".join(out)
|
||||
Reference in New Issue
Block a user