updated api_routed and db_queries for audio files
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -22,6 +22,7 @@ from db_queries import (
|
||||
create_audio_post,
|
||||
create_user,
|
||||
get_archive_metadata,
|
||||
get_original_audio_url,
|
||||
get_archive_rights,
|
||||
get_audio_post_by_id,
|
||||
get_post_bundle,
|
||||
@@ -438,6 +439,34 @@ def api_post_bundle(post_id: int):
|
||||
return jsonify(bundle)
|
||||
|
||||
|
||||
@api.get("/posts/<int:post_id>/audio-url")
|
||||
def api_post_audio_url(post_id: int):
|
||||
"""
|
||||
Get signed URL for original audio/video so users can play it.
|
||||
Private posts require owner user_id in query params.
|
||||
"""
|
||||
row = get_audio_post_by_id(post_id)
|
||||
if not row:
|
||||
return _error("Post not found.", 404)
|
||||
|
||||
visibility = row.get("visibility")
|
||||
owner_id = row.get("user_id")
|
||||
requester_id = request.args.get("user_id", type=int)
|
||||
expires_in = request.args.get("expires_in", default=3600, type=int)
|
||||
expires_in = min(max(60, expires_in), 86400)
|
||||
|
||||
if visibility == "private" and requester_id != owner_id:
|
||||
return _error("Not authorized to access this private audio.", 403)
|
||||
|
||||
try:
|
||||
result = get_original_audio_url(post_id=post_id, expires_in=expires_in)
|
||||
return jsonify(result)
|
||||
except ValueError as e:
|
||||
return _error(str(e), 404)
|
||||
except Exception as e:
|
||||
return _error(str(e), 500)
|
||||
|
||||
|
||||
@api.post("/posts/<int:post_id>/files")
|
||||
def api_add_file(post_id: int):
|
||||
payload = request.get_json(force=True, silent=False) or {}
|
||||
|
||||
@@ -3,7 +3,7 @@ Supabase data layer aligned with TitanForge/schema.sql.
|
||||
"""
|
||||
|
||||
import os
|
||||
from typing import Any, Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from supabase import Client, create_client
|
||||
@@ -36,6 +36,17 @@ def _paginate(page: int, limit: int) -> tuple[int, int]:
|
||||
return start, end
|
||||
|
||||
|
||||
def _parse_bucket_path(stored_path: str) -> Tuple[str, str]:
|
||||
"""
|
||||
Convert stored path like 'archives/user/uuid/original/file.mp4'
|
||||
into ('archives', 'user/uuid/original/file.mp4').
|
||||
"""
|
||||
parts = (stored_path or "").split("/", 1)
|
||||
if len(parts) != 2 or not parts[0] or not parts[1]:
|
||||
raise ValueError(f"Invalid storage path format: {stored_path}")
|
||||
return parts[0], parts[1]
|
||||
|
||||
|
||||
def upload_storage_object(
|
||||
bucket: str,
|
||||
object_path: str,
|
||||
@@ -56,6 +67,50 @@ def upload_storage_object(
|
||||
)
|
||||
|
||||
|
||||
def get_original_audio_url(post_id: int, expires_in: int = 3600) -> Dict[str, Any]:
|
||||
"""
|
||||
Return a signed URL for the original audio/video archive file.
|
||||
"""
|
||||
response = (
|
||||
supabase.table("archive_files")
|
||||
.select("path, content_type")
|
||||
.eq("post_id", post_id)
|
||||
.eq("role", "original_audio")
|
||||
.limit(1)
|
||||
.execute()
|
||||
)
|
||||
row = _first(response)
|
||||
if not row:
|
||||
raise ValueError("Original audio file not found for this post.")
|
||||
|
||||
bucket, object_path = _parse_bucket_path(row["path"])
|
||||
|
||||
signed = supabase.storage.from_(bucket).create_signed_url(object_path, expires_in)
|
||||
|
||||
# Supabase python client can return dict or object with .get depending on version.
|
||||
if isinstance(signed, dict):
|
||||
signed_url = (
|
||||
signed.get("signedURL")
|
||||
or signed.get("signedUrl")
|
||||
or signed.get("data", {}).get("signedUrl")
|
||||
or signed.get("data", {}).get("signedURL")
|
||||
)
|
||||
else:
|
||||
signed_url = None
|
||||
|
||||
if not signed_url:
|
||||
raise RuntimeError("Failed to create signed URL for original audio.")
|
||||
|
||||
return {
|
||||
"post_id": post_id,
|
||||
"bucket": bucket,
|
||||
"object_path": object_path,
|
||||
"content_type": row.get("content_type"),
|
||||
"signed_url": signed_url,
|
||||
"expires_in": expires_in,
|
||||
}
|
||||
|
||||
|
||||
# ==================== Users ====================
|
||||
|
||||
def create_user(payload: Dict[str, Any]) -> Dict[str, Any]:
|
||||
|
||||
Reference in New Issue
Block a user