shelfy/internal/route/main.go
2025-06-18 19:43:36 +02:00

189 lines
6.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package route
import (
"app/shelfly/internal/download"
"app/shelfly/internal/library"
"app/shelfly/internal/login"
"app/shelfly/internal/users"
"app/shelfly/renders"
"encoding/base64"
"fmt"
"log"
"net/http"
"os"
"path/filepath"
"strings"
"time"
"github.com/gorilla/mux"
"golang.org/x/net/webdav"
"gorm.io/gorm"
)
type spaHandler struct {
staticPath string
indexPath string
}
// Routes non protégées
func checkAuth(authHeader, username, password string) bool {
const prefix = "Basic "
if !strings.HasPrefix(authHeader, prefix) {
return false
}
decoded, err := base64.StdEncoding.DecodeString(authHeader[len(prefix):])
if err != nil {
return false
}
pair := strings.SplitN(string(decoded), ":", 2)
if len(pair) != 2 {
return false
}
return pair[0] == username && pair[1] == password
}
func RoutesPublic(r *mux.Router, bd *gorm.DB) {
// Fichiers statiques (CSS, JS, etc.)
staticDir := "./templates/assets/"
r.PathPrefix("/templates/assets/").Handler(
http.StripPrefix("/templates/assets/", http.FileServer(http.Dir(staticDir))),
)
// Page de login
r.HandleFunc("/login", renders.Login)
r.HandleFunc("/api/login", login.LoginHandler(bd)).Methods("POST")
r.HandleFunc("/api/scan/{id}", library.ScanFolder(bd)).Methods("GET")
r.HandleFunc("/api/download/stream", renders.HandleJobsStream(bd))
// Génération playlist
r.HandleFunc("/playlist.m3u", func(w http.ResponseWriter, r *http.Request) {
uploadDir := "/app/upload"
w.Header().Set("Content-Type", "audio/x-mpegurl")
fmt.Fprintln(w, "#EXTM3U")
err := filepath.Walk(uploadDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
relPath, _ := filepath.Rel(uploadDir, path)
relPath = filepath.ToSlash(relPath)
fileURL := fmt.Sprintf("https://media.canguidev.fr/upload/%s", relPath)
fmt.Fprintln(w, fileURL)
return nil
})
if err != nil {
http.Error(w, "Erreur lors de la génération de la playlist", http.StatusInternalServerError)
}
})
// WebDAV sécurisé
username := "tonuser" // ton login
password := "tonpassword" // ton password
webdavHandler := &webdav.Handler{
Prefix: "/webdav/",
FileSystem: webdav.Dir("/app/upload"),
LockSystem: webdav.NewMemLS(),
}
r.PathPrefix("/webdav/").Handler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
// Authentification
auth := req.Header.Get("Authorization")
if auth == "" || !checkAuth(auth, username, password) {
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// Protection lecture seule
if req.Method != "GET" && req.Method != "HEAD" && req.Method != "OPTIONS" && req.Method != "PROPFIND" {
http.Error(w, "Read-Only", http.StatusForbidden)
return
}
log.Printf("WebDAV request: %s %s", req.Method, req.URL.Path)
// Headers WebDAV que VLC attend
w.Header().Set("DAV", "1,2")
w.Header().Set("MS-Author-Via", "DAV")
webdavHandler.ServeHTTP(w, req)
}))
}
// Routes protégées
func RoutesProtected(r *mux.Router, bd *gorm.DB) {
// Ici on place les vues et API qui doivent être protégées
r.HandleFunc("/stream", StreamHandler)
r.HandleFunc("/dashboard", renders.Dashboard(bd))
r.HandleFunc("/settings", renders.Settings)
r.HandleFunc("/library", renders.Library)
r.HandleFunc("/menuLibary", renders.Library)
r.HandleFunc("/godownloader/downloads", renders.GoDownload)
r.HandleFunc("/godownloader/linkcollectors", renders.GoDownloadLinkCollectors)
r.HandleFunc("/godownloader/settings", renders.GoDownloadSetting(bd))
r.HandleFunc("/godownloader/poll-status", renders.PollStatusHandler(bd))
r.HandleFunc("/godownloader/table-refresh", renders.GoDownloadPartialTable(bd))
r.HandleFunc("/godownloader/settings/delete", renders.GoDownloadSettingDelete(bd))
r.HandleFunc("/api/download/add", renders.HandleAddJob(bd)).Methods("POST")
r.HandleFunc("/api/download/all", renders.HandleListJobsPartial(bd)).Methods("GET")
r.HandleFunc("/downloads", renders.GoDownload2(bd))
r.HandleFunc("/stream/{id}", download.HandleStreamPage()).Methods("GET")
r.HandleFunc("/api/download/start/{id}", renders.HandleStartJob(bd)).Methods("POST")
r.HandleFunc("/api/download/pause/{id}", renders.HandlePauseJob).Methods("POST")
r.HandleFunc("/api/download/resume/{id}", renders.HandleResumeJob(bd)).Methods("POST")
r.HandleFunc("/api/download/delete/{id}", renders.HandleDeleteJob(bd)).Methods("DELETE")
r.HandleFunc("/api/download/delete-multiple", renders.HandleDeleteMultipleJobs(bd)).Methods("POST")
// API user
r.HandleFunc("/api/user/create", users.CreateUser(bd)).Methods("POST")
r.HandleFunc("/api/user/update/{id}", users.UpdateUser(bd)).Methods("PUT")
r.HandleFunc("/api/user/delete/{id}", users.DeleteUser(bd)).Methods("DELETE")
r.HandleFunc("/api/user/all/", users.ReadAllUser(bd)).Methods("GET")
r.HandleFunc("/api/user/{id}", users.FindUserById(bd)).Methods("GET")
// API download
r.HandleFunc("/api/pathDownload/create", download.CreateSavePath(bd)).Methods("POST")
r.HandleFunc("/api/pathDownload/update/{id}", download.UpdateSavePath(bd)).Methods("PUT")
r.HandleFunc("/api/pathDownload/delete/{id}", download.DeleteSavePath(bd)).Methods("DELETE")
r.HandleFunc("/api/pathDownload/all/", download.ReadAllSavePath(bd)).Methods("GET")
//API Check path
r.HandleFunc("/validate-path", download.PathValidationHandler)
//API Scan folder
}
func StreamHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
flusher, ok := w.(http.Flusher)
if !ok {
http.Error(w, "Le streaming nest pas supporté par ce serveur", http.StatusInternalServerError)
return
}
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
// Boucle infinie (ou jusqu'à annulation)
for {
select {
case <-ticker.C:
fmt.Fprintf(w, "data: <p>Message #%d</p>\n\n")
flusher.Flush()
case <-r.Context().Done():
// Le client a probablement fermé la connexion
log.Println("Client déconnecté")
return
}
}
}