mirror of
https://github.com/sysadminsmedia/homebox.git
synced 2025-12-25 14:59:21 +01:00
More image type support for thumbnails (#814)
This commit is contained in:
@@ -31,6 +31,8 @@ type Attachment struct {
|
||||
Title string `json:"title,omitempty"`
|
||||
// Path holds the value of the "path" field.
|
||||
Path string `json:"path,omitempty"`
|
||||
// MimeType holds the value of the "mime_type" field.
|
||||
MimeType string `json:"mime_type,omitempty"`
|
||||
// Edges holds the relations/edges for other nodes in the graph.
|
||||
// The values are being populated by the AttachmentQuery when eager-loading is set.
|
||||
Edges AttachmentEdges `json:"edges"`
|
||||
@@ -79,7 +81,7 @@ func (*Attachment) scanValues(columns []string) ([]any, error) {
|
||||
switch columns[i] {
|
||||
case attachment.FieldPrimary:
|
||||
values[i] = new(sql.NullBool)
|
||||
case attachment.FieldType, attachment.FieldTitle, attachment.FieldPath:
|
||||
case attachment.FieldType, attachment.FieldTitle, attachment.FieldPath, attachment.FieldMimeType:
|
||||
values[i] = new(sql.NullString)
|
||||
case attachment.FieldCreatedAt, attachment.FieldUpdatedAt:
|
||||
values[i] = new(sql.NullTime)
|
||||
@@ -146,6 +148,12 @@ func (a *Attachment) assignValues(columns []string, values []any) error {
|
||||
} else if value.Valid {
|
||||
a.Path = value.String
|
||||
}
|
||||
case attachment.FieldMimeType:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field mime_type", values[i])
|
||||
} else if value.Valid {
|
||||
a.MimeType = value.String
|
||||
}
|
||||
case attachment.ForeignKeys[0]:
|
||||
if value, ok := values[i].(*sql.NullScanner); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field attachment_thumbnail", values[i])
|
||||
@@ -223,6 +231,9 @@ func (a *Attachment) String() string {
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("path=")
|
||||
builder.WriteString(a.Path)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("mime_type=")
|
||||
builder.WriteString(a.MimeType)
|
||||
builder.WriteByte(')')
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ const (
|
||||
FieldTitle = "title"
|
||||
// FieldPath holds the string denoting the path field in the database.
|
||||
FieldPath = "path"
|
||||
// FieldMimeType holds the string denoting the mime_type field in the database.
|
||||
FieldMimeType = "mime_type"
|
||||
// EdgeItem holds the string denoting the item edge name in mutations.
|
||||
EdgeItem = "item"
|
||||
// EdgeThumbnail holds the string denoting the thumbnail edge name in mutations.
|
||||
@@ -56,6 +58,7 @@ var Columns = []string{
|
||||
FieldPrimary,
|
||||
FieldTitle,
|
||||
FieldPath,
|
||||
FieldMimeType,
|
||||
}
|
||||
|
||||
// ForeignKeys holds the SQL foreign-keys that are owned by the "attachments"
|
||||
@@ -93,6 +96,8 @@ var (
|
||||
DefaultTitle string
|
||||
// DefaultPath holds the default value on creation for the "path" field.
|
||||
DefaultPath string
|
||||
// DefaultMimeType holds the default value on creation for the "mime_type" field.
|
||||
DefaultMimeType string
|
||||
// DefaultID holds the default value on creation for the "id" field.
|
||||
DefaultID func() uuid.UUID
|
||||
)
|
||||
@@ -165,6 +170,11 @@ func ByPath(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldPath, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByMimeType orders the results by the mime_type field.
|
||||
func ByMimeType(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldMimeType, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByItemField orders the results by item field.
|
||||
func ByItemField(field string, opts ...sql.OrderTermOption) OrderOption {
|
||||
return func(s *sql.Selector) {
|
||||
|
||||
@@ -81,6 +81,11 @@ func Path(v string) predicate.Attachment {
|
||||
return predicate.Attachment(sql.FieldEQ(FieldPath, v))
|
||||
}
|
||||
|
||||
// MimeType applies equality check predicate on the "mime_type" field. It's identical to MimeTypeEQ.
|
||||
func MimeType(v string) predicate.Attachment {
|
||||
return predicate.Attachment(sql.FieldEQ(FieldMimeType, v))
|
||||
}
|
||||
|
||||
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
||||
func CreatedAtEQ(v time.Time) predicate.Attachment {
|
||||
return predicate.Attachment(sql.FieldEQ(FieldCreatedAt, v))
|
||||
@@ -321,6 +326,71 @@ func PathContainsFold(v string) predicate.Attachment {
|
||||
return predicate.Attachment(sql.FieldContainsFold(FieldPath, v))
|
||||
}
|
||||
|
||||
// MimeTypeEQ applies the EQ predicate on the "mime_type" field.
|
||||
func MimeTypeEQ(v string) predicate.Attachment {
|
||||
return predicate.Attachment(sql.FieldEQ(FieldMimeType, v))
|
||||
}
|
||||
|
||||
// MimeTypeNEQ applies the NEQ predicate on the "mime_type" field.
|
||||
func MimeTypeNEQ(v string) predicate.Attachment {
|
||||
return predicate.Attachment(sql.FieldNEQ(FieldMimeType, v))
|
||||
}
|
||||
|
||||
// MimeTypeIn applies the In predicate on the "mime_type" field.
|
||||
func MimeTypeIn(vs ...string) predicate.Attachment {
|
||||
return predicate.Attachment(sql.FieldIn(FieldMimeType, vs...))
|
||||
}
|
||||
|
||||
// MimeTypeNotIn applies the NotIn predicate on the "mime_type" field.
|
||||
func MimeTypeNotIn(vs ...string) predicate.Attachment {
|
||||
return predicate.Attachment(sql.FieldNotIn(FieldMimeType, vs...))
|
||||
}
|
||||
|
||||
// MimeTypeGT applies the GT predicate on the "mime_type" field.
|
||||
func MimeTypeGT(v string) predicate.Attachment {
|
||||
return predicate.Attachment(sql.FieldGT(FieldMimeType, v))
|
||||
}
|
||||
|
||||
// MimeTypeGTE applies the GTE predicate on the "mime_type" field.
|
||||
func MimeTypeGTE(v string) predicate.Attachment {
|
||||
return predicate.Attachment(sql.FieldGTE(FieldMimeType, v))
|
||||
}
|
||||
|
||||
// MimeTypeLT applies the LT predicate on the "mime_type" field.
|
||||
func MimeTypeLT(v string) predicate.Attachment {
|
||||
return predicate.Attachment(sql.FieldLT(FieldMimeType, v))
|
||||
}
|
||||
|
||||
// MimeTypeLTE applies the LTE predicate on the "mime_type" field.
|
||||
func MimeTypeLTE(v string) predicate.Attachment {
|
||||
return predicate.Attachment(sql.FieldLTE(FieldMimeType, v))
|
||||
}
|
||||
|
||||
// MimeTypeContains applies the Contains predicate on the "mime_type" field.
|
||||
func MimeTypeContains(v string) predicate.Attachment {
|
||||
return predicate.Attachment(sql.FieldContains(FieldMimeType, v))
|
||||
}
|
||||
|
||||
// MimeTypeHasPrefix applies the HasPrefix predicate on the "mime_type" field.
|
||||
func MimeTypeHasPrefix(v string) predicate.Attachment {
|
||||
return predicate.Attachment(sql.FieldHasPrefix(FieldMimeType, v))
|
||||
}
|
||||
|
||||
// MimeTypeHasSuffix applies the HasSuffix predicate on the "mime_type" field.
|
||||
func MimeTypeHasSuffix(v string) predicate.Attachment {
|
||||
return predicate.Attachment(sql.FieldHasSuffix(FieldMimeType, v))
|
||||
}
|
||||
|
||||
// MimeTypeEqualFold applies the EqualFold predicate on the "mime_type" field.
|
||||
func MimeTypeEqualFold(v string) predicate.Attachment {
|
||||
return predicate.Attachment(sql.FieldEqualFold(FieldMimeType, v))
|
||||
}
|
||||
|
||||
// MimeTypeContainsFold applies the ContainsFold predicate on the "mime_type" field.
|
||||
func MimeTypeContainsFold(v string) predicate.Attachment {
|
||||
return predicate.Attachment(sql.FieldContainsFold(FieldMimeType, v))
|
||||
}
|
||||
|
||||
// HasItem applies the HasEdge predicate on the "item" edge.
|
||||
func HasItem() predicate.Attachment {
|
||||
return predicate.Attachment(func(s *sql.Selector) {
|
||||
|
||||
@@ -106,6 +106,20 @@ func (ac *AttachmentCreate) SetNillablePath(s *string) *AttachmentCreate {
|
||||
return ac
|
||||
}
|
||||
|
||||
// SetMimeType sets the "mime_type" field.
|
||||
func (ac *AttachmentCreate) SetMimeType(s string) *AttachmentCreate {
|
||||
ac.mutation.SetMimeType(s)
|
||||
return ac
|
||||
}
|
||||
|
||||
// SetNillableMimeType sets the "mime_type" field if the given value is not nil.
|
||||
func (ac *AttachmentCreate) SetNillableMimeType(s *string) *AttachmentCreate {
|
||||
if s != nil {
|
||||
ac.SetMimeType(*s)
|
||||
}
|
||||
return ac
|
||||
}
|
||||
|
||||
// SetID sets the "id" field.
|
||||
func (ac *AttachmentCreate) SetID(u uuid.UUID) *AttachmentCreate {
|
||||
ac.mutation.SetID(u)
|
||||
@@ -217,6 +231,10 @@ func (ac *AttachmentCreate) defaults() {
|
||||
v := attachment.DefaultPath
|
||||
ac.mutation.SetPath(v)
|
||||
}
|
||||
if _, ok := ac.mutation.MimeType(); !ok {
|
||||
v := attachment.DefaultMimeType
|
||||
ac.mutation.SetMimeType(v)
|
||||
}
|
||||
if _, ok := ac.mutation.ID(); !ok {
|
||||
v := attachment.DefaultID()
|
||||
ac.mutation.SetID(v)
|
||||
@@ -248,6 +266,9 @@ func (ac *AttachmentCreate) check() error {
|
||||
if _, ok := ac.mutation.Path(); !ok {
|
||||
return &ValidationError{Name: "path", err: errors.New(`ent: missing required field "Attachment.path"`)}
|
||||
}
|
||||
if _, ok := ac.mutation.MimeType(); !ok {
|
||||
return &ValidationError{Name: "mime_type", err: errors.New(`ent: missing required field "Attachment.mime_type"`)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -307,6 +328,10 @@ func (ac *AttachmentCreate) createSpec() (*Attachment, *sqlgraph.CreateSpec) {
|
||||
_spec.SetField(attachment.FieldPath, field.TypeString, value)
|
||||
_node.Path = value
|
||||
}
|
||||
if value, ok := ac.mutation.MimeType(); ok {
|
||||
_spec.SetField(attachment.FieldMimeType, field.TypeString, value)
|
||||
_node.MimeType = value
|
||||
}
|
||||
if nodes := ac.mutation.ItemIDs(); len(nodes) > 0 {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.M2O,
|
||||
|
||||
@@ -92,6 +92,20 @@ func (au *AttachmentUpdate) SetNillablePath(s *string) *AttachmentUpdate {
|
||||
return au
|
||||
}
|
||||
|
||||
// SetMimeType sets the "mime_type" field.
|
||||
func (au *AttachmentUpdate) SetMimeType(s string) *AttachmentUpdate {
|
||||
au.mutation.SetMimeType(s)
|
||||
return au
|
||||
}
|
||||
|
||||
// SetNillableMimeType sets the "mime_type" field if the given value is not nil.
|
||||
func (au *AttachmentUpdate) SetNillableMimeType(s *string) *AttachmentUpdate {
|
||||
if s != nil {
|
||||
au.SetMimeType(*s)
|
||||
}
|
||||
return au
|
||||
}
|
||||
|
||||
// SetItemID sets the "item" edge to the Item entity by ID.
|
||||
func (au *AttachmentUpdate) SetItemID(id uuid.UUID) *AttachmentUpdate {
|
||||
au.mutation.SetItemID(id)
|
||||
@@ -220,6 +234,9 @@ func (au *AttachmentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
if value, ok := au.mutation.Path(); ok {
|
||||
_spec.SetField(attachment.FieldPath, field.TypeString, value)
|
||||
}
|
||||
if value, ok := au.mutation.MimeType(); ok {
|
||||
_spec.SetField(attachment.FieldMimeType, field.TypeString, value)
|
||||
}
|
||||
if au.mutation.ItemCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.M2O,
|
||||
@@ -360,6 +377,20 @@ func (auo *AttachmentUpdateOne) SetNillablePath(s *string) *AttachmentUpdateOne
|
||||
return auo
|
||||
}
|
||||
|
||||
// SetMimeType sets the "mime_type" field.
|
||||
func (auo *AttachmentUpdateOne) SetMimeType(s string) *AttachmentUpdateOne {
|
||||
auo.mutation.SetMimeType(s)
|
||||
return auo
|
||||
}
|
||||
|
||||
// SetNillableMimeType sets the "mime_type" field if the given value is not nil.
|
||||
func (auo *AttachmentUpdateOne) SetNillableMimeType(s *string) *AttachmentUpdateOne {
|
||||
if s != nil {
|
||||
auo.SetMimeType(*s)
|
||||
}
|
||||
return auo
|
||||
}
|
||||
|
||||
// SetItemID sets the "item" edge to the Item entity by ID.
|
||||
func (auo *AttachmentUpdateOne) SetItemID(id uuid.UUID) *AttachmentUpdateOne {
|
||||
auo.mutation.SetItemID(id)
|
||||
@@ -518,6 +549,9 @@ func (auo *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment,
|
||||
if value, ok := auo.mutation.Path(); ok {
|
||||
_spec.SetField(attachment.FieldPath, field.TypeString, value)
|
||||
}
|
||||
if value, ok := auo.mutation.MimeType(); ok {
|
||||
_spec.SetField(attachment.FieldMimeType, field.TypeString, value)
|
||||
}
|
||||
if auo.mutation.ItemCleared() {
|
||||
edge := &sqlgraph.EdgeSpec{
|
||||
Rel: sqlgraph.M2O,
|
||||
|
||||
@@ -17,6 +17,7 @@ var (
|
||||
{Name: "primary", Type: field.TypeBool, Default: false},
|
||||
{Name: "title", Type: field.TypeString, Default: ""},
|
||||
{Name: "path", Type: field.TypeString, Default: ""},
|
||||
{Name: "mime_type", Type: field.TypeString, Default: "application/octet-stream"},
|
||||
{Name: "attachment_thumbnail", Type: field.TypeUUID, Unique: true, Nullable: true},
|
||||
{Name: "item_attachments", Type: field.TypeUUID, Nullable: true},
|
||||
}
|
||||
@@ -28,13 +29,13 @@ var (
|
||||
ForeignKeys: []*schema.ForeignKey{
|
||||
{
|
||||
Symbol: "attachments_attachments_thumbnail",
|
||||
Columns: []*schema.Column{AttachmentsColumns[7]},
|
||||
Columns: []*schema.Column{AttachmentsColumns[8]},
|
||||
RefColumns: []*schema.Column{AttachmentsColumns[0]},
|
||||
OnDelete: schema.SetNull,
|
||||
},
|
||||
{
|
||||
Symbol: "attachments_items_attachments",
|
||||
Columns: []*schema.Column{AttachmentsColumns[8]},
|
||||
Columns: []*schema.Column{AttachmentsColumns[9]},
|
||||
RefColumns: []*schema.Column{ItemsColumns[0]},
|
||||
OnDelete: schema.Cascade,
|
||||
},
|
||||
|
||||
@@ -62,6 +62,7 @@ type AttachmentMutation struct {
|
||||
primary *bool
|
||||
title *string
|
||||
_path *string
|
||||
mime_type *string
|
||||
clearedFields map[string]struct{}
|
||||
item *uuid.UUID
|
||||
cleareditem bool
|
||||
@@ -392,6 +393,42 @@ func (m *AttachmentMutation) ResetPath() {
|
||||
m._path = nil
|
||||
}
|
||||
|
||||
// SetMimeType sets the "mime_type" field.
|
||||
func (m *AttachmentMutation) SetMimeType(s string) {
|
||||
m.mime_type = &s
|
||||
}
|
||||
|
||||
// MimeType returns the value of the "mime_type" field in the mutation.
|
||||
func (m *AttachmentMutation) MimeType() (r string, exists bool) {
|
||||
v := m.mime_type
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// OldMimeType returns the old "mime_type" field's value of the Attachment entity.
|
||||
// If the Attachment object wasn't provided to the builder, the object is fetched from the database.
|
||||
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||
func (m *AttachmentMutation) OldMimeType(ctx context.Context) (v string, err error) {
|
||||
if !m.op.Is(OpUpdateOne) {
|
||||
return v, errors.New("OldMimeType is only allowed on UpdateOne operations")
|
||||
}
|
||||
if m.id == nil || m.oldValue == nil {
|
||||
return v, errors.New("OldMimeType requires an ID field in the mutation")
|
||||
}
|
||||
oldValue, err := m.oldValue(ctx)
|
||||
if err != nil {
|
||||
return v, fmt.Errorf("querying old value for OldMimeType: %w", err)
|
||||
}
|
||||
return oldValue.MimeType, nil
|
||||
}
|
||||
|
||||
// ResetMimeType resets all changes to the "mime_type" field.
|
||||
func (m *AttachmentMutation) ResetMimeType() {
|
||||
m.mime_type = nil
|
||||
}
|
||||
|
||||
// SetItemID sets the "item" edge to the Item entity by id.
|
||||
func (m *AttachmentMutation) SetItemID(id uuid.UUID) {
|
||||
m.item = &id
|
||||
@@ -504,7 +541,7 @@ func (m *AttachmentMutation) Type() string {
|
||||
// order to get all numeric fields that were incremented/decremented, call
|
||||
// AddedFields().
|
||||
func (m *AttachmentMutation) Fields() []string {
|
||||
fields := make([]string, 0, 6)
|
||||
fields := make([]string, 0, 7)
|
||||
if m.created_at != nil {
|
||||
fields = append(fields, attachment.FieldCreatedAt)
|
||||
}
|
||||
@@ -523,6 +560,9 @@ func (m *AttachmentMutation) Fields() []string {
|
||||
if m._path != nil {
|
||||
fields = append(fields, attachment.FieldPath)
|
||||
}
|
||||
if m.mime_type != nil {
|
||||
fields = append(fields, attachment.FieldMimeType)
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
@@ -543,6 +583,8 @@ func (m *AttachmentMutation) Field(name string) (ent.Value, bool) {
|
||||
return m.Title()
|
||||
case attachment.FieldPath:
|
||||
return m.Path()
|
||||
case attachment.FieldMimeType:
|
||||
return m.MimeType()
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
@@ -564,6 +606,8 @@ func (m *AttachmentMutation) OldField(ctx context.Context, name string) (ent.Val
|
||||
return m.OldTitle(ctx)
|
||||
case attachment.FieldPath:
|
||||
return m.OldPath(ctx)
|
||||
case attachment.FieldMimeType:
|
||||
return m.OldMimeType(ctx)
|
||||
}
|
||||
return nil, fmt.Errorf("unknown Attachment field %s", name)
|
||||
}
|
||||
@@ -615,6 +659,13 @@ func (m *AttachmentMutation) SetField(name string, value ent.Value) error {
|
||||
}
|
||||
m.SetPath(v)
|
||||
return nil
|
||||
case attachment.FieldMimeType:
|
||||
v, ok := value.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.SetMimeType(v)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown Attachment field %s", name)
|
||||
}
|
||||
@@ -682,6 +733,9 @@ func (m *AttachmentMutation) ResetField(name string) error {
|
||||
case attachment.FieldPath:
|
||||
m.ResetPath()
|
||||
return nil
|
||||
case attachment.FieldMimeType:
|
||||
m.ResetMimeType()
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown Attachment field %s", name)
|
||||
}
|
||||
|
||||
@@ -51,6 +51,10 @@ func init() {
|
||||
attachmentDescPath := attachmentFields[3].Descriptor()
|
||||
// attachment.DefaultPath holds the default value on creation for the path field.
|
||||
attachment.DefaultPath = attachmentDescPath.Default.(string)
|
||||
// attachmentDescMimeType is the schema descriptor for mime_type field.
|
||||
attachmentDescMimeType := attachmentFields[4].Descriptor()
|
||||
// attachment.DefaultMimeType holds the default value on creation for the mime_type field.
|
||||
attachment.DefaultMimeType = attachmentDescMimeType.Default.(string)
|
||||
// attachmentDescID is the schema descriptor for id field.
|
||||
attachmentDescID := attachmentMixinFields0[0].Descriptor()
|
||||
// attachment.DefaultID holds the default value on creation for the id field.
|
||||
|
||||
@@ -25,6 +25,7 @@ func (Attachment) Fields() []ent.Field {
|
||||
field.Bool("primary").Default(false),
|
||||
field.String("title").Default(""),
|
||||
field.String("path").Default(""),
|
||||
field.String("mime_type").Default("application/octet-stream"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
-- +goose Up
|
||||
ALTER TABLE public.attachments ADD COLUMN mime_type VARCHAR DEFAULT 'application/octet-stream';
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
-- +goose Up
|
||||
ALTER TABLE attachments ADD COLUMN mime_type TEXT DEFAULT 'application/octet-stream';
|
||||
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
"github.com/zeebo/blake3"
|
||||
|
||||
"github.com/gen2brain/avif"
|
||||
"github.com/gen2brain/heic"
|
||||
"github.com/gen2brain/jpegxl"
|
||||
"github.com/gen2brain/webp"
|
||||
"golang.org/x/image/draw"
|
||||
"image"
|
||||
@@ -62,6 +64,7 @@ type (
|
||||
Primary bool `json:"primary"`
|
||||
Path string `json:"path"`
|
||||
Title string `json:"title"`
|
||||
MimeType string `json:"mimeType,omitempty"`
|
||||
Thumbnail *ent.Attachment `json:"thumbnail,omitempty"`
|
||||
}
|
||||
|
||||
@@ -87,6 +90,8 @@ func ToItemAttachment(attachment *ent.Attachment) ItemAttachment {
|
||||
Primary: attachment.Primary,
|
||||
Path: attachment.Path,
|
||||
Title: attachment.Title,
|
||||
MimeType: attachment.MimeType,
|
||||
Thumbnail: attachment.QueryThumbnail().FirstX(context.Background()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,6 +198,17 @@ func (r *AttachmentRepo) Create(ctx context.Context, itemID uuid.UUID, doc ItemC
|
||||
return nil, err
|
||||
}
|
||||
|
||||
limitedReader := io.LimitReader(doc.Content, 1024*128)
|
||||
file, err := io.ReadAll(limitedReader)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to read file content")
|
||||
err = tx.Rollback()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
bldr = bldr.SetMimeType(http.DetectContentType(file[:min(512, len(file))]))
|
||||
bldr = bldr.SetPath(path)
|
||||
|
||||
attachmentDb, err := bldr.Save(ctx)
|
||||
@@ -416,6 +432,14 @@ func (r *AttachmentRepo) CreateThumbnail(ctx context.Context, groupId, attachmen
|
||||
log.Debug().Msg("detecting content type of original file")
|
||||
contentType := http.DetectContentType(contentBytes[:min(512, len(contentBytes))])
|
||||
|
||||
if contentType == "application/octet-stream" {
|
||||
if strings.HasSuffix(title, ".heic") || strings.HasSuffix(title, ".heif") {
|
||||
contentType = "image/heic"
|
||||
} else if strings.HasSuffix(title, ".avif") {
|
||||
contentType = "image/avif"
|
||||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
case isImageFile(contentType):
|
||||
log.Debug().Msg("creating thumbnail for image file")
|
||||
@@ -532,10 +556,88 @@ func (r *AttachmentRepo) CreateThumbnail(ctx context.Context, groupId, attachmen
|
||||
}
|
||||
log.Debug().Msg("setting thumbnail file path in attachment")
|
||||
att.SetPath(thumbnailFile)
|
||||
case contentType == "image/heic" || contentType == "image/heif":
|
||||
log.Debug().Msg("creating thumbnail for heic file")
|
||||
img, err := heic.Decode(bytes.NewReader(contentBytes))
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to decode avif image")
|
||||
err := tx.Rollback()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
dst := image.NewRGBA(image.Rect(0, 0, r.thumbnail.Width, r.thumbnail.Height))
|
||||
draw.ApproxBiLinear.Scale(dst, dst.Rect, img, img.Bounds(), draw.Over, nil)
|
||||
buf := new(bytes.Buffer)
|
||||
err = webp.Encode(buf, dst, webp.Options{Quality: 80, Lossless: false})
|
||||
if err != nil {
|
||||
err := tx.Rollback()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
contentBytes := buf.Bytes()
|
||||
log.Debug().Msg("uploading thumbnail file")
|
||||
thumbnailFile, err := r.UploadFile(ctx, tx.Group.GetX(ctx, groupId), ItemCreateAttachment{
|
||||
Title: fmt.Sprintf("%s-thumb", title),
|
||||
Content: bytes.NewReader(contentBytes),
|
||||
})
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to upload thumbnail file")
|
||||
err := tx.Rollback()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
log.Debug().Msg("setting thumbnail file path in attachment")
|
||||
att.SetPath(thumbnailFile)
|
||||
case contentType == "image/jxl":
|
||||
log.Debug().Msg("creating thumbnail for jpegxl file")
|
||||
img, err := jpegxl.Decode(bytes.NewReader(contentBytes))
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to decode avif image")
|
||||
err := tx.Rollback()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
dst := image.NewRGBA(image.Rect(0, 0, r.thumbnail.Width, r.thumbnail.Height))
|
||||
draw.ApproxBiLinear.Scale(dst, dst.Rect, img, img.Bounds(), draw.Over, nil)
|
||||
buf := new(bytes.Buffer)
|
||||
err = webp.Encode(buf, dst, webp.Options{Quality: 80, Lossless: false})
|
||||
if err != nil {
|
||||
err := tx.Rollback()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
contentBytes := buf.Bytes()
|
||||
log.Debug().Msg("uploading thumbnail file")
|
||||
thumbnailFile, err := r.UploadFile(ctx, tx.Group.GetX(ctx, groupId), ItemCreateAttachment{
|
||||
Title: fmt.Sprintf("%s-thumb", title),
|
||||
Content: bytes.NewReader(contentBytes),
|
||||
})
|
||||
if err != nil {
|
||||
log.Err(err).Msg("failed to upload thumbnail file")
|
||||
err := tx.Rollback()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
log.Debug().Msg("setting thumbnail file path in attachment")
|
||||
att.SetPath(thumbnailFile)
|
||||
default:
|
||||
return fmt.Errorf("file type %s is not supported for thumbnail creation or document thumnails disabled", title)
|
||||
}
|
||||
|
||||
att.SetMimeType("image/webp")
|
||||
|
||||
log.Debug().Msg("saving thumbnail attachment to database")
|
||||
thumbnail, err := att.Save(ctx)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user