mirror of
https://github.com/rommapp/romm.git
synced 2026-02-18 23:42:07 +01:00
This change installs and configures the `mod_zip` nginx module [1], which allows nginx to stream ZIP files directly. It includes a workaround needed to correctly calculate CRC-32 values for included files, by including a new `server` section listening at port 8081, only used for the file requests to be upstream subrequests that correctly trigger the CRC-32 calculation logic. Also, to be able to provide a `m3u` file generated on the fly, we add a `/decode` endpoint fully implemented in nginx using NJS, which receives a `value` URL param, and decodes it using base64. The decoded value is returned as the response. That way, the contents of the `m3u` file is base64-encoded, and set as part of the response, for `mod_zip` to include it in the ZIP file. [1] https://github.com/evanmiller/mod_zip
50 lines
1.3 KiB
Python
50 lines
1.3 KiB
Python
import dataclasses
|
|
from collections.abc import Collection
|
|
from typing import Any
|
|
|
|
from fastapi.responses import Response
|
|
|
|
|
|
@dataclasses.dataclass(frozen=True)
|
|
class ZipContentLine:
|
|
"""Dataclass for lines returned in the response body, for usage with the `mod_zip` module.
|
|
|
|
Reference:
|
|
https://github.com/evanmiller/mod_zip?tab=readme-ov-file#usage
|
|
"""
|
|
|
|
crc32: str | None
|
|
size_bytes: int
|
|
encoded_location: str
|
|
filename: str
|
|
|
|
def __str__(self) -> str:
|
|
crc32 = self.crc32 or "-"
|
|
return f"{crc32} {self.size_bytes} {self.encoded_location} {self.filename}"
|
|
|
|
|
|
class ZipResponse(Response):
|
|
"""Response class for returning a ZIP archive with multiple files, using the `mod_zip` module."""
|
|
|
|
def __init__(
|
|
self,
|
|
*,
|
|
content_lines: Collection[ZipContentLine],
|
|
filename: str,
|
|
**kwargs: Any,
|
|
):
|
|
if kwargs.get("content"):
|
|
raise ValueError(
|
|
"Argument 'content' must not be provided, as it is generated from 'content_lines'"
|
|
)
|
|
|
|
kwargs["content"] = "\n".join(str(line) for line in content_lines)
|
|
kwargs.setdefault("headers", {}).update(
|
|
{
|
|
"Content-Disposition": f'attachment; filename="{filename}"',
|
|
"X-Archive-Files": "zip",
|
|
}
|
|
)
|
|
|
|
super().__init__(**kwargs)
|