import boto3 from botocore.exceptions import ClientError from django.conf import settings def _is_s3_storage(): return "S3Boto3Storage" in settings.DEFAULT_FILE_STORAGE def _get_client(): return boto3.client( "s3", endpoint_url=settings.AWS_S3_ENDPOINT_URL, aws_access_key_id=settings.AWS_ACCESS_KEY_ID, aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY, region_name=settings.AWS_S3_REGION_NAME, ) def generate_presigned_put_url(key, content_type="video/mp4", expires_in=3600): """ Return a presigned PUT URL the client can use to upload directly to Wasabi. In development (local filesystem storage) returns None — callers should handle this. """ if not _is_s3_storage(): return None client = _get_client() return client.generate_presigned_url( "put_object", Params={ "Bucket": settings.AWS_STORAGE_BUCKET_NAME, "Key": key, "ContentType": content_type, }, ExpiresIn=expires_in, ) def generate_presigned_get_url(key, expires_in=3600): """Return a presigned GET URL for downloading a private Wasabi object.""" if not _is_s3_storage(): return None client = _get_client() return client.generate_presigned_url( "get_object", Params={ "Bucket": settings.AWS_STORAGE_BUCKET_NAME, "Key": key, }, ExpiresIn=expires_in, ) def object_exists(key): """Return True if the object exists in the Wasabi bucket.""" if not _is_s3_storage(): # In dev, assume upload happened (no real Wasabi) return True client = _get_client() try: client.head_object(Bucket=settings.AWS_STORAGE_BUCKET_NAME, Key=key) return True except ClientError: return False def preview_url(key): """ Return the public URL for a preview image. Uses Cloudflare CDN in production; falls back to a presigned URL. """ if not key: return None cdn = settings.CDN_BASE_URL if cdn: return f"{cdn.rstrip('/')}/{key}" return generate_presigned_get_url(key, expires_in=86400)