Fix pinned icons, add bulk download, add media metadata
Some checks failed
Automated Container Build / build-and-push (push) Has been cancelled
Some checks failed
Automated Container Build / build-and-push (push) Has been cancelled
This commit is contained in:
parent
2b49e90b81
commit
ed5cc79c25
6 changed files with 182 additions and 18 deletions
|
|
@ -19,6 +19,7 @@ FROM alpine:3.21
|
|||
|
||||
RUN apk add --no-cache \
|
||||
ffmpeg \
|
||||
exiftool \
|
||||
sqlite \
|
||||
ca-certificates \
|
||||
mailcap \
|
||||
|
|
|
|||
|
|
@ -32,9 +32,10 @@ type FileInfo struct {
|
|||
Size int64 `json:"size"`
|
||||
MimeType string `json:"mime_type"`
|
||||
IsPinned bool `json:"is_pinned"`
|
||||
IsTrashed bool `json:"is_trashed"`
|
||||
ModTime time.Time `json:"mod_time"`
|
||||
Checksum string `json:"checksum,omitempty"`
|
||||
IsTrashed bool `json:"is_trashed"`
|
||||
ModTime time.Time `json:"mod_time"`
|
||||
Checksum string `json:"checksum,omitempty"`
|
||||
Metadata map[string]interface{} `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type FolderNode struct {
|
||||
|
|
@ -280,10 +281,28 @@ func (h *FSHandler) GetExtendedFileInfo(c *fiber.Ctx) error {
|
|||
return nil
|
||||
})
|
||||
fi.Size = totalSize
|
||||
return c.JSON(fiber.Map{
|
||||
"info": fi,
|
||||
"file_count": fileCount,
|
||||
"created_at": createdAt,
|
||||
})
|
||||
}
|
||||
|
||||
// For files, attempt to get media metadata
|
||||
cat := categorizeFile(filepath.Ext(info.Name()))
|
||||
if cat == "images" || cat == "videos" || cat == "audio" {
|
||||
cmd := exec.Command("exiftool", "-json", resolvedPath)
|
||||
output, err := cmd.Output()
|
||||
if err == nil {
|
||||
var meta []map[string]interface{}
|
||||
if err := json.Unmarshal(output, &meta); err == nil && len(meta) > 0 {
|
||||
fi.Metadata = meta[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"info": fi,
|
||||
"info": fi,
|
||||
"file_count": fileCount,
|
||||
"created_at": createdAt,
|
||||
})
|
||||
|
|
@ -679,6 +698,90 @@ func (h *FSHandler) DownloadFolder(c *fiber.Ctx) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// DownloadBulk creates and streams a ZIP archive of multiple selected items.
|
||||
// POST /api/files/download-bulk
|
||||
func (h *FSHandler) DownloadBulk(c *fiber.Ctx) error {
|
||||
var body struct {
|
||||
Paths []string `json:"paths" form:"paths"`
|
||||
}
|
||||
if err := c.BodyParser(&body); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid payload"})
|
||||
}
|
||||
|
||||
if len(body.Paths) == 0 {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "no paths provided"})
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "application/zip")
|
||||
c.Set("Content-Disposition", "attachment; filename=\"download.zip\"")
|
||||
|
||||
c.Context().SetBodyStreamWriter(func(w *bufio.Writer) {
|
||||
zipWriter := zip.NewWriter(w)
|
||||
defer zipWriter.Close()
|
||||
|
||||
for _, p := range body.Paths {
|
||||
fullPath, err := h.resolveSafe(p)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
info, err := os.Stat(fullPath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if info.IsDir() {
|
||||
filepath.Walk(fullPath, func(path string, walkInfo os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Make it relative to the parent of the chosen directory
|
||||
relPath, err := filepath.Rel(filepath.Dir(fullPath), path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if walkInfo.IsDir() {
|
||||
relPath += "/"
|
||||
_, _ = zipWriter.Create(relPath)
|
||||
return nil
|
||||
}
|
||||
|
||||
zipFile, err := zipWriter.Create(relPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fsFile, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fsFile.Close()
|
||||
|
||||
_, _ = io.Copy(zipFile, fsFile)
|
||||
return nil
|
||||
})
|
||||
} else {
|
||||
zipFile, err := zipWriter.Create(info.Name())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
fsFile, err := os.Open(fullPath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
_, _ = io.Copy(zipFile, fsFile)
|
||||
fsFile.Close()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TogglePin pins or unpins a file/folder.
|
||||
// POST /api/files/pin
|
||||
func (h *FSHandler) TogglePin(c *fiber.Ctx) error {
|
||||
|
|
|
|||
|
|
@ -163,6 +163,7 @@ func main() {
|
|||
protected.Post("/files/move", fsHandler.Move)
|
||||
protected.Post("/files/copy", fsHandler.Copy)
|
||||
protected.Get("/files/download-folder", fsHandler.DownloadFolder)
|
||||
protected.Post("/files/download-bulk", fsHandler.DownloadBulk)
|
||||
protected.Post("/files/upload", fsHandler.Upload)
|
||||
|
||||
protected.Get("/files/folders-tree", fsHandler.GetFolderTree)
|
||||
|
|
|
|||
Reference in a new issue