[media] Support HEAD method on media stream endpoints.

This commit is contained in:
Fabio Manganiello 2024-10-19 17:02:39 +02:00
parent 4373d4ceaa
commit fa942b06e3
Signed by untrusted user: blacklight
GPG key ID: D90FBA7F76362774
2 changed files with 32 additions and 9 deletions

View file

@ -17,7 +17,7 @@ class MediaStreamRoute(StreamingRoute):
Route for media streams. Route for media streams.
""" """
SUPPORTED_METHODS = ['GET', 'PUT', 'DELETE'] SUPPORTED_METHODS = ['GET', 'HEAD', 'PUT', 'DELETE']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@ -50,6 +50,23 @@ class MediaStreamRoute(StreamingRoute):
except Exception as e: except Exception as e:
self._on_error(e) self._on_error(e)
def head(self, media_id: Optional[str] = None):
"""
Streams a media resource by ID.
"""
if not media_id:
self.finish()
return
# Strip the extension
media_id = '.'.join(media_id.split('.')[:-1])
try:
self.stream_media(media_id, head=True)
except Exception as e:
self._on_error(e)
def put(self, *_, **__): def put(self, *_, **__):
""" """
The `PUT` route is used to prepare a new media resource for streaming. The `PUT` route is used to prepare a new media resource for streaming.
@ -93,10 +110,10 @@ class MediaStreamRoute(StreamingRoute):
""" """
Returns the list of registered media resources. Returns the list of registered media resources.
""" """
self.add_header('Content-Type', 'application/json') self.set_header('Content-Type', 'application/json')
self.finish(json.dumps([dict(media) for media in load_media_map().values()])) self.finish(json.dumps([dict(media) for media in load_media_map().values()]))
def stream_media(self, media_id: str): def stream_media(self, media_id: str, head: bool = False):
""" """
Route to stream a media file given its ID. Route to stream a media file given its ID.
""" """
@ -107,11 +124,11 @@ class MediaStreamRoute(StreamingRoute):
range_hdr = self.request.headers.get('Range') range_hdr = self.request.headers.get('Range')
content_length = media_hndl.content_length content_length = media_hndl.content_length
self.add_header('Accept-Ranges', 'bytes') self.set_header('Accept-Ranges', 'bytes')
self.add_header('Content-Type', media_hndl.mime_type) self.set_header('Content-Type', media_hndl.mime_type)
if 'download' in self.request.arguments: if 'download' in self.request.arguments:
self.add_header( self.set_header(
'Content-Disposition', 'Content-Disposition',
'attachment' 'attachment'
+ ('; filename="{media_hndl.filename}"' if media_hndl.filename else ''), + ('; filename="{media_hndl.filename}"' if media_hndl.filename else ''),
@ -129,7 +146,7 @@ class MediaStreamRoute(StreamingRoute):
content_length = to_bytes - from_bytes content_length = to_bytes - from_bytes
self.set_status(206) self.set_status(206)
self.add_header( self.set_header(
'Content-Range', 'Content-Range',
f'bytes {from_bytes}-{to_bytes}/{media_hndl.content_length}', f'bytes {from_bytes}-{to_bytes}/{media_hndl.content_length}',
) )
@ -137,7 +154,13 @@ class MediaStreamRoute(StreamingRoute):
from_bytes = 0 from_bytes = 0
to_bytes = STREAMING_BLOCK_SIZE to_bytes = STREAMING_BLOCK_SIZE
self.add_header('Content-Length', str(content_length)) self.set_header('Content-Length', str(content_length))
if head:
self.flush()
self.finish()
return
for chunk in media_hndl.get_data( for chunk in media_hndl.get_data(
from_bytes=from_bytes, from_bytes=from_bytes,
to_bytes=to_bytes, to_bytes=to_bytes,

View file

@ -36,7 +36,7 @@ class FileHandler(MediaHandler):
), f'{source} is not a valid media file (detected format: {self.mime_type})' ), f'{source} is not a valid media file (detected format: {self.mime_type})'
self.extension = mimetypes.guess_extension(self.mime_type) self.extension = mimetypes.guess_extension(self.mime_type)
if self.url and self.extension: if self.url and self.extension and not self.url.endswith(self.extension):
self.url += self.extension self.url += self.extension
self.content_length = os.path.getsize(self.path) self.content_length = os.path.getsize(self.path)