diff --git a/backend/workers/thumbnails.go b/backend/workers/thumbnails.go index 6c54aa4..a3dd8f6 100644 --- a/backend/workers/thumbnails.go +++ b/backend/workers/thumbnails.go @@ -154,81 +154,120 @@ func generateOfficeThumbnail(filePath, destPath string, cfg *config.Config) erro ext = "docx" } - payload := map[string]interface{}{ - "async": false, - "filetype": ext, - "key": fmt.Sprintf("thumb_%d", time.Now().UnixNano()), - "outputtype": "jpg", - "title": "preview.jpg", - "url": fileUrl, - "thumbnail": map[string]interface{}{ - "aspect": 1, - "first": true, - "width": 1024, - "height": 1024, - }, - } - - if ext == "xlsx" { - payload["spreadsheetLayout"] = map[string]interface{}{ - "ignorePrintArea": true, - "printGridlines": true, - "printHeadings": true, - "fitToWidth": 1, + callConvert := func(payload map[string]interface{}) (string, error) { + payloadBytes, err := json.Marshal(payload) + if err != nil { + return "", err } - } - payloadBytes, err := json.Marshal(payload) - if err != nil { - return err - } - - req, err := http.NewRequest("POST", "https://office.elijahkuntz.com/ConvertService.ashx", bytes.NewBuffer(payloadBytes)) - if err != nil { - return err - } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("Accept", "application/json") - - // Sign the payload with the OnlyOffice JWT - if cfg.OnlyOfficeJWT != "" { - jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims(payload)) - signedToken, err := jwtToken.SignedString([]byte(cfg.OnlyOfficeJWT)) - if err == nil { - req.Header.Set("Authorization", "Bearer "+signedToken) + req, err := http.NewRequest("POST", "https://office.elijahkuntz.com/ConvertService.ashx", bytes.NewBuffer(payloadBytes)) + if err != nil { + return "", err } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Accept", "application/json") + + if cfg.OnlyOfficeJWT != "" { + jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims(payload)) + signedToken, err := jwtToken.SignedString([]byte(cfg.OnlyOfficeJWT)) + if err == nil { + req.Header.Set("Authorization", "Bearer "+signedToken) + } + } + + client := &http.Client{Timeout: 30 * time.Second} + resp, err := client.Do(req) + if err != nil { + return "", fmt.Errorf("conversion request failed: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("conversion request returned status: %d", resp.StatusCode) + } + + var result struct { + Error *int `json:"error,omitempty"` + FileUrl string `json:"fileUrl,omitempty"` + } + if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + return "", fmt.Errorf("failed to decode conversion response: %w", err) + } + + if result.Error != nil && *result.Error != 0 { + return "", fmt.Errorf("conversion service returned error code: %d", *result.Error) + } + + if result.FileUrl == "" { + return "", fmt.Errorf("no fileUrl in conversion response") + } + return result.FileUrl, nil } - client := &http.Client{Timeout: 30 * time.Second} - resp, err := client.Do(req) - if err != nil { - return fmt.Errorf("conversion request failed: %w", err) - } - defer resp.Body.Close() + var finalImgUrl string - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("conversion request returned status: %d", resp.StatusCode) - } - - var result struct { - Error *int `json:"error,omitempty"` - FileUrl string `json:"fileUrl,omitempty"` - } - if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { - return fmt.Errorf("failed to decode conversion response: %w", err) - } - - // Wait, the API might return error 0 for success - if result.Error != nil && *result.Error != 0 { - return fmt.Errorf("conversion service returned error code: %d", *result.Error) - } - - if result.FileUrl == "" { - return fmt.Errorf("no fileUrl in conversion response") + if ext == "xlsx" || ext == "xls" { + pdfPayload := map[string]interface{}{ + "async": false, + "filetype": ext, + "key": fmt.Sprintf("thumb_pdf_%d", time.Now().UnixNano()), + "outputtype": "pdf", + "title": "preview.pdf", + "url": fileUrl, + "spreadsheetLayout": map[string]interface{}{ + "ignorePrintArea": true, + "printGridlines": true, + "printHeadings": true, + "fitToWidth": 1, + }, + } + pdfUrl, err := callConvert(pdfPayload) + if err != nil { + return fmt.Errorf("failed to convert xlsx to pdf: %w", err) + } + + jpgPayload := map[string]interface{}{ + "async": false, + "filetype": "pdf", + "key": fmt.Sprintf("thumb_jpg_%d", time.Now().UnixNano()), + "outputtype": "jpg", + "title": "preview.jpg", + "url": pdfUrl, + "thumbnail": map[string]interface{}{ + "aspect": 1, + "first": true, + "width": 1024, + "height": 1024, + }, + } + finalImgUrl, err = callConvert(jpgPayload) + if err != nil { + return fmt.Errorf("failed to convert pdf to jpg: %w", err) + } + } else { + payload := map[string]interface{}{ + "async": false, + "filetype": ext, + "key": fmt.Sprintf("thumb_%d", time.Now().UnixNano()), + "outputtype": "jpg", + "title": "preview.jpg", + "url": fileUrl, + "thumbnail": map[string]interface{}{ + "aspect": 1, + "first": true, + "width": 1024, + "height": 1024, + }, + } + var err error + finalImgUrl, err = callConvert(payload) + if err != nil { + return err + } } // Download the resulting image - imgResp, err := http.Get(result.FileUrl) + imgResp, err := http.Get(finalImgUrl) if err != nil { return fmt.Errorf("failed to download converted image: %w", err) }