Mercurial > code > home > repos > video
view video.py @ 12:e60be5d74c07
css edits and ingest link
author | drewp@bigasterisk.com |
---|---|
date | Sat, 15 Apr 2023 15:20:12 -0700 |
parents | ccfea3625cf6 |
children | 53d99454f394 |
line wrap: on
line source
import asyncio from dataclasses import dataclass from pathlib import Path import hashlib import logging import re from typing import Iterable from prometheus_client import Gauge from starlette.applications import Starlette from starlette.requests import Request from starlette.responses import HTMLResponse, JSONResponse from starlette.routing import Route from starlette_exporter import PrometheusMiddleware, handle_metrics from video_service import VideoFile logging.basicConfig(level=logging.DEBUG) log = logging.getLogger() def vf(p: Path, label: str): return VideoFile(p, './files/' + str(p.relative_to('/data')), label) def thumbWebPath(rel: str)->str: return './files/' + rel @dataclass class VideoFileStore: top: Path def findInDir(self, subdir: str) -> Iterable[VideoFile]: if subdir[0] != '/': raise ValueError here = self.top / subdir[1:] manifests = list(here.glob('*.mpd')) if manifests: p = manifests[0] label = p.parent.name yield vf(p, label) return for p in sorted(list(here.glob('*.mp4')) + list(here.glob('*.webm'))): label = re.sub(r' \[[^\]]+\]\.\w+', '', p.name) yield vf(p, label) def findSubdirs(self, subdir: str) -> Iterable: if subdir[0] != '/': raise ValueError here = self.top / subdir[1:] for p in here.iterdir(): if p.is_dir() and p.name not in {'_thumb'}: yield {'label': p.name, 'path': '/' + str(p.relative_to(self.top))} def thumbPath(self, vf: VideoFile) -> str: sha256 = hashlib.sha256() with open(vf.diskPath, 'rb') as f: firstMb = f.read(1<<20) sha256.update(firstMb) cksum = sha256.hexdigest() return f'_thumb/{cksum}.jpg' async def getOrCreateThumb(self, vf: VideoFile) -> str: p = self.top / self.thumbPath(vf) if not p.exists(): sp = asyncio.create_subprocess_exec('ffmpegthumbnailer', '-s', '250', '-i', str(vf.diskPath), '-o', str(p)) await sp return thumbWebPath(str(p.relative_to(self.top))) def root(req): return HTMLResponse("api") async def videos(req: Request) -> JSONResponse: subdir = req.query_params.get('subdir', '/') # danger user input vfInDir = store.findInDir(subdir) return JSONResponse({ "videos": [{ 'webRelPath': vf.webRelPath, 'label': vf.label, 'thumbRelPath': await store.getOrCreateThumb(vf), } for vf in vfInDir], "subdirs": list(store.findSubdirs(subdir)), }) store = VideoFileStore(top=Path('/data')) def main(): app = Starlette( debug=True, routes=[ Route('/video/api/', root), Route('/video/api/videos', videos), ], ) app.add_middleware(PrometheusMiddleware, app_name='video_api') app.add_route("/metrics", handle_metrics) return app app = main()