Files
mediaplayer/sentence_api/oss.py

78 lines
2.5 KiB
Python

import logging
from pathlib import Path
from typing import Optional
from urllib.parse import quote
from .config import Settings
logger = logging.getLogger(__name__)
class VolcanoOSSUploader:
"""Upload course videos to Volcano Engine Object Storage (TOS)."""
def __init__(self, settings: Settings):
self.settings = settings
@property
def enabled(self) -> bool:
return self.settings.volcano_oss_enabled
def object_key(self, video_hash: str, stored_filename: str) -> str:
normalized_hash = video_hash.strip().lower()
suffix = Path(stored_filename).suffix or ".mp4"
return f"{self.settings.volcano_oss_key_prefix}{normalized_hash}{suffix}"
def public_url(self, object_key: str) -> str:
return self.settings.volcano_oss_public_url(object_key)
def upload(
self,
*,
video_hash: str,
stored_filename: str,
local_path: Path,
content_type: Optional[str] = None,
) -> str:
"""Upload one local file and return its permanent public URL."""
if not self.enabled:
raise RuntimeError("Volcano OSS is not configured.")
if not local_path.is_file():
raise FileNotFoundError(f"Cannot upload a missing video: {local_path}")
# Keep the SDK import optional for development machines that do not run
# the production service. It is declared in sentence_api/requirements.txt.
try:
import tos
except ImportError as exc:
raise RuntimeError(
"The Volcano TOS SDK is not installed. Run: pip install tos"
) from exc
object_key = self.object_key(video_hash, stored_filename)
endpoint = self.settings.volcano_oss_endpoint
client = tos.TosClientV2(
self.settings.volcano_oss_access_key,
self.settings.volcano_oss_secret_key,
endpoint,
self.settings.volcano_oss_region,
)
try:
client.put_object_from_file(
self.settings.volcano_oss_bucket,
object_key,
str(local_path),
)
except Exception:
logger.exception(
"Volcano OSS upload failed: bucket=%s key=%s endpoint=%s",
self.settings.volcano_oss_bucket,
object_key,
endpoint,
)
raise
logger.info("Uploaded %s to Volcano OSS object %s", local_path.name, object_key)
return self.public_url(object_key)