annotate 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
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
6
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
1 import asyncio
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
2 from dataclasses import dataclass
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
3 from pathlib import Path
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
4 import hashlib
3
ee55ed10faec start py service deployment
drewp@bigasterisk.com
parents: 0
diff changeset
5 import logging
6
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
6 import re
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
7 from typing import Iterable
5
75b54be050bc show one subdir of archive at once, with folders and parents-breadcrumbs
drewp@bigasterisk.com
parents: 4
diff changeset
8
3
ee55ed10faec start py service deployment
drewp@bigasterisk.com
parents: 0
diff changeset
9 from prometheus_client import Gauge
ee55ed10faec start py service deployment
drewp@bigasterisk.com
parents: 0
diff changeset
10 from starlette.applications import Starlette
ee55ed10faec start py service deployment
drewp@bigasterisk.com
parents: 0
diff changeset
11 from starlette.requests import Request
4
c8a41359505c server provides video listing from disk
drewp@bigasterisk.com
parents: 3
diff changeset
12 from starlette.responses import HTMLResponse, JSONResponse
3
ee55ed10faec start py service deployment
drewp@bigasterisk.com
parents: 0
diff changeset
13 from starlette.routing import Route
ee55ed10faec start py service deployment
drewp@bigasterisk.com
parents: 0
diff changeset
14 from starlette_exporter import PrometheusMiddleware, handle_metrics
5
75b54be050bc show one subdir of archive at once, with folders and parents-breadcrumbs
drewp@bigasterisk.com
parents: 4
diff changeset
15
6
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
16 from video_service import VideoFile
0
drewp@bigasterisk.com
parents:
diff changeset
17
3
ee55ed10faec start py service deployment
drewp@bigasterisk.com
parents: 0
diff changeset
18 logging.basicConfig(level=logging.DEBUG)
ee55ed10faec start py service deployment
drewp@bigasterisk.com
parents: 0
diff changeset
19 log = logging.getLogger()
0
drewp@bigasterisk.com
parents:
diff changeset
20
6
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
21 def vf(p: Path, label: str):
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
22 return VideoFile(p, './files/' + str(p.relative_to('/data')), label)
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
23
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
24 def thumbWebPath(rel: str)->str:
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
25 return './files/' + rel
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
26
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
27 @dataclass
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
28 class VideoFileStore:
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
29 top: Path
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
30
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
31 def findInDir(self, subdir: str) -> Iterable[VideoFile]:
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
32 if subdir[0] != '/': raise ValueError
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
33 here = self.top / subdir[1:]
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
34 manifests = list(here.glob('*.mpd'))
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
35 if manifests:
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
36 p = manifests[0]
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
37 label = p.parent.name
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
38 yield vf(p, label)
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
39 return
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
40 for p in sorted(list(here.glob('*.mp4')) + list(here.glob('*.webm'))):
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
41 label = re.sub(r' \[[^\]]+\]\.\w+', '', p.name)
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
42 yield vf(p, label)
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
43
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
44
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
45 def findSubdirs(self, subdir: str) -> Iterable:
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
46 if subdir[0] != '/': raise ValueError
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
47 here = self.top / subdir[1:]
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
48 for p in here.iterdir():
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
49 if p.is_dir() and p.name not in {'_thumb'}:
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
50 yield {'label': p.name, 'path': '/' + str(p.relative_to(self.top))}
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
51
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
52 def thumbPath(self, vf: VideoFile) -> str:
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
53 sha256 = hashlib.sha256()
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
54 with open(vf.diskPath, 'rb') as f:
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
55 firstMb = f.read(1<<20)
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
56 sha256.update(firstMb)
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
57 cksum = sha256.hexdigest()
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
58 return f'_thumb/{cksum}.jpg'
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
59
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
60 async def getOrCreateThumb(self, vf: VideoFile) -> str:
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
61 p = self.top / self.thumbPath(vf)
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
62 if not p.exists():
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
63 sp = asyncio.create_subprocess_exec('ffmpegthumbnailer',
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
64 '-s', '250',
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
65 '-i', str(vf.diskPath),
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
66 '-o', str(p))
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
67 await sp
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
68 return thumbWebPath(str(p.relative_to(self.top)))
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
69
0
drewp@bigasterisk.com
parents:
diff changeset
70
3
ee55ed10faec start py service deployment
drewp@bigasterisk.com
parents: 0
diff changeset
71 def root(req):
ee55ed10faec start py service deployment
drewp@bigasterisk.com
parents: 0
diff changeset
72 return HTMLResponse("api")
0
drewp@bigasterisk.com
parents:
diff changeset
73
drewp@bigasterisk.com
parents:
diff changeset
74
6
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
75 async def videos(req: Request) -> JSONResponse:
5
75b54be050bc show one subdir of archive at once, with folders and parents-breadcrumbs
drewp@bigasterisk.com
parents: 4
diff changeset
76 subdir = req.query_params.get('subdir', '/') # danger user input
6
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
77 vfInDir = store.findInDir(subdir)
4
c8a41359505c server provides video listing from disk
drewp@bigasterisk.com
parents: 3
diff changeset
78 return JSONResponse({
c8a41359505c server provides video listing from disk
drewp@bigasterisk.com
parents: 3
diff changeset
79 "videos": [{
c8a41359505c server provides video listing from disk
drewp@bigasterisk.com
parents: 3
diff changeset
80 'webRelPath': vf.webRelPath,
c8a41359505c server provides video listing from disk
drewp@bigasterisk.com
parents: 3
diff changeset
81 'label': vf.label,
6
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
82 'thumbRelPath': await store.getOrCreateThumb(vf),
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
83 } for vf in vfInDir],
5
75b54be050bc show one subdir of archive at once, with folders and parents-breadcrumbs
drewp@bigasterisk.com
parents: 4
diff changeset
84 "subdirs":
6
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
85 list(store.findSubdirs(subdir)),
4
c8a41359505c server provides video listing from disk
drewp@bigasterisk.com
parents: 3
diff changeset
86 })
c8a41359505c server provides video listing from disk
drewp@bigasterisk.com
parents: 3
diff changeset
87
6
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
88 store = VideoFileStore(top=Path('/data'))
4
c8a41359505c server provides video listing from disk
drewp@bigasterisk.com
parents: 3
diff changeset
89
c8a41359505c server provides video listing from disk
drewp@bigasterisk.com
parents: 3
diff changeset
90 def main():
3
ee55ed10faec start py service deployment
drewp@bigasterisk.com
parents: 0
diff changeset
91
6
ccfea3625cf6 render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents: 5
diff changeset
92
3
ee55ed10faec start py service deployment
drewp@bigasterisk.com
parents: 0
diff changeset
93 app = Starlette(
ee55ed10faec start py service deployment
drewp@bigasterisk.com
parents: 0
diff changeset
94 debug=True,
ee55ed10faec start py service deployment
drewp@bigasterisk.com
parents: 0
diff changeset
95 routes=[
4
c8a41359505c server provides video listing from disk
drewp@bigasterisk.com
parents: 3
diff changeset
96 Route('/video/api/', root),
c8a41359505c server provides video listing from disk
drewp@bigasterisk.com
parents: 3
diff changeset
97 Route('/video/api/videos', videos),
3
ee55ed10faec start py service deployment
drewp@bigasterisk.com
parents: 0
diff changeset
98 ],
ee55ed10faec start py service deployment
drewp@bigasterisk.com
parents: 0
diff changeset
99 )
ee55ed10faec start py service deployment
drewp@bigasterisk.com
parents: 0
diff changeset
100
ee55ed10faec start py service deployment
drewp@bigasterisk.com
parents: 0
diff changeset
101 app.add_middleware(PrometheusMiddleware, app_name='video_api')
ee55ed10faec start py service deployment
drewp@bigasterisk.com
parents: 0
diff changeset
102 app.add_route("/metrics", handle_metrics)
4
c8a41359505c server provides video listing from disk
drewp@bigasterisk.com
parents: 3
diff changeset
103 return app
3
ee55ed10faec start py service deployment
drewp@bigasterisk.com
parents: 0
diff changeset
104
ee55ed10faec start py service deployment
drewp@bigasterisk.com
parents: 0
diff changeset
105
4
c8a41359505c server provides video listing from disk
drewp@bigasterisk.com
parents: 3
diff changeset
106 app = main()