Files
kihong.kim c3795138da Initial commit: YouTube Shorts maker application
Features:
- Video download from TikTok/Douyin using yt-dlp
- Audio transcription with OpenAI Whisper
- GPT-4 translation (direct/summarize/rewrite modes)
- Subtitle generation with ASS format
- Video trimming with frame-accurate preview
- BGM integration with volume control
- Intro text overlay support
- Thumbnail generation with text overlay

Tech stack:
- Backend: FastAPI, Python 3.11+
- Frontend: React, Vite, TailwindCSS
- Video processing: FFmpeg
- AI: OpenAI Whisper, GPT-4

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 21:38:34 +09:00

65 lines
2.1 KiB
Python

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from contextlib import asynccontextmanager
import os
from app.routers import download, process, bgm, jobs, fonts
from app.config import settings
@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup
os.makedirs(settings.DOWNLOAD_DIR, exist_ok=True)
os.makedirs(settings.PROCESSED_DIR, exist_ok=True)
os.makedirs(settings.BGM_DIR, exist_ok=True)
# Check BGM status on startup
bgm_files = []
if os.path.exists(settings.BGM_DIR):
bgm_files = [f for f in os.listdir(settings.BGM_DIR) if f.endswith(('.mp3', '.wav', '.m4a', '.ogg'))]
if len(bgm_files) == 0:
print("[Startup] No BGM files found. Upload BGM via /api/bgm/upload or download from Pixabay/Mixkit")
else:
names = ', '.join(bgm_files[:3])
suffix = f'... (+{len(bgm_files) - 3} more)' if len(bgm_files) > 3 else ''
print(f"[Startup] Found {len(bgm_files)} BGM files: {names}{suffix}")
yield
# Shutdown
app = FastAPI(
title="Shorts Maker API",
description="중국 쇼츠 영상을 한글 자막으로 변환하는 서비스",
version="1.0.0",
lifespan=lifespan,
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Static files for processed videos
app.mount("/static/downloads", StaticFiles(directory="data/downloads"), name="downloads")
app.mount("/static/processed", StaticFiles(directory="data/processed"), name="processed")
app.mount("/static/bgm", StaticFiles(directory="data/bgm"), name="bgm")
# Routers
app.include_router(download.router, prefix="/api/download", tags=["Download"])
app.include_router(process.router, prefix="/api/process", tags=["Process"])
app.include_router(bgm.router, prefix="/api/bgm", tags=["BGM"])
app.include_router(jobs.router, prefix="/api/jobs", tags=["Jobs"])
app.include_router(fonts.router, prefix="/api/fonts", tags=["Fonts"])
@app.get("/api/health")
async def health_check():
return {"status": "healthy", "service": "shorts-maker"}