README

Media Library

Media is a Golang library that supports the upload of files/images/videos to a filesystem or cloud storage as well as linked videos (i.e. YouTube, Vimeo, etc.). The plugin includes:

  • cropping and resizing features for images.
  • optional multiple sizes for each media resource.
  • Accessibility helpers.

GoDoc

File Types

Media accepts any and every file type, yet it associates certain file types as images or videos so as to provide helpers supporting those media's specific needs.

Images: .jpg, .jpeg, .png, .tif, .tiff, .bmp, .gif

Videos: .mp4, .m4p, .m4v, .m4v, .mov, .mpeg, .webm, .avi, .ogg, .ogv

Usage

Media depends on GORM models as it is using GORM's callbacks to handle file processing, so you will need to register callbacks first:

import (
  "github.com/jinzhu/gorm"
  "github.com/qor/media"
)

DB, err = gorm.Open("sqlite3", "demo_db") // [gorm](https://github.com/jinzhu/gorm)

media.RegisterCallbacks(DB)

Then add OSS(Object Storage Service) to your model:

import (
  "github.com/jinzhu/gorm"
  "github.com/qor/media/oss"
)

type Product struct {
  gorm.Model
  Image oss.OSS
}

Last, configure the storage. The default value is oss.Storage := filesystem.New("public"). Here we configure S3 as storage.

import (
  // "github.com/oss/filesystem"
  "github.com/oss/s3"
)

oss.Storage := s3.New(s3.Config{AccessID: "access_id", AccessKey: "access_key", Region: "region", Bucket: "bucket", Endpoint: "cdn.getqor.com", ACL: aws.BucketCannedACLPublicRead})
// Default configuration `oss.Storage := filesystem.New("public")`

Operate stored files

The OSS(Object Storage Service) provides a pretty simple API to operate files on filesytem or cloud storage

type StorageInterface interface {
  Get(path string) (*os.File, error)
  GetStream(path string) (io.ReadCloser, error)
  Put(path string, reader io.Reader) (*Object, error)
  Delete(path string) error
  List(path string) ([]*Object, error)
  GetEndpoint() string
  GetURL(path string) (string, error)
}

So once you finished the setting, you could operate saved files like this:

storage := s3.New(s3.Config{AccessID: "access_id", AccessKey: "access_key", Region: "region", Bucket: "bucket", Endpoint: "cdn.getqor.com", ACL: aws.BucketCannedACLPublicRead})
// storage := filesystem.New("public")

// Save a reader interface into storage
storage.Put("/sample.txt", reader)

// Get file with path
storage.Get("/sample.txt")

// Delete file with path
storage.Delete("/sample.txt")

// List all objects under path
storage.List("/")

Predefine common image size

You can implement the GetSizes function to predefine image sizes. The size name can be used to fetch image of corresponding size.

import (
  "github.com/qor/media/oss"
  "github.com/jinzhu/gorm"
)

type Product struct {
  gorm.Model
  Image ProductIconImageStorage
}

type ProductIconImageStorage struct{
  oss.OSS
}

func (ProductIconImageStorage) GetSizes() map[string]*media.Size {
  return map[string]*media.Size{
    // Add padding to thumbnail if ratio doesn't match, by default, crop center
    "small":    {Width: 60 * 2, Height: 60 * 2, Padding: true},
    "small@ld": {Width: 60, Height: 60},

    "middle":    {Width: 108 * 2, Height: 108 * 2},
    "middle@ld": {Width: 108, Height: 108},

    "big":    {Width: 144 * 2, Height: 144 * 2},
    "big@ld": {Width: 144, Height: 144},
  }
}

// Get image's url with style
product.Image.URL("small")
product.Image.URL("big@ld")

How to setup a Media Library and use media box

You can also setup a media library, not use oss.OSS in model directly, then you can choose file from media library.

setup a media library

import(
"github.com/qor/admin"
"github.com/qor/media/oss"
"github.com/oss/s3"
"github.com/qor/media/media_library"
)

db.AutoMigrate(&media_library.MediaLibrary{})
adm = admin.New(&admin.AdminConfig{SiteName: "XXX", DB: db})
oss.Storage = s3.New(s3.Config{AccessID: "access_id", AccessKey: "access_key", Region: "region", Bucket: "bucket", Endpoint: "cdn.getqor.com", ACL: aws.BucketCannedACLPublicRead})
adm.AddResource(&media_library.MediaLibrary{}, &admin.Config{Name: "Media Library")
media.RegisterCallbacks(db)

use media box in model

import(
"github.com/qor/media/media_library"
"github.com/qor/media
}

type Product struct {
	gorm.Model

	Image          media_library.MediaBox
}

   res :=adm.AddResource(&Product{}, &admin.Config{Name: "Product")
   res.Meta(&admin.Meta{Name: "Image", Config: &media_library.MediaBoxConfig{
		Max:                1,
		Sizes:              map[string]*media.Size{
	        "m": {Width: 500,Height:500},
        },
		AllowType:          media_library.ALLOW_TYPE_IMAGE,
	}})

Set file storage path in the file system

The default size and path for Image. The default size is 4294967295 and default path is {repo_path}/public/system/{{class}}/{{primary_key}}/{{column}}.{{extension}}.

You can set the path and size manually by adding tag to the field like this:

type Product struct {
  gorm.Model
  Image oss.OSS `sql:"size:4294967295;" media_library:"url:/backend/{{class}}/{{primary_key}}/{{column}}.{{extension}};path:./private"`
}

The media takes two parameters, url and path. the url set the relative file path and the path set the prefix path. So suppose we uploaded a image called demo.png. The file will be stored at {repo_path}/private/backend/products/1/demo.png.

Be careful when using http.FileServer

The http.FileServer not only serves the files, but also shows the directory contents. This is very dangerous when you do things like

for _, path := range []string{"system", "javascripts", "stylesheets", "images"} {
  mux.Handle(fmt.Sprintf("/%s/", path), http.FileServer(http.Dir("public")))
}

The files under public will be exposed to public(especially the search engine!), Imagine someone upload a illegal or sensitive file to your server. The directory is fully visible to everyone and its indexable by search engines and boom!

To avoid this problem, we made a safer FileServer function here. This function serves file only. So the previous code now turned into:

for _, path := range []string{"system", "javascripts", "stylesheets", "images"} {
  mux.Handle(fmt.Sprintf("/%s/", path), utils.FileServer(http.Dir("public")))
}

Accessibility helpers

Media Library has some features aimed at helping achieve Accessibile frontends:

  • capture of a textual description for images, videos, and linked videos to aid with Accessibility.
  • capture of textual transcript for videos and linked videos to aid with Accessibility.

The values captured are fed into the sub-templates for each media type to be used if/where necessary. For example, an image's HTML output (an img tag) manifests the textual description within an alt attribute while a video's HTML (an iframe tag) manifests the textual description within a title attribute.

License

Released under the MIT License.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// set MediaLibraryURL to change the default url /system/{{class}}/{{primary_key}}/{{column}}.{{extension}}
	MediaLibraryURL = ""
)

Functions

func GetImageFormat

func GetImageFormat(url string) (*imaging.Format, error)

func IsImageFormat

func IsImageFormat(name string) bool

    IsImageFormat check filename is image or not

    func IsSVGFormat

    func IsSVGFormat(name string) bool

    func IsVideoFormat

    func IsVideoFormat(name string) bool

      IsVideoFormat check filename is video or not

      func RegisterCallbacks

      func RegisterCallbacks(db *gorm.DB)

        RegisterCallbacks register callback into GORM DB

        func RegisterMediaHandler

        func RegisterMediaHandler(name string, handler MediaHandler)

          RegisterMediaHandler register Media library handler

          Types

          type Base

          type Base struct {
          	FileName    string
          	Url         string
          	CropOptions map[string]*CropOption `json:",omitempty"`
          	Delete      bool                   `json:"-"`
          	Crop        bool                   `json:"-"`
          	FileHeader  FileHeader             `json:"-"`
          	Reader      io.Reader              `json:"-"`
          	Options     map[string]string      `json:",omitempty"`
          	// contains filtered or unexported fields
          }

            Base defined a base struct for storages

            func (Base) ConfigureQorMetaBeforeInitialize

            func (Base) ConfigureQorMetaBeforeInitialize(meta resource.Metaor)

              ConfigureQorMetaBeforeInitialize configure this field for Qor Admin

              func (*Base) Cropped

              func (b *Base) Cropped(values ...bool) (result bool)

                Cropped mark the image to be cropped

                func (Base) Ext

                func (b Base) Ext() string

                func (*Base) GetCropOption

                func (b *Base) GetCropOption(name string) *image.Rectangle

                  GetCropOption get crop options

                  func (Base) GetFileHeader

                  func (b Base) GetFileHeader() FileHeader

                    GetFileHeader get file's header, this value only exists when saving files

                    func (Base) GetFileName

                    func (b Base) GetFileName() string

                      GetFileName get file's name

                      func (Base) GetSizes

                      func (b Base) GetSizes() map[string]*Size

                        GetSizes get configured sizes, it will be used to crop images accordingly

                        func (Base) GetURL

                        func (b Base) GetURL(option *Option, scope *gorm.Scope, field *gorm.Field, templater URLTemplater) string

                          GetURL get default URL for a model based on its options

                          func (Base) GetURLTemplate

                          func (b Base) GetURLTemplate(option *Option) (path string)

                            GetURLTemplate get url template

                            func (Base) IsImage

                            func (b Base) IsImage() bool

                              IsImage return if it is an image

                              func (Base) IsSVG

                              func (b Base) IsSVG() bool

                              func (Base) IsVideo

                              func (b Base) IsVideo() bool

                              func (*Base) NeedCrop

                              func (b *Base) NeedCrop() bool

                                NeedCrop return the file needs to be cropped or not

                                func (Base) Retrieve

                                func (b Base) Retrieve(url string) (*os.File, error)

                                  Retrieve retrieve file content with url

                                  func (*Base) Scan

                                  func (b *Base) Scan(data interface{}) (err error)

                                    Scan scan files, crop options, db values into struct

                                    func (Base) String

                                    func (b Base) String() string

                                      String return file's url

                                      func (Base) URL

                                      func (b Base) URL(styles ...string) string

                                        URL return file's url with given style

                                        func (Base) Value

                                        func (b Base) Value() (driver.Value, error)

                                          Value return struct's Value

                                          type CropOption

                                          type CropOption struct {
                                          	X, Y, Width, Height int
                                          }

                                            CropOption includes crop options

                                            type FileHeader

                                            type FileHeader interface {
                                            	Open() (multipart.File, error)
                                            }

                                              FileHeader is an interface, for matched values, when call its `Open` method will return `multipart.File`

                                              type FileInterface

                                              type FileInterface interface {
                                              	io.ReadSeeker
                                              	io.Closer
                                              }

                                                FileInterface media file interface

                                                type Media

                                                type Media interface {
                                                	Scan(value interface{}) error
                                                	Value() (driver.Value, error)
                                                
                                                	GetURLTemplate(*Option) string
                                                	GetURL(option *Option, scope *gorm.Scope, field *gorm.Field, templater URLTemplater) string
                                                
                                                	GetFileHeader() FileHeader
                                                	GetFileName() string
                                                
                                                	GetSizes() map[string]*Size
                                                	NeedCrop() bool
                                                	Cropped(values ...bool) bool
                                                	GetCropOption(name string) *image.Rectangle
                                                
                                                	Store(url string, option *Option, reader io.Reader) error
                                                	Retrieve(url string) (FileInterface, error)
                                                
                                                	IsImage() bool
                                                
                                                	URL(style ...string) string
                                                	Ext() string
                                                	String() string
                                                }

                                                  Media is an interface including methods that needs for a media library storage

                                                  type MediaHandler

                                                  type MediaHandler interface {
                                                  	CouldHandle(media Media) bool
                                                  	Handle(media Media, file FileInterface, option *Option) error
                                                  }

                                                    MediaHandler media library handler interface, defined which files could be handled, and the handler

                                                    type Option

                                                    type Option map[string]string

                                                      Option media library option

                                                      func (Option) Get

                                                      func (option Option) Get(key string) string

                                                        get option with name

                                                        func (Option) Set

                                                        func (option Option) Set(key string, val string)

                                                          set option

                                                          type Size

                                                          type Size struct {
                                                          	Width   int
                                                          	Height  int
                                                          	Padding bool
                                                          }

                                                            Size is a struct, used for `GetSizes` method, it will return a slice of Size, media library will crop images automatically based on it

                                                            type URLTemplater

                                                            type URLTemplater interface {
                                                            	GetURLTemplate(*Option) string
                                                            }

                                                              URLTemplater is a interface to return url template

                                                              Directories

                                                              Path Synopsis
                                                              handlers