Help us shape the future of Go! Take the 2026 Go Developer Survey

media

package
v1.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 28, 2026 License: Apache-2.0 Imports: 28 Imported by: 0

Documentation

Overview

Package media provides media file management functionality.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrMediaNotFound   = errors.New("media not found")
	ErrInvalidMimeType = errors.New("invalid mime type")
	ErrFileTooLarge    = errors.New("file too large")
	ErrInvalidFile     = errors.New("invalid file")
	// ErrQuotaExceeded is returned when Config.MaxTotalBytes would be exceeded
	// (the public demo caps its total media size).
	ErrQuotaExceeded = errors.New("media storage quota exceeded")
	ErrStorageFailed = errors.New("storage operation failed")
	// ErrImageTooLarge is returned when an image's pixel count exceeds the
	// configured cap (decompression-bomb guard).
	ErrImageTooLarge = errors.New("image dimensions exceed the maximum allowed")
)

Error definitions for the media package.

View Source
var VariantSizes = map[string]struct {
	MaxWidth  int
	MaxHeight int
	Crop      bool
}{
	"thumbnail": {MaxWidth: 150, MaxHeight: 150, Crop: true},
	"medium":    {MaxWidth: 300, MaxHeight: 300, Crop: false},
	"large":     {MaxWidth: 1024, MaxHeight: 1024, Crop: false},
}

VariantSizes defines the standard image variant sizes.

Functions

func AllowedExtensionsForMIME

func AllowedExtensionsForMIME(mimeType string) ([]string, bool)

AllowedExtensionsForMIME returns the extensions permitted for a sniffed MIME type and whether the type is allowed at all.

func ExtensionMatchesMIME

func ExtensionMatchesMIME(ext, mimeType string) bool

ExtensionMatchesMIME reports whether a filename extension is consistent with the sniffed MIME type. It cross-validates content against the declared name so a .png full of JPEG bytes, or a .php renamed .jpg, is rejected. ext is matched case-insensitively and must include the leading dot.

func ImageTypeAndExtensionAllowed

func ImageTypeAndExtensionAllowed(ext, mimeType string) bool

ImageTypeAndExtensionAllowed reports whether the sniffed type and the extension are each an allowed image type, even when they do not pair. Resized copies of WebP uploads written by older versions are JPEG bytes under a .webp name; they must still restore. Only images qualify: html, svg, pdf and video never pass through here.

Types

type BlobStore

type BlobStore interface {
	// Put streams r into key and returns the bytes written. A failed Put
	// leaves no partial blob behind.
	Put(ctx context.Context, key string, r io.Reader) (int64, error)
	// Get opens key for streaming; close the returned reader.
	Get(ctx context.Context, key string) (io.ReadCloser, error)
	// Delete removes key. A missing key returns an error satisfying
	// errors.Is(err, fs.ErrNotExist).
	Delete(ctx context.Context, key string) error
	// URL is the public URL of key.
	URL(key string) string
}

BlobStore holds the bytes of stored media. Keys are the persisted StoragePath strings, relative to the store and never absolute.

func NewLocalStore

func NewLocalStore(root, baseURL string) (BlobStore, error)

NewLocalStore returns the local-disk store rooted at root (created if missing, symlinks resolved once) whose URLs start with baseURL.

type Config

type Config struct {
	UploadDir string // Directory for storing uploaded files
	BaseURL   string // Base URL for serving files (e.g., "/media")
	MaxSizeMB int    // Maximum file size in MB
	MaxPixels int    // Maximum decoded pixel count (width*height); 0 = default
	// MaxTotalBytes caps everything under UploadDir (originals and variants);
	// 0 = no cap. Set by the public demo so visitors cannot fill the disk.
	MaxTotalBytes int64
}

Config holds media service configuration.

func DefaultConfig

func DefaultConfig() Config

type CreateMediaInput

type CreateMediaInput struct {
	Filename         string
	OriginalFilename string
	MimeType         string
	FileSize         int64
	StoragePath      string
	Width            *int
	Height           *int
	Folder           string
}

CreateMediaInput contains the input for creating media.

type ImageVariant

type ImageVariant struct {
	Size   string `json:"size"`
	Path   string `json:"path"`
	URL    string `json:"url"`
	Width  int    `json:"width"`
	Height int    `json:"height"`
}

ImageVariant represents a resized version of an image.

type ListMediaFilter

type ListMediaFilter struct {
	Folder   string
	MimeType string
	Search   string
}

ListMediaFilter contains filter options for listing media.

type Media

type Media struct {
	ID               uuid.UUID      `json:"id"`
	Filename         string         `json:"filename"`
	OriginalFilename string         `json:"original_filename"`
	MimeType         string         `json:"mime_type"`
	FileSize         int64          `json:"file_size"`
	StorageProvider  string         `json:"storage_provider"`
	StoragePath      string         `json:"storage_path"`
	PublicURL        *string        `json:"public_url,omitempty"`
	Width            *int           `json:"width,omitempty"`
	Height           *int           `json:"height,omitempty"`
	Variants         []ImageVariant `json:"variants,omitempty"`
	AltText          *string        `json:"alt_text,omitempty"`
	Caption          *string        `json:"caption,omitempty"`
	Folder           string         `json:"folder"`
	UploadedBy       *uuid.UUID     `json:"uploaded_by,omitempty"`
	CreatedAt        time.Time      `json:"created_at"`
	UpdatedAt        time.Time      `json:"updated_at"`
}

Media represents a media file stored in the system.

func (*Media) IsImage

func (m *Media) IsImage() bool

IsImage returns true if the media is an image based on mime type.

func (*Media) MarshalVariants

func (m *Media) MarshalVariants() ([]byte, error)

MarshalVariants converts variants slice to JSON for database storage.

func (*Media) SupportsVariants

func (m *Media) SupportsVariants() bool

SupportsVariants returns true if the image format supports creating variants.

func (*Media) UnmarshalVariants

func (m *Media) UnmarshalVariants(data []byte) error

UnmarshalVariants converts JSON from database to variants slice.

type PagedResult

type PagedResult struct {
	Items []*Media `json:"items"`
	Total int      `json:"total"`
}

PagedResult represents a paginated result set.

type PostgresRepository

type PostgresRepository struct {
	// contains filtered or unexported fields
}

PostgresRepository implements Repository using PostgreSQL.

func NewPostgresRepository

func NewPostgresRepository(db *database.DB) *PostgresRepository

NewPostgresRepository creates a new PostgreSQL media repository.

func (*PostgresRepository) Create

func (r *PostgresRepository) Create(ctx context.Context, m *Media) error

Create inserts a new media record.

func (*PostgresRepository) Delete

func (r *PostgresRepository) Delete(ctx context.Context, id uuid.UUID) error

Delete removes a media record.

func (*PostgresRepository) GetByID

func (r *PostgresRepository) GetByID(ctx context.Context, id uuid.UUID) (*Media, error)

GetByID retrieves a media record by ID.

func (*PostgresRepository) List

func (r *PostgresRepository) List(ctx context.Context, filter *ListMediaFilter, limit, offset int) (*PagedResult, error)

List retrieves media records with filtering and pagination.

func (*PostgresRepository) Update

func (r *PostgresRepository) Update(ctx context.Context, m *Media) error

Update modifies a media record.

func (*PostgresRepository) Usage

func (r *PostgresRepository) Usage(ctx context.Context, stem string) ([]Usage, error)

Usage is the Postgres implementation behind Service.Usage.

type Repository

type Repository interface {
	Create(ctx context.Context, m *Media) error
	GetByID(ctx context.Context, id uuid.UUID) (*Media, error)
	List(ctx context.Context, filter *ListMediaFilter, limit, offset int) (*PagedResult, error)
	Update(ctx context.Context, m *Media) error
	Delete(ctx context.Context, id uuid.UUID) error
}

Repository defines the interface for media data operations.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service handles media operations.

func NewService

func NewService(repo Repository, config Config, logger *slog.Logger) *Service

NewService creates a new media service.

func (*Service) Config

func (s *Service) Config() Config

Config returns the media service configuration.

func (*Service) Delete

func (s *Service) Delete(ctx context.Context, id uuid.UUID) error

Delete removes a media file and its database record.

func (*Service) Get

func (s *Service) Get(ctx context.Context, id uuid.UUID) (*Media, error)

Get retrieves a media record by ID.

func (*Service) List

func (s *Service) List(ctx context.Context, filter *ListMediaFilter, limit, offset int) (*PagedResult, error)

List retrieves media records with filtering and pagination.

func (*Service) OpenFile

func (s *Service) OpenFile(rel string) (*os.File, error)

OpenFile opens a stored file by its path relative to the upload directory. The path is resolved inside an os.Root: "..", absolute paths and symlinks that lead outside the directory are refused. Close the returned file.

func (*Service) SetChangeObserver

func (s *Service) SetChangeObserver(f func(ctx context.Context))

SetChangeObserver installs the callback run after Update or Delete; nil disables it.

func (*Service) Update

func (s *Service) Update(ctx context.Context, id uuid.UUID, input *UpdateMediaInput) (*Media, error)

Update modifies media metadata.

func (*Service) Upload

func (s *Service) Upload(ctx context.Context, userID *uuid.UUID, file io.Reader, filename, _ string, fileSize int64) (*Media, error)

Upload stores a new media file.

func (*Service) Usage

func (s *Service) Usage(ctx context.Context, m *Media) ([]Usage, error)

Usage lists what references m. Entities hold media as URL strings inside their JSON attributes, so a reference is the generated file name (its stem also matches the resized variants).

type UpdateMediaInput

type UpdateMediaInput struct {
	AltText *string `json:"alt_text,omitempty"`
	Caption *string `json:"caption,omitempty"`
	Folder  *string `json:"folder,omitempty"`
}

UpdateMediaInput contains the input for updating media metadata.

type Usage

type Usage struct {
	Kind       string // entity | site | menu | plugin
	ID         uuid.UUID
	Name       string
	SchemaSlug string // entities only
}

Usage is one place a media file is referenced from: an entity (its attributes mention the file's URL, which covers a person's photo), the site settings (logo, theme), a menu or a plugin's settings. The legacy authors table is a rollback mirror of the people and is not a usage of its own.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL