Merge branch 'main' of https://lab.canguidev.fr/cangui/shelfy
This commit is contained in:
commit
2cdee0eed1
@ -157,7 +157,7 @@ func (c *Client) RequestDeviceCodeWithCredentials(ctx context.Context, username,
|
|||||||
form.Set("grant_type", "password") // possible variation
|
form.Set("grant_type", "password") // possible variation
|
||||||
form.Set("username", username)
|
form.Set("username", username)
|
||||||
form.Set("password", password)
|
form.Set("password", password)
|
||||||
form.Set("scope", "get.post.downloader get.post.seedbox get.account")
|
form.Set("scope", "get.post.downloader get.post.seedbox get.account get.post.stream")
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, "https://debrid-link.com/api/oauth/device/code", strings.NewReader(form.Encode()))
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, "https://debrid-link.com/api/oauth/device/code", strings.NewReader(form.Encode()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -319,6 +319,11 @@ func (c *Client) doJSON(ctx context.Context, method, path string, params url.Val
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
reqBody = bytes.NewReader(b)
|
reqBody = bytes.NewReader(b)
|
||||||
|
|
||||||
|
// 👇 DEBUG : afficher le body
|
||||||
|
log.Printf("➡️ [API %s] URL: %s\nBody: %s\n", method, urlStr, string(b))
|
||||||
|
} else {
|
||||||
|
log.Printf("➡️ [API %s] URL: %s (empty body)", method, urlStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, method, urlStr, reqBody)
|
req, err := http.NewRequestWithContext(ctx, method, urlStr, reqBody)
|
||||||
@ -326,7 +331,11 @@ func (c *Client) doJSON(ctx context.Context, method, path string, params url.Val
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Set("Authorization", "Bearer "+c.account.AccessToken)
|
// 👇 DEBUG : afficher le header Authorization
|
||||||
|
authHeader := "Bearer " + c.account.AccessToken
|
||||||
|
log.Printf("➡️ Authorization Header: %s\n", authHeader)
|
||||||
|
|
||||||
|
req.Header.Set("Authorization", authHeader)
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
resp, err := c.http.Do(req)
|
resp, err := c.http.Do(req)
|
||||||
@ -346,6 +355,7 @@ func (c *Client) doJSON(ctx context.Context, method, path string, params url.Val
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// =========================== RSS ===========================
|
// =========================== RSS ===========================
|
||||||
type RSSFeed struct {
|
type RSSFeed struct {
|
||||||
ID string `json:"id" gorm:"column:id;primaryKey"`
|
ID string `json:"id" gorm:"column:id;primaryKey"`
|
||||||
@ -525,16 +535,18 @@ func (c *Client) ListFiles(ctx context.Context, parentID string) ([]File, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// =========================== Stream ===========================
|
// =========================== Stream ===========================
|
||||||
func (c *Client) CreateTranscode(ctx context.Context, fileID, preset string) (string, error) {
|
// func (c *Client) CreateTranscode(ctx context.Context, fileID, preset string) (string, error) {
|
||||||
var resp struct{ TranscodeID string `json:"transcodeId"` }
|
// var resp struct{ TranscodeID string `json:"transcodeId"` }
|
||||||
body := map[string]string{"fileId": fileID, "preset": preset}
|
// body := map[string]string{"fileId": fileID}
|
||||||
if err := c.doJSON(ctx, "POST", "stream/transcode", nil, body, &resp); err != nil {
|
// if err := c.doJSON(ctx, "POST", "stream/transcode", nil, body, &resp); err != nil {
|
||||||
return "", err
|
// return "", err
|
||||||
}
|
// }
|
||||||
return resp.TranscodeID, nil
|
// return resp.TranscodeID, nil
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
func (c *Client) CreateTranscode(ctx context.Context, fileID string) (*StreamInfo, error) {
|
||||||
|
body := map[string]string{"id": fileID}
|
||||||
|
|
||||||
func (c *Client) GetTranscode(ctx context.Context, transcodeID string) (*StreamInfo, error) {
|
|
||||||
var raw struct {
|
var raw struct {
|
||||||
Success bool `json:"success"`
|
Success bool `json:"success"`
|
||||||
Value struct {
|
Value struct {
|
||||||
@ -545,15 +557,16 @@ func (c *Client) GetTranscode(ctx context.Context, transcodeID string) (*StreamI
|
|||||||
MimeType string `json:"mimetype"`
|
MimeType string `json:"mimetype"`
|
||||||
Domain string `json:"domain"`
|
Domain string `json:"domain"`
|
||||||
File struct {
|
File struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Size int64 `json:"size"`
|
Size int64 `json:"size"`
|
||||||
|
Source string `json:"source"`
|
||||||
} `json:"file"`
|
} `json:"file"`
|
||||||
} `json:"value"`
|
} `json:"value"`
|
||||||
}
|
}
|
||||||
|
|
||||||
path := fmt.Sprintf("stream/transcode/%s", transcodeID)
|
path := "stream/transcode/add"
|
||||||
if err := c.doJSON(ctx, "GET", path, nil, nil, &raw); err != nil {
|
if err := c.doJSON(ctx, "POST", path, nil, body, &raw); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -570,3 +583,7 @@ func (c *Client) GetTranscode(ctx context.Context, transcodeID string) (*StreamI
|
|||||||
}
|
}
|
||||||
return info, nil
|
return info, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -95,56 +95,55 @@ func RoutesPublic(r *mux.Router, bd *gorm.DB) {
|
|||||||
http.Error(w, "Erreur lors de la génération de la playlist", http.StatusInternalServerError)
|
http.Error(w, "Erreur lors de la génération de la playlist", http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
r.PathPrefix("/webdav/").Handler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
r.PathPrefix("/webdav/").Handler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
authHeader := req.Header.Get("Authorization")
|
authHeader := req.Header.Get("Authorization")
|
||||||
if authHeader == "" {
|
if authHeader == "" {
|
||||||
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
|
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
|
||||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authentification HTTP Basic en base de données
|
// Authentification HTTP Basic en base de données
|
||||||
email, password, ok := req.BasicAuth()
|
email, password, ok := req.BasicAuth()
|
||||||
if !ok {
|
if !ok {
|
||||||
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
|
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
|
||||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
log.Printf("✅ email saisi: %s", email)
|
||||||
|
log.Printf("✅ password saisi: %s", password)
|
||||||
|
|
||||||
var user models.User
|
var user models.User
|
||||||
result := bd.Where("email = ?", email).First(&user)
|
result := bd.Where("email = ?", email).First(&user)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
|
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
|
||||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
|
err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
|
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
|
||||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lecture seule
|
// ✅ Ici on autorise TOUTES les méthodes WebDAV (lecture/écriture/suppression)
|
||||||
if req.Method != "GET" && req.Method != "HEAD" && req.Method != "OPTIONS" && req.Method != "PROPFIND" {
|
log.Printf("✅ WebDAV FULL ACCESS for user: %s", email)
|
||||||
http.Error(w, "Read-Only", http.StatusForbidden)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("✅ WebDAV access for user: %s", email)
|
// Headers WebDAV que certains clients attendent
|
||||||
|
w.Header().Set("DAV", "1,2")
|
||||||
|
w.Header().Set("MS-Author-Via", "DAV")
|
||||||
|
|
||||||
w.Header().Set("DAV", "1,2")
|
// Handler WebDAV complet
|
||||||
w.Header().Set("MS-Author-Via", "DAV")
|
webdavHandler := &webdav.Handler{
|
||||||
|
Prefix: "/webdav/",
|
||||||
|
FileSystem: webdav.Dir("/app/upload"),
|
||||||
|
LockSystem: webdav.NewMemLS(),
|
||||||
|
}
|
||||||
|
|
||||||
webdavHandler := &webdav.Handler{
|
webdavHandler.ServeHTTP(w, req)
|
||||||
Prefix: "/webdav/",
|
}))
|
||||||
FileSystem: webdav.Dir("/app/upload"),
|
|
||||||
LockSystem: webdav.NewMemLS(),
|
|
||||||
}
|
|
||||||
|
|
||||||
webdavHandler.ServeHTTP(w, req)
|
|
||||||
}))
|
|
||||||
|
|
||||||
// WebDAV sécurisé
|
// WebDAV sécurisé
|
||||||
// username := "tonuser" // ton login
|
// username := "tonuser" // ton login
|
||||||
|
|||||||
@ -360,6 +360,14 @@ func HandleAddJob(db *gorm.DB) http.HandlerFunc {
|
|||||||
|
|
||||||
// Enregistre chaque lien comme un job "en attente"
|
// Enregistre chaque lien comme un job "en attente"
|
||||||
for _, l := range links {
|
for _, l := range links {
|
||||||
|
log.Printf("[l'id] : %v\n", l.ID)
|
||||||
|
|
||||||
|
streamInfo, err := client.CreateTranscode(ctx,l.ID)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Erreur GetTranscode:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
job := &download.DownloadJob{
|
job := &download.DownloadJob{
|
||||||
ID: l.ID,
|
ID: l.ID,
|
||||||
Link: l.DownloadURL,
|
Link: l.DownloadURL,
|
||||||
@ -369,7 +377,7 @@ func HandleAddJob(db *gorm.DB) http.HandlerFunc {
|
|||||||
Size: l.Size,
|
Size: l.Size,
|
||||||
Host: l.Host,
|
Host: l.Host,
|
||||||
Progress: 0, // obligatoire si valeur attendue
|
Progress: 0, // obligatoire si valeur attendue
|
||||||
StreamURL: "", // vide par défaut
|
StreamURL: streamInfo.StreamURL, // vide par défaut
|
||||||
}
|
}
|
||||||
if err := download.RegisterJobWithDB(job, db); err != nil {
|
if err := download.RegisterJobWithDB(job, db); err != nil {
|
||||||
log.Printf("[ERROR] Job non enregistré : %v\n", err)
|
log.Printf("[ERROR] Job non enregistré : %v\n", err)
|
||||||
|
|||||||
@ -51,11 +51,14 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<section class="section is-info">
|
<section class="section is-primary">
|
||||||
<h1 class="title">Section</h1>
|
<h1 class="title">Section</h1>
|
||||||
<h2 class="subtitle">
|
<div class="column">
|
||||||
A simple container to divide your page into <strong>sections</strong>, like
|
<div hx-get="/godownloader/settings" hx-trigger="load" hx-target="#download-list"> </div>
|
||||||
the one you're currently reading.
|
<div id="download-list">
|
||||||
</h2>
|
<!-- Liste des chemins apparaîtra ici -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
Loading…
Reference in New Issue
Block a user