package download import ( "app/shelfly/internal/debridlink" "app/shelfly/internal/models" "context" "encoding/json" "errors" "fmt" "html/template" "log" "net/http" "os" "strings" "github.com/gorilla/mux" "gorm.io/gorm" ) func GetFirstActiveAccount(client *debridlink.Client) *debridlink.DebridAccount { ctx := context.Background() // ✅ on remplace ici accounts, err := client.ListDebridAccounts(ctx) if err != nil { log.Println("[ERROR] Impossible de récupérer les comptes :", err) return nil } for _, acc := range accounts { if acc.IsActive { return &acc } } return nil } func CreateSavePath(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") var pathDownload models.PathDownload if err := json.NewDecoder(r.Body).Decode(&pathDownload); err != nil { http.Error(w, `{"error": "Invalid JSON format"}`, http.StatusBadRequest) return } if pathDownload.PathName == "" { http.Error(w, `{"error": "PathName cannot be empty"}`, http.StatusBadRequest) return } // Création du dossier physique fullPath := "/app/upload/" + pathDownload.PathName if _, err := os.Stat(fullPath); os.IsNotExist(err) { if err := os.MkdirAll(fullPath, 0755); err != nil { http.Error(w, `{"error": "Failed to create directory"}`, http.StatusInternalServerError) return } } // Enregistrement en base pathDownload.Path = fullPath if err := db.Create(&pathDownload).Error; err != nil { http.Error(w, `{"error": "Failed to save path"}`, http.StatusInternalServerError) return } // Recharge la liste ReadAllSavePath(db)(w, r) } } func ReadAllSavePath(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html") var paths []models.PathDownload if err := db.Find(&paths).Error; err != nil { http.Error(w, `{"error": "Failed to retrieve paths"}`, http.StatusInternalServerError) return } var response strings.Builder for _, path := range paths { response.WriteString(fmt.Sprintf(`
`, path.ID, path.ID, path.PathName, path.ID, path.ID, path.ID, path.ID, path.ID, path.ID, path.ID, path.ID, path.ID, path.ID)) } w.WriteHeader(http.StatusOK) fmt.Fprint(w, response.String()) } } func UpdateSavePath(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") id := mux.Vars(r)["id"] var pathDownload models.PathDownload if err := json.NewDecoder(r.Body).Decode(&pathDownload); err != nil { http.Error(w, `{"error": "Invalid JSON format"}`, http.StatusBadRequest) return } var existingPath models.PathDownload if err := db.First(&existingPath, "id = ?", id).Error; err != nil { if err == gorm.ErrRecordNotFound { http.Error(w, `{"error": "Path not found"}`, http.StatusNotFound) return } http.Error(w, `{"error": "Failed to retrieve path"}`, http.StatusInternalServerError) return } // Renommage physique du dossier oldFullPath := "/app/upload/" + existingPath.PathName newFullPath := "/app/upload/" + pathDownload.PathName if oldFullPath != newFullPath { if err := os.Rename(oldFullPath, newFullPath); err != nil { http.Error(w, `{"error": "Failed to rename directory"}`, http.StatusInternalServerError) return } } existingPath.PathName = pathDownload.PathName existingPath.Path = newFullPath if err := db.Save(&existingPath).Error; err != nil { http.Error(w, `{"error": "Failed to update path"}`, http.StatusInternalServerError) return } ReadAllSavePath(db)(w, r) } } func DeleteSavePath(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") id := mux.Vars(r)["id"] var pathDownload models.PathDownload if err := db.First(&pathDownload, "id = ?", id).Error; err != nil { if err == gorm.ErrRecordNotFound { http.Error(w, `{"error": "Path not found"}`, http.StatusNotFound) return } http.Error(w, `{"error": "Failed to retrieve path"}`, http.StatusInternalServerError) return } // Supprimer physiquement le dossier fullPath := "/app/upload/" + pathDownload.PathName if err := os.RemoveAll(fullPath); err != nil { http.Error(w, `{"error": "Failed to delete directory"}`, http.StatusInternalServerError) return } if err := db.Delete(&pathDownload).Error; err != nil { http.Error(w, `{"error": "Failed to delete path"}`, http.StatusInternalServerError) return } ReadAllSavePath(db)(w, r) } } func IsPathValid(subPath string) error { if subPath == "" { return errors.New("path is empty") } fullPath := "/app/upload/" + subPath info, err := os.Stat(fullPath) if os.IsNotExist(err) { return errors.New("path does not exist") } if err != nil { return errors.New("unable to access path: " + err.Error()) } if !info.IsDir() { return errors.New("path is not a directory") } return nil } // PathValidationHandler handles HTTP requests to validate a path func PathValidationHandler(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) return } var requestBody struct { PathName string `json:"pathName"` } if err := json.NewDecoder(r.Body).Decode(&requestBody); err != nil { http.Error(w, "Invalid request body", http.StatusBadRequest) return } err := IsPathValid(requestBody.PathName) response := map[string]string{ "pathName": requestBody.PathName, "status": "valid", } if err != nil { response["status"] = "invalid" response["error"] = err.Error() w.WriteHeader(http.StatusBadRequest) } w.Header().Set("Content-Type", "application/json") if err := json.NewEncoder(w).Encode(response); err != nil { http.Error(w, "Failed to encode response", http.StatusInternalServerError) } } type StreamPageData struct { StreamURL string } func HandleStreamPage() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { id := mux.Vars(r)["id"] job := jobs[id] if job == nil || job.StreamURL == "" { http.Error(w, "Stream non disponible", http.StatusNotFound) return } tmpl := ` Streaming ` t := template.Must(template.New("stream").Parse(tmpl)) t.Execute(w, StreamPageData{StreamURL: job.StreamURL}) } }