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 renderPathHTML(path models.PathDownload) string { return 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) } 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", "text/html") 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 } 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 } } pathDownload.Path = fullPath if err := db.Create(&pathDownload).Error; err != nil { http.Error(w, `{"error": "Failed to save path"}`, http.StatusInternalServerError) return } // 👉 On renvoie uniquement la ligne HTML nouvellement créée fmt.Fprint(w, renderPathHTML(pathDownload)) } } 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", "text/html") 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 { http.Error(w, `{"error": "Path not found"}`, http.StatusNotFound) return } 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 } // 👉 On renvoie uniquement la ligne HTML mise à jour fmt.Fprint(w, renderPathHTML(existingPath)) } } 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(pathName string) error { if pathName == "" { return errors.New("PathName cannot be empty") } if strings.Contains(pathName, "/") || strings.Contains(pathName, "\\") { return errors.New("PathName cannot contain '/' or '\\'") } fullPath := "/app/upload/" + pathName if _, err := os.Stat(fullPath); err == nil { return errors.New("Path already exists") } // os.Stat() retourne une erreur si le dossier n'existe pas, on ignore cette erreur ici 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}) } }