package main import ( "log" "net/http" "os" "path/filepath" "ai-media-hub/backend/handlers" "ai-media-hub/backend/models" "ai-media-hub/backend/services" "github.com/gin-gonic/gin" ) func main() { root := envOrDefault("APP_ROOT", "/app") dbPath := envOrDefault("SQLITE_PATH", filepath.Join(root, "db", "media.db")) downloadsDir := envOrDefault("DOWNLOADS_DIR", filepath.Join(root, "downloads")) frontendDir := envOrDefault("FRONTEND_DIR", filepath.Join(root, "frontend")) workerScript := envOrDefault("WORKER_SCRIPT", filepath.Join(root, "worker", "downloader.py")) db, err := models.InitDB(dbPath) if err != nil { log.Fatal(err) } defer db.Close() if err := handlers.EnsurePaths(downloadsDir, workerScript); err != nil { log.Fatal(err) } app := &handlers.App{ DB: db, DownloadsDir: downloadsDir, WorkerScript: workerScript, SearchService: services.NewSearchService( os.Getenv("VERTEX_AI_SEARCH_API_KEY"), os.Getenv("VERTEX_AI_SEARCH_PROJECT_ID"), os.Getenv("VERTEX_AI_SEARCH_LOCATION"), os.Getenv("VERTEX_AI_SEARCH_DATA_STORE_ID"), os.Getenv("VERTEX_AI_SEARCH_SERVING_CONFIG"), ), GeminiService: services.NewGeminiService(os.Getenv("GEMINI_API_KEY")), Hub: handlers.NewHub(), } router := gin.Default() handlers.RegisterRoutes(router, app) router.StaticFile("/", filepath.Join(frontendDir, "index.html")) router.StaticFile("/app.js", filepath.Join(frontendDir, "app.js")) router.StaticFile("/style.css", filepath.Join(frontendDir, "style.css")) router.NoRoute(func(c *gin.Context) { c.File(filepath.Join(frontendDir, "index.html")) }) router.NoMethod(func(c *gin.Context) { c.JSON(http.StatusMethodNotAllowed, gin.H{"error": "method not allowed"}) }) addr := envOrDefault("APP_ADDR", ":8080") log.Printf("server listening on %s", addr) if err := router.Run(addr); err != nil { log.Fatal(err) } } func envOrDefault(key, fallback string) string { if value := os.Getenv(key); value != "" { return value } return fallback }