diff --git a/store/app/crud/base.py b/store/app/crud/base.py index 4bcc03ea..1b73e2e2 100644 --- a/store/app/crud/base.py +++ b/store/app/crud/base.py @@ -644,3 +644,48 @@ async def generate_presigned_download_url( str(e), ) raise + + async def generate_presigned_video_upload_url(self, filename: str, s3_key: str, expires_in: int = 3600) -> str: + """Generates a presigned URL specifically for uploading video files to S3. + + Optimized for video content like .mkv files with appropriate content type + handling and upload parameters. + + Args: + filename: Original filename for Content-Disposition + s3_key: The S3 key where the file will be stored + expires_in: Number of seconds until URL expires + + Returns: + Presigned URL for uploading + """ + try: + content_type = "video/x-matroska" if filename.lower().endswith(".mkv") else "video/mp4" + + params = { + "Bucket": settings.s3.bucket, + "Key": f"{settings.s3.prefix}{s3_key}", + "ContentType": content_type, + "ContentDisposition": f'attachment; filename="{filename}"', + "ACL": "private", + } + + url = await self.s3.meta.client.generate_presigned_url( + ClientMethod="put_object", + Params=params, + ExpiresIn=expires_in, + ) + logger.debug("Generated video upload presigned URL for %s with content type %s", filename, content_type) + return url + + except ClientError as e: + error_code = e.response.get("Error", {}).get("Code", "Unknown") + error_message = e.response.get("Error", {}).get("Message", str(e)) + logger.error( + "Failed to generate video upload presigned URL - Bucket: %s, Key: %s, Error: %s - %s", + settings.s3.bucket, + s3_key, + error_code, + error_message, + ) + raise diff --git a/store/app/routers/krecs.py b/store/app/routers/krecs.py index 1a95f291..80d46286 100644 --- a/store/app/routers/krecs.py +++ b/store/app/routers/krecs.py @@ -50,18 +50,16 @@ async def create_krec( await crud._add_item(krec) s3_key = f"krecs/{krec.id}/{krec.name}" - upload_url = await crud.generate_presigned_upload_url( + upload_url = await crud.generate_presigned_video_upload_url( filename=krec.name, s3_key=s3_key, - content_type="video/x-matroska", - checksum_algorithm="SHA256", expires_in=12 * 3600, ) return { "krec_id": krec.id, "upload_url": upload_url, - "expires_at": int((datetime.utcnow() + timedelta(hours=12)).timestamp()), # Match the expiration time + "expires_at": int((datetime.utcnow() + timedelta(hours=12)).timestamp()), }