o2o-castad-backend/app/ssulbox/services/blob_service.py

67 lines
2.3 KiB
Python

# -*- coding: utf-8 -*-
"""썰박스 산출물 Blob 업로드.
castad `AzureBlobUploader` 를 그대로 재사용한다 — 원본 썰박스의 `blob_client.py`
는 이식하지 않는다. 같은 Azure 계정을 쓰므로 업로더를 두 벌 둘 이유가 없다.
경로는 `{user_uuid}/{task_id}/video/{file}` 형태가 되는데, ADO2 콘텐츠와 섞이지 않도록
task_id 자리에 `ssulbox-{id}` 접두를 붙인다.
"""
from pathlib import Path
from typing import Optional
from app.utils.logger import get_logger
from app.utils.upload_blob_as_request import AzureBlobUploader
from config import azure_blob_settings, ssulbox_settings
logger = get_logger("ssulbox")
#: 설정되지 않았을 때의 플레이스홀더 (config.py 기본값)
_PLACEHOLDER_SAS = {"", "your-sas-token", "none"}
def blob_enabled() -> bool:
"""Blob 업로드가 가능한 상태인지.
비활성이면 로컬 파일을 그대로 서빙한다(개발 환경).
"""
token = (azure_blob_settings.AZURE_BLOB_SAS_TOKEN or "").strip()
return token.lower() not in _PLACEHOLDER_SAS
async def upload_ssul_video(
mp4_path: Path, user_uuid: Optional[str], content_id: int
) -> Optional[str]:
"""완성 영상을 Blob 에 올리고 공개 URL 을 반환. 실패·비활성이면 None.
Args:
mp4_path: 로컬 mp4 경로
user_uuid: 소유자. 탈퇴로 NULL 이면 업로드하지 않는다
content_id: `ssul_content.id`
Returns:
SAS 토큰이 제외된 공개 URL, 또는 None
"""
if not blob_enabled():
logger.info("[upload_ssul_video] Blob 비활성 — 로컬 서빙")
return None
if not user_uuid:
logger.warning(f"[upload_ssul_video] user_uuid 없음 id={content_id}")
return None
if not mp4_path.exists():
logger.error(f"[upload_ssul_video] 파일 없음 {mp4_path}")
return None
# ADO2 영상과 경로를 분리한다
task_id = f"{ssulbox_settings.SSULBOX_BLOB_PREFIX}-{content_id}"
uploader = AzureBlobUploader(user_uuid=user_uuid, task_id=task_id)
success = await uploader.upload_video(file_path=str(mp4_path))
if not success:
logger.error(f"[upload_ssul_video] 업로드 실패 id={content_id}")
return None
logger.info(f"[upload_ssul_video] OK id={content_id} url={uploader.public_url}")
return uploader.public_url