내부 youtube 업로드 endpoint 적용 .

subtitle
hbyang 2026-03-03 16:16:23 +09:00
parent d0334a5575
commit 6fba9c5362
5 changed files with 75 additions and 4 deletions

View File

@ -0,0 +1,43 @@
"""
내부 전용 소셜 업로드 API
스케줄러 서버에서만 호출하는 내부 엔드포인트입니다.
X-Internal-Secret 헤더로 인증합니다.
"""
import logging
from fastapi import APIRouter, BackgroundTasks, Header, HTTPException, status
from app.social.worker.upload_task import process_social_upload
from config import internal_settings
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/internal/social", tags=["Internal"])
def _verify_secret(x_internal_secret: str = Header(...)) -> None:
if x_internal_secret != internal_settings.INTERNAL_SECRET_KEY:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Invalid internal secret",
)
@router.post(
"/upload/{upload_id}",
summary="[내부] 예약 업로드 실행",
description="스케줄러 서버에서 호출하는 내부 전용 엔드포인트입니다.",
)
async def trigger_scheduled_upload(
upload_id: int,
background_tasks: BackgroundTasks,
x_internal_secret: str = Header(...),
) -> dict:
_verify_secret(x_internal_secret)
logger.info(f"[INTERNAL] 예약 업로드 실행 - upload_id: {upload_id}")
background_tasks.add_task(process_social_upload, upload_id)
return {"success": True, "upload_id": upload_id, "message": "업로드 작업이 시작되었습니다."}

View File

@ -4,7 +4,7 @@
소셜 미디어 영상 업로드 관련 엔드포인트를 제공합니다. 소셜 미디어 영상 업로드 관련 엔드포인트를 제공합니다.
""" """
import logging, json import logging
from typing import Optional from typing import Optional
from fastapi import APIRouter, BackgroundTasks, Depends, Query from fastapi import APIRouter, BackgroundTasks, Depends, Query
@ -158,6 +158,7 @@ async def upload_to_social(
description=body.description, description=body.description,
tags=body.tags, tags=body.tags,
privacy_status=body.privacy_status.value, privacy_status=body.privacy_status.value,
scheduled_at=body.scheduled_at,
platform_options={ platform_options={
**(body.platform_options or {}), **(body.platform_options or {}),
"scheduled_at": body.scheduled_at.isoformat() if body.scheduled_at else None, "scheduled_at": body.scheduled_at.isoformat() if body.scheduled_at else None,
@ -175,15 +176,19 @@ async def upload_to_social(
f"account_id: {account.id}, upload_seq: {next_seq}, platform: {account.platform}" f"account_id: {account.id}, upload_seq: {next_seq}, platform: {account.platform}"
) )
# 6. 백그라운드 태스크 등록 # 6. 백그라운드 태스크 등록 (즉시 업로드 or 예약 없을 때만)
from app.utils.timezone import now as utcnow
is_scheduled = body.scheduled_at and body.scheduled_at > utcnow()
if not is_scheduled:
background_tasks.add_task(process_social_upload, social_upload.id) background_tasks.add_task(process_social_upload, social_upload.id)
message = "예약 업로드가 등록되었습니다." if is_scheduled else "업로드 요청이 접수되었습니다."
return SocialUploadResponse( return SocialUploadResponse(
success=True, success=True,
upload_id=social_upload.id, upload_id=social_upload.id,
platform=account.platform, platform=account.platform,
status=social_upload.status, status=social_upload.status,
message="업로드 요청이 접수되었습니다.", message=message,
) )

View File

@ -190,6 +190,15 @@ class SocialUpload(Base):
comment="플랫폼별 추가 옵션 (JSON)", comment="플랫폼별 추가 옵션 (JSON)",
) )
# ==========================================================================
# 예약 게시 시간
# ==========================================================================
scheduled_at: Mapped[Optional[datetime]] = mapped_column(
DateTime,
nullable=True,
comment="예약 게시 시간 (스케줄러가 이 시간 이후에 업로드 실행)",
)
# ========================================================================== # ==========================================================================
# 에러 정보 # 에러 정보
# ========================================================================== # ==========================================================================

View File

@ -566,6 +566,17 @@ class SocialOAuthSettings(BaseSettings):
model_config = _base_config model_config = _base_config
class InternalSettings(BaseSettings):
"""내부 서버 간 통신 설정"""
INTERNAL_SECRET_KEY: str = Field(
default="change-me-internal-secret-key",
description="스케줄러 서버 → 백엔드 내부 API 인증 키",
)
model_config = _base_config
class SocialUploadSettings(BaseSettings): class SocialUploadSettings(BaseSettings):
"""소셜 미디어 업로드 설정 """소셜 미디어 업로드 설정
@ -613,4 +624,5 @@ kakao_settings = KakaoSettings()
jwt_settings = JWTSettings() jwt_settings = JWTSettings()
recovery_settings = RecoverySettings() recovery_settings = RecoverySettings()
social_oauth_settings = SocialOAuthSettings() social_oauth_settings = SocialOAuthSettings()
internal_settings = InternalSettings()
social_upload_settings = SocialUploadSettings() social_upload_settings = SocialUploadSettings()

View File

@ -23,6 +23,7 @@ from app.video.api.routers.v1.video import router as video_router
from app.social.api.routers.v1.oauth import router as social_oauth_router from app.social.api.routers.v1.oauth import router as social_oauth_router
from app.social.api.routers.v1.upload import router as social_upload_router from app.social.api.routers.v1.upload import router as social_upload_router
from app.social.api.routers.v1.seo import router as social_seo_router from app.social.api.routers.v1.seo import router as social_seo_router
from app.social.api.routers.v1.internal import router as social_internal_router
from app.utils.cors import CustomCORSMiddleware from app.utils.cors import CustomCORSMiddleware
from config import prj_settings from config import prj_settings
@ -391,6 +392,7 @@ app.include_router(archive_router) # Archive API 라우터 추가
app.include_router(social_oauth_router, prefix="/social") # Social OAuth 라우터 추가 app.include_router(social_oauth_router, prefix="/social") # Social OAuth 라우터 추가
app.include_router(social_upload_router, prefix="/social") # Social Upload 라우터 추가 app.include_router(social_upload_router, prefix="/social") # Social Upload 라우터 추가
app.include_router(social_seo_router, prefix="/social") # Social Upload 라우터 추가 app.include_router(social_seo_router, prefix="/social") # Social Upload 라우터 추가
app.include_router(social_internal_router) # 내부 스케줄러 전용 라우터
app.include_router(sns_router) # SNS API 라우터 추가 app.include_router(sns_router) # SNS API 라우터 추가
app.include_router(dashboard_router) # Dashboard API 라우터 추가 app.include_router(dashboard_router) # Dashboard API 라우터 추가