mirror of
https://github.com/arkorty/DownLink.git
synced 2026-03-17 16:51:45 +00:00
110 lines
3.4 KiB
Go
110 lines
3.4 KiB
Go
package handlers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"log/slog"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"DownLink/models"
|
|
"DownLink/services"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type VideoHandler struct {
|
|
videoService *services.VideoService
|
|
}
|
|
|
|
func NewVideoHandler(videoService *services.VideoService) *VideoHandler {
|
|
return &VideoHandler{
|
|
videoService: videoService,
|
|
}
|
|
}
|
|
|
|
func (vh *VideoHandler) DownloadVideo(w http.ResponseWriter, r *http.Request) {
|
|
var req models.VideoDownloadRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
slog.Error("Failed to decode request body", "error", err)
|
|
vh.writeError(w, http.StatusBadRequest, "Invalid JSON")
|
|
return
|
|
}
|
|
|
|
if req.URL == "" || req.Quality == "" {
|
|
slog.Warn("Invalid request parameters", "url", req.URL, "quality", req.Quality)
|
|
vh.writeError(w, http.StatusBadRequest, "URL and Quality are required")
|
|
return
|
|
}
|
|
|
|
slog.Info("Starting video download", "url", req.URL, "quality", req.Quality)
|
|
|
|
outputPath, err := vh.videoService.DownloadVideo(req.URL, req.Quality)
|
|
if err != nil {
|
|
slog.Error("Video download failed", "url", req.URL, "quality", req.Quality, "error", err)
|
|
vh.writeError(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
|
|
// Determine if this was a cached response
|
|
isCached := !strings.Contains(outputPath, "dl_") && strings.Contains(outputPath, "cache")
|
|
|
|
// Only cleanup if it's a fresh download (not cached)
|
|
if strings.Contains(outputPath, "dl_") {
|
|
defer vh.videoService.CleanupTempDir(outputPath)
|
|
}
|
|
|
|
uid := uuid.New().String()
|
|
filename := fmt.Sprintf("video_%s.mp4", uid)
|
|
|
|
// Add cache status header
|
|
if isCached {
|
|
w.Header().Set("X-Cache-Status", "HIT")
|
|
slog.Info("Serving cached video", "url", req.URL, "quality", req.Quality, "file", outputPath)
|
|
} else {
|
|
w.Header().Set("X-Cache-Status", "MISS")
|
|
slog.Info("Serving fresh download", "url", req.URL, "quality", req.Quality, "file", outputPath)
|
|
}
|
|
|
|
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))
|
|
w.Header().Set("Content-Type", "video/mp4")
|
|
|
|
http.ServeFile(w, r, outputPath)
|
|
}
|
|
|
|
func (vh *VideoHandler) HealthCheck(w http.ResponseWriter, r *http.Request) {
|
|
slog.Debug("Health check requested", "remote_addr", r.RemoteAddr)
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte("Backend for DownLink is running.\n"))
|
|
}
|
|
|
|
func (vh *VideoHandler) ClearCache(w http.ResponseWriter, r *http.Request) {
|
|
slog.Info("Cache clear requested")
|
|
if err := vh.videoService.CleanupExpiredCache(0); err != nil {
|
|
slog.Error("Failed to clear cache", "error", err)
|
|
vh.writeError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to clear cache: %v", err))
|
|
return
|
|
}
|
|
|
|
slog.Info("Cache cleared successfully")
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusOK)
|
|
json.NewEncoder(w).Encode(map[string]string{"message": "Cache cleared successfully"})
|
|
}
|
|
|
|
func (vh *VideoHandler) GetCacheStatus(w http.ResponseWriter, r *http.Request) {
|
|
slog.Debug("Cache status requested")
|
|
status := vh.videoService.GetCacheStats()
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusOK)
|
|
json.NewEncoder(w).Encode(status)
|
|
}
|
|
|
|
func (vh *VideoHandler) writeError(w http.ResponseWriter, status int, message string) {
|
|
slog.Error("HTTP error response", "status", status, "message", message)
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(status)
|
|
json.NewEncoder(w).Encode(models.ErrorResponse{Error: message})
|
|
}
|