Mercurial > code > home > repos > video
view video.py @ 44:239a83d46d48
make the server return urls with the (new) correct slashes
author | drewp@bigasterisk.com |
---|---|
date | Fri, 06 Dec 2024 01:01:05 -0800 |
parents | b5b29f6ef5cb |
children | 882d0bb0f801 |
line wrap: on
line source
import asyncio from functools import partial import json import logging import uvicorn from prometheus_client import Gauge from sse_starlette.sse import EventSourceResponse from starlette.applications import Starlette from starlette.requests import Request from starlette.responses import HTMLResponse, JSONResponse, Response from starlette.routing import Route from starlette_exporter import PrometheusMiddleware, handle_metrics import dl_queue from video_file_store import VideoFileStore from video_ingest import VideoIngest from mongo_required import open_mongo_or_die import pymongo.database import thumbnail from urllib.parse import unquote logging.basicConfig(level=logging.DEBUG) log = logging.getLogger() logging.getLogger('sse_starlette').setLevel(logging.WARNING) logging.getLogger('pymongo').setLevel(logging.INFO) def root(req): return HTMLResponse("api") async def videos(req: Request) -> JSONResponse: # either like /dir1/dir2/ or /dir1/dir2/vid1 subdir = req.query_params.get('subdir', '/') subdir = unquote(subdir) webDirRelPath = subdir.rsplit('/', 1)[0] + '/' autoplayRelPath = subdir if not subdir.endswith('/') else None log.info(f'loading {webDirRelPath=} {autoplayRelPath=}') assert webDirRelPath.startswith('/') assert webDirRelPath.endswith('/') resp: dict[str, object] = { 'webDirRelPath': webDirRelPath, 'dirLabel': webDirRelPath.strip('/').split('/')[-1], #todo } d = webDirRelPath[1:-1] or '.' log.info(f'loading {d=}') vfInDir = list(store.findInDir(d)) resp["videos"] = [{ 'webRelPath': '/' + vf.webRelPath, 'webDataPath': '/' + vf.webDataPath, 'label': vf.label, } for vf in vfInDir] if autoplayRelPath: for vf in vfInDir: if '/' + vf.webRelPath == autoplayRelPath: resp['autoplay'] = { 'webRelPath': '/' + vf.webRelPath, 'webDataPath': '/' + vf.webDataPath, 'label': vf.label } break else: raise ValueError(f'{autoplayRelPath=} not in dir') log.info(f'{subdir=}') resp['subdirs'] = [] for s in store.findSubdirs(subdir.strip('/') or '/'): resp['subdirs'].append({ 'label': s['label'], 'path': '/' + s['path'] + '/', }) return JSONResponse(resp) def folderTree(req: Request) -> JSONResponse: return JSONResponse(store.folderTree()) async def ingestVideoUrl(req: Request) -> Response: folder = req.query_params['folder'] url = await req.body() await svc.ingestUrl(url.decode('utf8'), folder) return Response(status_code=202) async def ingestVideoUpload(req: Request) -> Response: name = req.query_params['name'] await svc.addContent(name, req.body()) return Response(status_code=200) async def ingestQueue(req: Request) -> EventSourceResponse: async def g(): async for ev in svc.events(): yield json.dumps(ev) return EventSourceResponse(g()) def getDiskPath(fs, webRelPath): doc = fs.find_one({'webRelPath': webRelPath}) if doc is None: raise ValueError return doc['diskPath'] async def getThumbnail(db: pymongo.database.Database, req: Request) -> Response: webRelPath = req.query_params['webRelPath'].lstrip('/') fs = db.get_collection('fs') diskPath = getDiskPath(fs, webRelPath) th = db.get_collection('thumb') async with asyncio.timeout(10): data = await thumbnail.getThumbnailData(th, diskPath) return Response(content=data, media_type='image/jpeg') db = open_mongo_or_die().get_database('video') store = VideoFileStore(db.get_collection('fs')) svc = VideoIngest(store) def main(): app = Starlette( debug=True, routes=[ Route('/video/api/', root), Route('/video/api/videos', videos), Route('/video/api/folderTree', folderTree), Route('/video/api/ingest/videoUpload', ingestVideoUpload, methods=['POST']), Route('/video/api/ingest/videoUrl', ingestVideoUrl, methods=['POST']), Route('/video/api/ingest/queue', ingestQueue), Route('/video/api/thumbnail', partial(getThumbnail, db)), ], ) app.add_middleware(PrometheusMiddleware, app_name='video_api') app.add_route("/video/api/metrics", handle_metrics) app.add_route("/metrics", handle_metrics) app.state.processTask = asyncio.create_task(dl_queue.process()) return app uvicorn.run(main, host="0.0.0.0", port=8004, log_level=logging.INFO, factory=True)