Make docker image work

This commit is contained in:
2025-10-30 17:31:29 +11:00
parent b298cb2e5c
commit 5dd486844f
3 changed files with 70 additions and 9 deletions
+5 -1
View File
@@ -47,6 +47,7 @@ EXPOSE 8000
# Environment variables # Environment variables
ENV PYTHONUNBUFFERED=1 ENV PYTHONUNBUFFERED=1
ENV PYTHONPATH=/app/backend
ENV DATABASE_URL=sqlite+aiosqlite:///./data/youmusic.db ENV DATABASE_URL=sqlite+aiosqlite:///./data/youmusic.db
ENV MUSIC_DIR=/app/data/music ENV MUSIC_DIR=/app/data/music
ENV UPLOAD_DIR=/app/data/uploads ENV UPLOAD_DIR=/app/data/uploads
@@ -57,5 +58,8 @@ ENV BASE_DIR=/app
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8000/ || exit 1 CMD curl -f http://localhost:8000/ || exit 1
# Set working directory to backend
WORKDIR /app/backend
# Run the application # Run the application
CMD ["uvicorn", "backend.main:app", "--host", "0.0.0.0", "--port", "8000"] CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
+63 -7
View File
@@ -1,8 +1,10 @@
import os import os
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from pathlib import Path
from fastapi import FastAPI from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
from app.api import music, playlist, download, search, stream, artist from app.api import music, playlist, download, search, stream, artist
from app.core.config import settings from app.core.config import settings
from app.db.session import init_db from app.db.session import init_db
@@ -11,11 +13,34 @@ from app.db.session import init_db
@asynccontextmanager @asynccontextmanager
async def lifespan(app: FastAPI): async def lifespan(app: FastAPI):
# Startup # Startup
print("=" * 80)
print("🎵 YouMusic Starting Up")
print("=" * 80)
print(f"📂 BASE_DIR: {settings.BASE_DIR}")
print(f"📂 MUSIC_DIR: {settings.MUSIC_DIR}")
print(f"📂 UPLOAD_DIR: {settings.UPLOAD_DIR}")
print(f"📂 TEMP_DIR: {settings.TEMP_DIR}")
print(f"📂 DATABASE: {settings.DATABASE_URL}")
cache_dir = os.path.join(settings.BASE_DIR, "data", "cache")
artist_cache_dir = os.path.join(cache_dir, "artists")
artist_images_dir = os.path.join(cache_dir, "artist_images")
print(f"📂 CACHE_DIR: {cache_dir}")
print(f"📂 ARTIST_CACHE: {artist_cache_dir}")
print(f"📂 ARTIST_IMAGES: {artist_images_dir}")
print(f"🎬 FFMPEG: {settings.FFMPEG_LOCATION}")
print("=" * 80)
os.makedirs(settings.MUSIC_DIR, exist_ok=True) os.makedirs(settings.MUSIC_DIR, exist_ok=True)
os.makedirs(settings.UPLOAD_DIR, exist_ok=True) os.makedirs(settings.UPLOAD_DIR, exist_ok=True)
os.makedirs(os.path.join(settings.BASE_DIR, "data", "cache"), exist_ok=True) os.makedirs(cache_dir, exist_ok=True)
os.makedirs(os.path.join(settings.BASE_DIR, "data", "cache", "artist_images"), exist_ok=True) os.makedirs(artist_cache_dir, exist_ok=True)
os.makedirs(artist_images_dir, exist_ok=True)
await init_db() await init_db()
print("✅ All directories created and database initialized")
print("=" * 80)
yield yield
# Shutdown # Shutdown
@@ -53,16 +78,47 @@ app.include_router(stream.router, prefix="/api", tags=["stream"])
app.include_router(artist.router, prefix="/api/artists", tags=["artists"]) app.include_router(artist.router, prefix="/api/artists", tags=["artists"])
@app.get("/") # Health check endpoint (must be before catch-all route)
async def root():
return {"message": "YouMusic API is running"}
@app.get("/health") @app.get("/health")
async def health(): async def health():
return {"status": "healthy"} return {"status": "healthy"}
# Mount frontend static files (built React app)
static_dir = Path(__file__).parent / "static"
if static_dir.exists():
app.mount("/assets", StaticFiles(directory=str(static_dir / "assets")), name="assets")
@app.get("/")
async def serve_frontend():
"""Serve the React frontend"""
index_file = static_dir / "index.html"
if index_file.exists():
return FileResponse(index_file)
return {"message": "YouMusic API is running (frontend not built)"}
@app.get("/{full_path:path}")
async def serve_spa(full_path: str):
"""Serve React app for all non-API routes (SPA routing)"""
# Skip API routes, health check, and static assets
if full_path.startswith(("api/", "music/", "cache/", "assets/", "health", "docs", "redoc", "openapi.json")):
return {"error": "Not found"}
# For all other routes, serve index.html (React Router handles client-side routing)
index_file = static_dir / "index.html"
if index_file.exists():
return FileResponse(index_file)
return {"error": "Frontend not found"}
else:
@app.get("/")
async def root():
return {"message": "YouMusic API is running (frontend not built)"}
@app.get("/health")
async def health_no_frontend():
return {"status": "healthy"}
if __name__ == "__main__": if __name__ == "__main__":
import uvicorn import uvicorn
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True) uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
+2 -1
View File
@@ -7,7 +7,8 @@ services:
- "8000:8000" - "8000:8000"
volumes: volumes:
- ./data:/app/data - ./data:/app/data
- ./backend:/app/backend # Note: Do not mount ./backend in production - it overwrites the built image
# For development, use ./dev.sh instead
environment: environment:
- DATABASE_URL=sqlite+aiosqlite:////app/data/youmusic.db - DATABASE_URL=sqlite+aiosqlite:////app/data/youmusic.db
- MUSIC_DIR=/app/data/music - MUSIC_DIR=/app/data/music