Feat: Live thumbnails for office files
All checks were successful
Automated Container Build / build-and-push (push) Successful in 1m26s

This commit is contained in:
Elijah 2026-05-25 14:43:04 -07:00
parent b80abdbefb
commit 80d60d540a
10 changed files with 244 additions and 106 deletions

View file

@ -10,13 +10,19 @@ import (
"strings"
"git.elijahkuntz.com/Elijah/drive/config"
"git.elijahkuntz.com/Elijah/drive/database"
"git.elijahkuntz.com/Elijah/drive/middleware"
"git.elijahkuntz.com/Elijah/drive/workers"
"github.com/gofiber/fiber/v2"
"github.com/golang-jwt/jwt/v5"
"sync"
"time"
"mime"
)
type OnlyOfficeHandler struct {
Config *config.Config
DB *database.DB
}
type CallbackRequest struct {
@ -73,12 +79,51 @@ func (h *OnlyOfficeHandler) Callback(c *fiber.Ctx) error {
if _, err := io.Copy(out, resp.Body); err != nil {
return c.Status(500).JSON(fiber.Map{"error": "failed to write file"})
}
h.scheduleThumbnailUpdate(targetPath, path)
}
// Send successful response according to OnlyOffice API
return c.JSON(fiber.Map{"error": 0})
}
var (
saveDebounceMutex sync.Mutex
saveTimers = make(map[string]*time.Timer)
)
func (h *OnlyOfficeHandler) scheduleThumbnailUpdate(targetPath, relativePath string) {
saveDebounceMutex.Lock()
defer saveDebounceMutex.Unlock()
if timer, exists := saveTimers[targetPath]; exists {
timer.Stop()
}
saveTimers[targetPath] = time.AfterFunc(10*time.Second, func() {
saveDebounceMutex.Lock()
delete(saveTimers, targetPath)
saveDebounceMutex.Unlock()
checksum, err := generateChecksum(targetPath)
if err != nil {
return
}
info, err := os.Stat(targetPath)
if err != nil {
return
}
h.DB.Exec("UPDATE files SET checksum = ?, size = ?, updated_at = CURRENT_TIMESTAMP WHERE path = ?", checksum, info.Size(), filepath.ToSlash(relativePath))
workers.Instance.Enqueue(workers.ThumbnailJob{
FilePath: relativePath,
Checksum: checksum,
MimeType: mime.TypeByExtension(filepath.Ext(relativePath)),
})
})
}
// DownloadForEditor serves a file to the OnlyOffice Document Server.
// This is a public endpoint that validates the download token manually,
// bypassing the auth middleware (which can fail when requests are proxied

View file

@ -40,8 +40,6 @@ func (h *SettingsHandler) UpdateSettings(c *fiber.Ctx) error {
allowedKeys := map[string]bool{
"theme": true,
"thumbnail_images": true,
"thumbnail_videos": true,
"trash_auto_purge_days": true,
"pinned_sidebar_expanded": true,
"pinned_order": true,