#Streaming response for video Static files with correct range requests/responses for seeking function

1 messages · Page 1 of 1 (latest)

nimble hamlet
#

Problem: I'm serving medium size videos (approximately 20Mb each) using litestar's static file router from litestar.static_files import create_static_files_router, and I need to play these videos on the frontend. However, browsers require specific headers like content-length, content-range, accept-ranges, and content-encoding etc for seeking functionality.

Current stupid workaround:
I just add header, but it doesn't truly solve the seeking problem, and eats bandwidth like crazy.

class VideoHeaderMiddleware(AbstractMiddleware):
    """
    Check if any header is Content-Type and starts with 'video/'
    If true, add 'Accept-Ranges: bytes' header
    """

    async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
        async def modified_send(message):
            if message["type"] == "http.response.start":
                headers = message.get("headers", [])

                # Quick check for video content type
                if any(k.lower() == b'content-type' and v.lower().startswith(b'video/') for k, v in headers):
                    # Append Accept-Ranges header
                    message["headers"] = [*headers, (b'Accept-Ranges', b'bytes')]

            await send(message)

        await self.app(scope, receive, modified_send)

create_static_files_router(
    middleware=[jwt_cookie_auth.middleware],
    path="/static",
    directories=[
        # ...
    ],
    send_as_attachment=False,
    middleware=[VideoHeaderMiddleware]
),

The problem is that this results in multiple redundant requests (duplicate requests each 20Mb ). So, it is not truly streaming response with proper chunk sizes but at least seeking is working

Anyone else had a similar problem? Any ideas?

graceful questBOT
#
Notes for Streaming response for video Static files with correct range requests/responses for seeking function
At your assistance

@nimble hamlet

No Response?

If no response in a reasonable time, ping @Member.

Closing

To close, type !solve or byte solve.

MCVE

Please include an MCVE so that we can reproduce your issue locally.

nimble hamlet
#

I found a similar issue on fastapi rep https://github.com/fastapi/fastapi/issues/1240, but it seems like it already does what litestar's

  litestar.response.streaming
class Stream(Response[StreamType[Union[str, bytes]]])

does? Maybe use Stream class with router's hook after_request?

regal birchBOT
# nimble hamlet I found a similar issue on fastapi rep https://github.com/fastapi/fastapi/issues...

First check

  • I checked StreamingResponse (along with the related issues) and can stream a video properly.

Description

I was wondering if it was possible using fastapi to use "StreamingResponse" not only to stream a video, but to be able to seek (with byte-range i guess ?)

Additional context

I am trying to reimplement a similar software to peerflix (https://github.com/mafintosh/peerflix), which basically downloads a content, and stream it then. It uses nodejs, which I would like to avoid, and i was wondering if it was possible to do such thing with fastapi. (some people achieved it with other technology : https://github.com/romanvm/kodi.yatp )

Labels

question, question-migrate

floral jay
#

The static files router does not support range request out of the box

#

If you need this, you'll have to implement it yourself using the Stream response type

#

Would be a reasonable feature request though if you want to open one 🙂

nimble hamlet
# floral jay Would be a reasonable feature request though if you want to open one 🙂
class Stream(Response[StreamType[Union[str, bytes]]]):
    """An HTTP response that streams the response data as a series of ASGI ``http.response.body`` events."""

   # ...
   
        if app is not None:
            warn_deprecation(
                version="2.1",
                deprecated_name="app",
                kind="parameter",
                removal_in="3.0.0",
                alternative="request.app",
            )

Is that a deprecated class for removal in 3.0.0?

floral jay
#

No, it is not

#

If you read the deprecation warning, you'll see that it's for the app parameter of that particular method, not the class

nimble hamlet
#

If anyone ends up searching for a solution for litestar, here is the middleware I use for static files. I made it for my specific case