Mercurial > code > home > repos > video
annotate 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 |
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 |
44
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
21 from urllib.parse import unquote |
18 | 22 |
3 | 23 logging.basicConfig(level=logging.DEBUG) |
24 log = logging.getLogger() | |
17
071943adf000
dnd a file or a url which we'll queue and fetch
drewp@bigasterisk.com
parents:
15
diff
changeset
|
25 logging.getLogger('sse_starlette').setLevel(logging.WARNING) |
32 | 26 logging.getLogger('pymongo').setLevel(logging.INFO) |
0 | 27 |
28 | |
3 | 29 def root(req): |
30 return HTMLResponse("api") | |
0 | 31 |
32 | |
6
ccfea3625cf6
render thumbs and display them (no video player at all atm)
drewp@bigasterisk.com
parents:
5
diff
changeset
|
33 async def videos(req: Request) -> JSONResponse: |
44
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
34 # either like /dir1/dir2/ or /dir1/dir2/vid1 |
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
|
35 subdir = req.query_params.get('subdir', '/') |
44
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
36 |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
37 subdir = unquote(subdir) |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
38 webDirRelPath = subdir.rsplit('/', 1)[0] + '/' |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
39 autoplayRelPath = subdir if not subdir.endswith('/') else None |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
40 |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
41 log.info(f'loading {webDirRelPath=} {autoplayRelPath=}') |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
42 |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
43 assert webDirRelPath.startswith('/') |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
44 assert webDirRelPath.endswith('/') |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
45 |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
46 resp: dict[str, object] = { |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
47 'webDirRelPath': webDirRelPath, |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
48 'dirLabel': webDirRelPath.strip('/').split('/')[-1], #todo |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
49 } |
39 | 50 |
44
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
51 d = webDirRelPath[1:-1] or '.' |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
52 log.info(f'loading {d=}') |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
53 vfInDir = list(store.findInDir(d)) |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
54 resp["videos"] = [{ |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
55 'webRelPath': '/' + vf.webRelPath, |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
56 'webDataPath': '/' + vf.webDataPath, |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
57 'label': vf.label, |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
58 } for vf in vfInDir] |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
59 |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
60 if autoplayRelPath: |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
61 for vf in vfInDir: |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
62 if '/' + vf.webRelPath == autoplayRelPath: |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
63 resp['autoplay'] = { |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
64 'webRelPath': '/' + vf.webRelPath, |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
65 'webDataPath': '/' + vf.webDataPath, |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
66 'label': vf.label |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
67 } |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
68 break |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
69 else: |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
70 raise ValueError(f'{autoplayRelPath=} not in dir') |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
71 |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
72 log.info(f'{subdir=}') |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
73 resp['subdirs'] = [] |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
74 for s in store.findSubdirs(subdir.strip('/') or '/'): |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
75 resp['subdirs'].append({ |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
76 'label': s['label'], |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
77 'path': '/' + s['path'] + '/', |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
78 }) |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
79 |
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
80 return JSONResponse(resp) |
4
c8a41359505c
server provides video listing from disk
drewp@bigasterisk.com
parents:
3
diff
changeset
|
81 |
15 | 82 |
20 | 83 def folderTree(req: Request) -> JSONResponse: |
84 return JSONResponse(store.folderTree()) | |
85 | |
86 | |
15 | 87 async def ingestVideoUrl(req: Request) -> Response: |
23
9e56e86a6814
server supports downloading into a given folder
drewp@bigasterisk.com
parents:
20
diff
changeset
|
88 folder = req.query_params['folder'] |
15 | 89 url = await req.body() |
23
9e56e86a6814
server supports downloading into a given folder
drewp@bigasterisk.com
parents:
20
diff
changeset
|
90 await svc.ingestUrl(url.decode('utf8'), folder) |
15 | 91 return Response(status_code=202) |
92 | |
93 | |
94 async def ingestVideoUpload(req: Request) -> Response: | |
95 name = req.query_params['name'] | |
96 await svc.addContent(name, req.body()) | |
97 return Response(status_code=200) | |
98 | |
99 | |
100 async def ingestQueue(req: Request) -> EventSourceResponse: | |
18 | 101 |
17
071943adf000
dnd a file or a url which we'll queue and fetch
drewp@bigasterisk.com
parents:
15
diff
changeset
|
102 async def g(): |
071943adf000
dnd a file or a url which we'll queue and fetch
drewp@bigasterisk.com
parents:
15
diff
changeset
|
103 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
|
104 yield json.dumps(ev) |
18 | 105 |
17
071943adf000
dnd a file or a url which we'll queue and fetch
drewp@bigasterisk.com
parents:
15
diff
changeset
|
106 return EventSourceResponse(g()) |
15 | 107 |
39 | 108 |
37
7cacfae58430
thumbnails rewrite - store in db; don't use YT-provided pics for now
drewp@bigasterisk.com
parents:
36
diff
changeset
|
109 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
|
110 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
|
111 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
|
112 raise ValueError |
7cacfae58430
thumbnails rewrite - store in db; don't use YT-provided pics for now
drewp@bigasterisk.com
parents:
36
diff
changeset
|
113 return doc['diskPath'] |
7cacfae58430
thumbnails rewrite - store in db; don't use YT-provided pics for now
drewp@bigasterisk.com
parents:
36
diff
changeset
|
114 |
39 | 115 |
116 async def getThumbnail(db: pymongo.database.Database, | |
117 req: Request) -> Response: | |
44
239a83d46d48
make the server return urls with the (new) correct slashes
drewp@bigasterisk.com
parents:
39
diff
changeset
|
118 webRelPath = req.query_params['webRelPath'].lstrip('/') |
37
7cacfae58430
thumbnails rewrite - store in db; don't use YT-provided pics for now
drewp@bigasterisk.com
parents:
36
diff
changeset
|
119 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
|
120 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
|
121 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
|
122 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
|
123 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
|
124 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
|
125 |
15 | 126 |
36
ed16fdbb3996
rewrite WIP. scan fs separately; store in db. thumbs are broken for now
drewp@bigasterisk.com
parents:
32
diff
changeset
|
127 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
|
128 store = VideoFileStore(db.get_collection('fs')) |
15 | 129 svc = VideoIngest(store) |
130 | |
18 | 131 |
4
c8a41359505c
server provides video listing from disk
drewp@bigasterisk.com
parents:
3
diff
changeset
|
132 def main(): |
3 | 133 |
134 app = Starlette( | |
135 debug=True, | |
136 routes=[ | |
4
c8a41359505c
server provides video listing from disk
drewp@bigasterisk.com
parents:
3
diff
changeset
|
137 Route('/video/api/', root), |
c8a41359505c
server provides video listing from disk
drewp@bigasterisk.com
parents:
3
diff
changeset
|
138 Route('/video/api/videos', videos), |
20 | 139 Route('/video/api/folderTree', folderTree), |
15 | 140 Route('/video/api/ingest/videoUpload', |
141 ingestVideoUpload, | |
142 methods=['POST']), | |
143 Route('/video/api/ingest/videoUrl', | |
144 ingestVideoUrl, | |
145 methods=['POST']), | |
146 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
|
147 Route('/video/api/thumbnail', partial(getThumbnail, db)), |
3 | 148 ], |
149 ) | |
150 | |
151 app.add_middleware(PrometheusMiddleware, app_name='video_api') | |
25 | 152 app.add_route("/video/api/metrics", handle_metrics) |
27 | 153 app.add_route("/metrics", handle_metrics) |
18 | 154 |
17
071943adf000
dnd a file or a url which we'll queue and fetch
drewp@bigasterisk.com
parents:
15
diff
changeset
|
155 app.state.processTask = asyncio.create_task(dl_queue.process()) |
4
c8a41359505c
server provides video listing from disk
drewp@bigasterisk.com
parents:
3
diff
changeset
|
156 return app |
3 | 157 |
39 | 158 |
28
1e058bea3ac2
crash better when mongo is unreachable
drewp@bigasterisk.com
parents:
27
diff
changeset
|
159 uvicorn.run(main, |
1e058bea3ac2
crash better when mongo is unreachable
drewp@bigasterisk.com
parents:
27
diff
changeset
|
160 host="0.0.0.0", |
1e058bea3ac2
crash better when mongo is unreachable
drewp@bigasterisk.com
parents:
27
diff
changeset
|
161 port=8004, |
1e058bea3ac2
crash better when mongo is unreachable
drewp@bigasterisk.com
parents:
27
diff
changeset
|
162 log_level=logging.INFO, |
1e058bea3ac2
crash better when mongo is unreachable
drewp@bigasterisk.com
parents:
27
diff
changeset
|
163 factory=True) |