Mercurial > code > home > repos > video
annotate video.py @ 38:0aea9e55899b
hack in path router - dirs kind of work; putting a video in the path doesn't
author | drewp@bigasterisk.com |
---|---|
date | Wed, 04 Dec 2024 21:50:16 -0800 |
parents | 7cacfae58430 |
children | b5b29f6ef5cb |
rev | line source |
---|---|
17
071943adf000
dnd a file or a url which we'll queue and fetch
drewp@bigasterisk.com
parents:
15
diff
changeset
|
1 import asyncio |
37
7cacfae58430
thumbnails rewrite - store in db; don't use YT-provided pics for now
drewp@bigasterisk.com
parents:
36
diff
changeset
|
2 from functools import partial |
17
071943adf000
dnd a file or a url which we'll queue and fetch
drewp@bigasterisk.com
parents:
15
diff
changeset
|
3 import json |
15 | 4 import logging |
5
75b54be050bc
show one subdir of archive at once, with folders and parents-breadcrumbs
drewp@bigasterisk.com
parents:
4
diff
changeset
|
5 |
28
1e058bea3ac2
crash better when mongo is unreachable
drewp@bigasterisk.com
parents:
27
diff
changeset
|
6 import uvicorn |
3 | 7 from prometheus_client import Gauge |
28
1e058bea3ac2
crash better when mongo is unreachable
drewp@bigasterisk.com
parents:
27
diff
changeset
|
8 from sse_starlette.sse import EventSourceResponse |
3 | 9 from starlette.applications import Starlette |
10 from starlette.requests import Request | |
15 | 11 from starlette.responses import HTMLResponse, JSONResponse, Response |
3 | 12 from starlette.routing import Route |
13 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
|
14 |
28
1e058bea3ac2
crash better when mongo is unreachable
drewp@bigasterisk.com
parents:
27
diff
changeset
|
15 import dl_queue |
15 | 16 from video_file_store import VideoFileStore |
17 from video_ingest import VideoIngest | |
36
ed16fdbb3996
rewrite WIP. scan fs separately; store in db. thumbs are broken for now
drewp@bigasterisk.com
parents:
32
diff
changeset
|
18 from mongo_required import open_mongo_or_die |
37
7cacfae58430
thumbnails rewrite - store in db; don't use YT-provided pics for now
drewp@bigasterisk.com
parents:
36
diff
changeset
|
19 import pymongo.database |
7cacfae58430
thumbnails rewrite - store in db; don't use YT-provided pics for now
drewp@bigasterisk.com
parents:
36
diff
changeset
|
20 import thumbnail |
18 | 21 |
3 | 22 logging.basicConfig(level=logging.DEBUG) |
23 log = logging.getLogger() | |
17
071943adf000
dnd a file or a url which we'll queue and fetch
drewp@bigasterisk.com
parents:
15
diff
changeset
|
24 logging.getLogger('sse_starlette').setLevel(logging.WARNING) |
32 | 25 logging.getLogger('pymongo').setLevel(logging.INFO) |
0 | 26 |
27 | |
3 | 28 def root(req): |
29 return HTMLResponse("api") | |
0 | 30 |
31 | |
6
ccfea3625cf6
render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents:
5
diff
changeset
|
32 async def videos(req: Request) -> JSONResponse: |
38
0aea9e55899b
hack in path router - dirs kind of work; putting a video in the path doesn't
drewp@bigasterisk.com
parents:
37
diff
changeset
|
33 subdir = req.query_params.get('subdir', '/') |
0aea9e55899b
hack in path router - dirs kind of work; putting a video in the path doesn't
drewp@bigasterisk.com
parents:
37
diff
changeset
|
34 if not subdir.endswith('/'): |
0aea9e55899b
hack in path router - dirs kind of work; putting a video in the path doesn't
drewp@bigasterisk.com
parents:
37
diff
changeset
|
35 # raise ValueError(f'not a dir {subdir=}') |
0aea9e55899b
hack in path router - dirs kind of work; putting a video in the path doesn't
drewp@bigasterisk.com
parents:
37
diff
changeset
|
36 # ok we'll list the parent dir underneath |
0aea9e55899b
hack in path router - dirs kind of work; putting a video in the path doesn't
drewp@bigasterisk.com
parents:
37
diff
changeset
|
37 subdir = '/'.join(subdir.split('/')[:-1]) # todo move to FE |
0aea9e55899b
hack in path router - dirs kind of work; putting a video in the path doesn't
drewp@bigasterisk.com
parents:
37
diff
changeset
|
38 else: |
0aea9e55899b
hack in path router - dirs kind of work; putting a video in the path doesn't
drewp@bigasterisk.com
parents:
37
diff
changeset
|
39 subdir = subdir[:-1] |
0aea9e55899b
hack in path router - dirs kind of work; putting a video in the path doesn't
drewp@bigasterisk.com
parents:
37
diff
changeset
|
40 if subdir=="": |
0aea9e55899b
hack in path router - dirs kind of work; putting a video in the path doesn't
drewp@bigasterisk.com
parents:
37
diff
changeset
|
41 subdir = "./" |
0aea9e55899b
hack in path router - dirs kind of work; putting a video in the path doesn't
drewp@bigasterisk.com
parents:
37
diff
changeset
|
42 if not (subdir.startswith('/') or subdir=='./'): |
0aea9e55899b
hack in path router - dirs kind of work; putting a video in the path doesn't
drewp@bigasterisk.com
parents:
37
diff
changeset
|
43 raise ValueError(f'not a dir {subdir=}') |
0aea9e55899b
hack in path router - dirs kind of work; putting a video in the path doesn't
drewp@bigasterisk.com
parents:
37
diff
changeset
|
44 subdir = subdir[1:] |
0aea9e55899b
hack in path router - dirs kind of work; putting a video in the path doesn't
drewp@bigasterisk.com
parents:
37
diff
changeset
|
45 log.debug(f'videos request corrected to: {subdir=}') |
0aea9e55899b
hack in path router - dirs kind of work; putting a video in the path doesn't
drewp@bigasterisk.com
parents:
37
diff
changeset
|
46 |
6
ccfea3625cf6
render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents:
5
diff
changeset
|
47 vfInDir = store.findInDir(subdir) |
4
c8a41359505c
server provides video listing from disk
drewp@bigasterisk.com
parents:
3
diff
changeset
|
48 return JSONResponse({ |
c8a41359505c
server provides video listing from disk
drewp@bigasterisk.com
parents:
3
diff
changeset
|
49 "videos": [{ |
c8a41359505c
server provides video listing from disk
drewp@bigasterisk.com
parents:
3
diff
changeset
|
50 'webRelPath': vf.webRelPath, |
36
ed16fdbb3996
rewrite WIP. scan fs separately; store in db. thumbs are broken for now
drewp@bigasterisk.com
parents:
32
diff
changeset
|
51 'webDataPath': vf.webDataPath, |
4
c8a41359505c
server provides video listing from disk
drewp@bigasterisk.com
parents:
3
diff
changeset
|
52 'label': vf.label, |
6
ccfea3625cf6
render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents:
5
diff
changeset
|
53 } 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
|
54 "subdirs": |
6
ccfea3625cf6
render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents:
5
diff
changeset
|
55 list(store.findSubdirs(subdir)), |
4
c8a41359505c
server provides video listing from disk
drewp@bigasterisk.com
parents:
3
diff
changeset
|
56 }) |
c8a41359505c
server provides video listing from disk
drewp@bigasterisk.com
parents:
3
diff
changeset
|
57 |
15 | 58 |
20 | 59 def folderTree(req: Request) -> JSONResponse: |
60 return JSONResponse(store.folderTree()) | |
61 | |
62 | |
15 | 63 async def ingestVideoUrl(req: Request) -> Response: |
23
9e56e86a6814
server supports downloading into a given folder
drewp@bigasterisk.com
parents:
20
diff
changeset
|
64 folder = req.query_params['folder'] |
15 | 65 url = await req.body() |
23
9e56e86a6814
server supports downloading into a given folder
drewp@bigasterisk.com
parents:
20
diff
changeset
|
66 await svc.ingestUrl(url.decode('utf8'), folder) |
15 | 67 return Response(status_code=202) |
68 | |
69 | |
70 async def ingestVideoUpload(req: Request) -> Response: | |
71 name = req.query_params['name'] | |
72 await svc.addContent(name, req.body()) | |
73 return Response(status_code=200) | |
74 | |
75 | |
76 async def ingestQueue(req: Request) -> EventSourceResponse: | |
18 | 77 |
17
071943adf000
dnd a file or a url which we'll queue and fetch
drewp@bigasterisk.com
parents:
15
diff
changeset
|
78 async def g(): |
071943adf000
dnd a file or a url which we'll queue and fetch
drewp@bigasterisk.com
parents:
15
diff
changeset
|
79 async for ev in svc.events(): |
071943adf000
dnd a file or a url which we'll queue and fetch
drewp@bigasterisk.com
parents:
15
diff
changeset
|
80 yield json.dumps(ev) |
18 | 81 |
17
071943adf000
dnd a file or a url which we'll queue and fetch
drewp@bigasterisk.com
parents:
15
diff
changeset
|
82 return EventSourceResponse(g()) |
15 | 83 |
37
7cacfae58430
thumbnails rewrite - store in db; don't use YT-provided pics for now
drewp@bigasterisk.com
parents:
36
diff
changeset
|
84 def getDiskPath(fs, webRelPath): |
7cacfae58430
thumbnails rewrite - store in db; don't use YT-provided pics for now
drewp@bigasterisk.com
parents:
36
diff
changeset
|
85 doc = fs.find_one({'webRelPath': webRelPath}) |
7cacfae58430
thumbnails rewrite - store in db; don't use YT-provided pics for now
drewp@bigasterisk.com
parents:
36
diff
changeset
|
86 if doc is None: |
7cacfae58430
thumbnails rewrite - store in db; don't use YT-provided pics for now
drewp@bigasterisk.com
parents:
36
diff
changeset
|
87 raise ValueError |
7cacfae58430
thumbnails rewrite - store in db; don't use YT-provided pics for now
drewp@bigasterisk.com
parents:
36
diff
changeset
|
88 return doc['diskPath'] |
7cacfae58430
thumbnails rewrite - store in db; don't use YT-provided pics for now
drewp@bigasterisk.com
parents:
36
diff
changeset
|
89 |
7cacfae58430
thumbnails rewrite - store in db; don't use YT-provided pics for now
drewp@bigasterisk.com
parents:
36
diff
changeset
|
90 async def getThumbnail(db: pymongo.database.Database, req: Request) -> Response: |
7cacfae58430
thumbnails rewrite - store in db; don't use YT-provided pics for now
drewp@bigasterisk.com
parents:
36
diff
changeset
|
91 webRelPath = req.query_params['webRelPath'] |
7cacfae58430
thumbnails rewrite - store in db; don't use YT-provided pics for now
drewp@bigasterisk.com
parents:
36
diff
changeset
|
92 fs = db.get_collection('fs') |
7cacfae58430
thumbnails rewrite - store in db; don't use YT-provided pics for now
drewp@bigasterisk.com
parents:
36
diff
changeset
|
93 diskPath = getDiskPath(fs, webRelPath) |
7cacfae58430
thumbnails rewrite - store in db; don't use YT-provided pics for now
drewp@bigasterisk.com
parents:
36
diff
changeset
|
94 th = db.get_collection('thumb') |
7cacfae58430
thumbnails rewrite - store in db; don't use YT-provided pics for now
drewp@bigasterisk.com
parents:
36
diff
changeset
|
95 async with asyncio.timeout(10): |
7cacfae58430
thumbnails rewrite - store in db; don't use YT-provided pics for now
drewp@bigasterisk.com
parents:
36
diff
changeset
|
96 data = await thumbnail.getThumbnailData(th, diskPath) |
7cacfae58430
thumbnails rewrite - store in db; don't use YT-provided pics for now
drewp@bigasterisk.com
parents:
36
diff
changeset
|
97 return Response(content=data, media_type='image/jpeg') |
7cacfae58430
thumbnails rewrite - store in db; don't use YT-provided pics for now
drewp@bigasterisk.com
parents:
36
diff
changeset
|
98 |
7cacfae58430
thumbnails rewrite - store in db; don't use YT-provided pics for now
drewp@bigasterisk.com
parents:
36
diff
changeset
|
99 |
15 | 100 |
36
ed16fdbb3996
rewrite WIP. scan fs separately; store in db. thumbs are broken for now
drewp@bigasterisk.com
parents:
32
diff
changeset
|
101 db = open_mongo_or_die().get_database('video') |
ed16fdbb3996
rewrite WIP. scan fs separately; store in db. thumbs are broken for now
drewp@bigasterisk.com
parents:
32
diff
changeset
|
102 store = VideoFileStore(db.get_collection('fs')) |
15 | 103 svc = VideoIngest(store) |
104 | |
18 | 105 |
4
c8a41359505c
server provides video listing from disk
drewp@bigasterisk.com
parents:
3
diff
changeset
|
106 def main(): |
3 | 107 |
108 app = Starlette( | |
109 debug=True, | |
110 routes=[ | |
4
c8a41359505c
server provides video listing from disk
drewp@bigasterisk.com
parents:
3
diff
changeset
|
111 Route('/video/api/', root), |
c8a41359505c
server provides video listing from disk
drewp@bigasterisk.com
parents:
3
diff
changeset
|
112 Route('/video/api/videos', videos), |
20 | 113 Route('/video/api/folderTree', folderTree), |
15 | 114 Route('/video/api/ingest/videoUpload', |
115 ingestVideoUpload, | |
116 methods=['POST']), | |
117 Route('/video/api/ingest/videoUrl', | |
118 ingestVideoUrl, | |
119 methods=['POST']), | |
120 Route('/video/api/ingest/queue', ingestQueue), | |
37
7cacfae58430
thumbnails rewrite - store in db; don't use YT-provided pics for now
drewp@bigasterisk.com
parents:
36
diff
changeset
|
121 Route('/video/api/thumbnail', partial(getThumbnail, db)), |
3 | 122 ], |
123 ) | |
124 | |
125 app.add_middleware(PrometheusMiddleware, app_name='video_api') | |
25 | 126 app.add_route("/video/api/metrics", handle_metrics) |
27 | 127 app.add_route("/metrics", handle_metrics) |
18 | 128 |
17
071943adf000
dnd a file or a url which we'll queue and fetch
drewp@bigasterisk.com
parents:
15
diff
changeset
|
129 app.state.processTask = asyncio.create_task(dl_queue.process()) |
4
c8a41359505c
server provides video listing from disk
drewp@bigasterisk.com
parents:
3
diff
changeset
|
130 return app |
3 | 131 |
28
1e058bea3ac2
crash better when mongo is unreachable
drewp@bigasterisk.com
parents:
27
diff
changeset
|
132 uvicorn.run(main, |
1e058bea3ac2
crash better when mongo is unreachable
drewp@bigasterisk.com
parents:
27
diff
changeset
|
133 host="0.0.0.0", |
1e058bea3ac2
crash better when mongo is unreachable
drewp@bigasterisk.com
parents:
27
diff
changeset
|
134 port=8004, |
1e058bea3ac2
crash better when mongo is unreachable
drewp@bigasterisk.com
parents:
27
diff
changeset
|
135 log_level=logging.INFO, |
1e058bea3ac2
crash better when mongo is unreachable
drewp@bigasterisk.com
parents:
27
diff
changeset
|
136 factory=True) |