From d0fd0a2ff17cafdf866b894d8b3d28807199f795 Mon Sep 17 00:00:00 2001 From: Abhishek Shroff Date: Thu, 31 Jul 2025 22:05:07 +0530 Subject: [PATCH] [server][thumbs] Generate thumbnails for office documents --- server/internal/thumbs/thumbs.go | 56 +++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/server/internal/thumbs/thumbs.go b/server/internal/thumbs/thumbs.go index 24980760..1395ff73 100644 --- a/server/internal/thumbs/thumbs.go +++ b/server/internal/thumbs/thumbs.go @@ -6,6 +6,7 @@ import ( "os" "os/exec" "path/filepath" + "slices" "strings" "codeberg.org/shroff/phylum/server/internal/storage" @@ -29,9 +30,28 @@ var imageTypes = map[string]bool{ } var applicationTextTypes = map[string]bool{ - "json": true, - "yaml": true, - "toml": true, + "json": true, + "yaml": true, + "toml": true, + "x-sh": true, + "x-sql": true, + "xml": true, +} +var applicationImageTypes = map[string]bool{ + "pdf": true, + "postscript": true, +} + +var applicationDocumentTypes = map[string]bool{ + "msword": true, + "vnd.ms-excel": true, + "vnd.ms-powerpoint": true, + "vnd.oasis.opendocument.presentation": true, + "vnd.oasis.opendocument.spreadsheet": true, + "vnd.oasis.opendocument.text": true, + "vnd.openxmlformats-officedocument.presentationml.presentation": true, + "vnd.openxmlformats-officedocument.spreadsheetml.sheet": true, + "vnd.openxmlformats-officedocument.wordprocessingml.document": true, } func NewThumber(cfg Config) (*Thumber, error) { @@ -62,9 +82,18 @@ func (t *Thumber) Generate(path, mimeType string) (bool, error) { return true, t.createTextThumbnail(path, output) } if subType, ok := strings.CutPrefix(mimeType, "application/"); ok { + if _, ok := applicationImageTypes[subType]; ok { + return true, t.createImageThumbnail(path, output) + } if _, ok := applicationTextTypes[subType]; ok { return true, t.createTextThumbnail(path, output) } + if strings.HasSuffix("+json", subType) || strings.HasSuffix("+xml", subType) { + return true, t.createTextThumbnail(path, output) + } + if _, ok := applicationDocumentTypes[subType]; ok { + return true, t.createDocumentThumbnail(path, output) + } } return false, nil } @@ -89,16 +118,27 @@ func (t *Thumber) createImageThumbnail(input, output string) error { } func (t *Thumber) createTextThumbnail(input, output string) error { - cmd := exec.Command( - "soffice", + return t.createThumbnailLibreOffice(input, output, true) +} + +func (t *Thumber) createDocumentThumbnail(input, output string) error { + return t.createThumbnailLibreOffice(input, output, false) +} + +func (t *Thumber) createThumbnailLibreOffice(input, output string, text bool) error { + args := []string{ "--headless", - "--infilter=\"Text (encoded):UTF8,LF,Droid Sans,en-US\"", "--convert-to", - "webp:writer_webp_Export", + "webp", "--outdir", t.dir, input, - ) + } + if text { + args = slices.Insert(args, 1, "--infilter=\"Text (encoded):UTF8,LF,Droid Sans,en-US\"") + } + + cmd := exec.Command("soffice", args...) if err := cmd.Run(); err != nil { return errors.New("failed to generate text thumbnail: " + err.Error())