Files
2025-03-16 11:32:00 +02:00

191 lines
4.6 KiB
Go

package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/bootdotdev/learn-file-storage-s3-golang-starter/internal/database"
"log"
"net/http"
"os"
"os/exec"
"github.com/joho/godotenv"
_ "github.com/lib/pq"
)
type apiConfig struct {
db database.Client
jwtSecret string
platform string
filepathRoot string
assetsRoot string
s3Client *s3.Client
s3Bucket string
s3Region string
s3CfDistribution string
port string
}
type thumbnail struct {
data []byte
mediaType string
}
func getVideoAspectRatio(filePath string) (string, error) {
cmd := exec.Command("ffprobe", "-v", "error", "-print_format", "json", "-show_streams", filePath)
var buffer bytes.Buffer
cmd.Stdout = &buffer
err := cmd.Run()
if err != nil {
return "", err
}
type Stream struct {
Index int `json:"index"`
Width int `json:"width"`
Height int `json:"height"`
DisplayAspectRatio string `json:"display_aspect_ratio"`
}
type VideoInfo struct {
Streams []Stream `json:"streams"`
}
var videoInfo VideoInfo
err = json.Unmarshal(buffer.Bytes(), &videoInfo)
if err != nil {
fmt.Println(err)
return "", err
}
return videoInfo.Streams[0].DisplayAspectRatio, nil
}
func processVideoForFastStart(filePath string) (string, error) {
newName := filePath + ".processing"
cmd := exec.Command("ffmpeg", "-i", filePath, "-c", "copy", "-movflags", "faststart", "-f", "mp4", newName)
var buffer bytes.Buffer
cmd.Stdout = &buffer
err := cmd.Run()
if err != nil {
return "", err
}
return newName, nil
}
func main() {
godotenv.Load(".env")
pathToDB := os.Getenv("DB_PATH")
if pathToDB == "" {
log.Fatal("DB_URL must be set")
}
db, err := database.NewClient(pathToDB)
if err != nil {
log.Fatalf("Couldn't connect to database: %v", err)
}
jwtSecret := os.Getenv("JWT_SECRET")
if jwtSecret == "" {
log.Fatal("JWT_SECRET environment variable is not set")
}
platform := os.Getenv("PLATFORM")
if platform == "" {
log.Fatal("PLATFORM environment variable is not set")
}
filepathRoot := os.Getenv("FILEPATH_ROOT")
if filepathRoot == "" {
log.Fatal("FILEPATH_ROOT environment variable is not set")
}
assetsRoot := os.Getenv("ASSETS_ROOT")
if assetsRoot == "" {
log.Fatal("ASSETS_ROOT environment variable is not set")
}
s3Bucket := os.Getenv("S3_BUCKET")
if s3Bucket == "" {
log.Fatal("S3_BUCKET environment variable is not set")
}
s3Region := os.Getenv("S3_REGION")
if s3Region == "" {
log.Fatal("S3_REGION environment variable is not set")
}
s3CfDistribution := os.Getenv("S3_CF_DISTRO")
if s3CfDistribution == "" {
log.Fatal("S3_CF_DISTRO environment variable is not set")
}
port := os.Getenv("PORT")
if port == "" {
log.Fatal("PORT environment variable is not set")
}
cfg := apiConfig{
db: db,
jwtSecret: jwtSecret,
platform: platform,
filepathRoot: filepathRoot,
assetsRoot: assetsRoot,
s3Bucket: s3Bucket,
s3Region: s3Region,
s3CfDistribution: s3CfDistribution,
port: port,
}
err = cfg.ensureAssetsDir()
if err != nil {
log.Fatalf("Couldn't create assets directory: %v", err)
}
awsCfg, err := config.LoadDefaultConfig(context.Background(), config.WithRegion(cfg.s3Region))
if err != nil {
log.Fatal(err)
}
client := s3.NewFromConfig(awsCfg)
cfg.s3Client = client
mux := http.NewServeMux()
appHandler := http.StripPrefix("/app", http.FileServer(http.Dir(filepathRoot)))
mux.Handle("/app/", appHandler)
assetsHandler := http.StripPrefix("/assets", http.FileServer(http.Dir(assetsRoot)))
mux.Handle("/assets/", cacheMiddleware(assetsHandler))
mux.HandleFunc("POST /api/login", cfg.handlerLogin)
mux.HandleFunc("POST /api/refresh", cfg.handlerRefresh)
mux.HandleFunc("POST /api/revoke", cfg.handlerRevoke)
mux.HandleFunc("POST /api/users", cfg.handlerUsersCreate)
mux.HandleFunc("POST /api/videos", cfg.handlerVideoMetaCreate)
mux.HandleFunc("POST /api/thumbnail_upload/{videoID}", cfg.handlerUploadThumbnail)
mux.HandleFunc("POST /api/video_upload/{videoID}", cfg.handlerUploadVideo)
mux.HandleFunc("GET /api/videos", cfg.handlerVideosRetrieve)
mux.HandleFunc("GET /api/videos/{videoID}", cfg.handlerVideoGet)
mux.HandleFunc("DELETE /api/videos/{videoID}", cfg.handlerVideoMetaDelete)
mux.HandleFunc("POST /admin/reset", cfg.handlerReset)
srv := &http.Server{
Addr: ":" + port,
Handler: mux,
}
log.Printf("Serving on: http://localhost:%s/app/\n", port)
log.Fatal(srv.ListenAndServe())
}